开始逐渐领略到ItemDecoration的美~
今天让我 使用 ItemDecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图:
具体实现步骤如下:
根据我前面的文章所讲的RecyclerView的基本使用,我们先来完成基本的recyclerView:
第一步:布局里写一个RecyclerView
第二步:实例化
Java
1 | recyclerView = (RecyclerView) findViewById(R.id.recyclerView); |
第三步:获取所需的数据 (这里我们来个真实点的情景,去联网请求数据)
Java
1 2 3 4 | /** * 联网请求所需的url */ public String url="http://api.meituan.com/mmdb/movie/v2/list/rt/order/coming.json?ci=1&limit=12&token=&__vhost=api.maoyan.com&utm_campaign=AmovieBmovieCD-1&movieBundleVersion=6801&utm_source=xiaomi&utm_medium=android&utm_term=6.8.0&utm_content=868030022327462&net=255&dModel=MI%205&uuid=0894DE03C76F6045D55977B6D4E32B7F3C6AAB02F9CEA042987B380EC5687C43&lat=40.100673&lng=116.378619&__skck=6a375bce8c66a0dc293860dfa83833ef&__skts=1463704714271&__skua=7e01cf8dd30a179800a7a93979b430b2&__skno=1a0b4a9b-44ec-42fc-b110-ead68bcc2824&__skcy=sXcDKbGi20CGXQPPZvhCU3%2FkzdE%3D"; |
Java
想要更多 加qq群私聊群主:584508688
1 2 | //联网获取数据 getDataFromNet(); |
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | /** * 使用okhttpUtils进行联网请求数据 */ private void getDataFromNet() { OkHttpUtils. get() .url(url) .build() .execute(new StringCallback() { public void onError(okhttp3.Call call, Exception e, int id) { Log.e("TAG", "联网失败" + e.getMessage()); }
public void onResponse(String response, int id) { Log.e("TAG", "联网成功==" + response);
//联网成功后使用fastjson解析 processData(response); } }); } |
Java
想要更多 加qq群私聊群主:584508688
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 | /** * 使用fastjson进行解析 * * @param json */ private void processData(String json) { //这里使用GsonFormat生成对应的bean类 JSONObject jsonObject = parseObject(json);
String data = jsonObject.getString("data"); JSONObject dataObj = JSON.parseObject(data);
String coming = dataObj.getString("coming"); List<WaitMVBean.DataBean.ComingBean> comingslist = parseArray(coming, WaitMVBean.DataBean.ComingBean.class);
//测试是否解析数据成功 // String strTest = comingslist.get(0).getCat(); // Log.e("TAG", strTest + "222");
//解析数据成功,设置适配器-->
}
} |
第四步:解析数据成功后,创建并设置适配器,并传递相关数据
Java
1 2 3 | //解析数据成功,设置适配器 MyRecyclerAdapter adapter = new MyRecyclerAdapter( mContext,comingslist); recyclerView.setAdapter(adapter); |
适配器:
Java
想要更多 加qq群私聊群主:584508688
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 | public class MyRecyclerAdapter extends RecyclerView.Adapter {
private final List<WaitMVBean.DataBean.ComingBean> comingslist; private final Context mContext; private final LayoutInflater mLayoutInflater;
public MyRecyclerAdapter(Context mContext, List<WaitMVBean.DataBean.ComingBean> comingslist) { this.mContext = mContext; this.comingslist = comingslist; mLayoutInflater = LayoutInflater.from(mContext); }
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new MyViewHolder(mLayoutInflater.inflate(R.layout.date_item, null)); }
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { MyViewHolder myholder = (MyViewHolder) holder; myholder.setData(position); }
@Override public int getItemCount() { return comingslist.size(); }
class MyViewHolder extends RecyclerView.ViewHolder { private TextView mv_name; private TextView mv_dec; private TextView mv_date; private ImageView imageView;
public MyViewHolder(View itemView) { super(itemView); mv_name = (TextView) itemView.findViewById(R.id.mv_name); mv_dec = (TextView) itemView.findViewById(R.id.mv_dec); mv_date = (TextView) itemView.findViewById(R.id.mv_date); imageView = (ImageView) itemView.findViewById(R.id.image); }
public void setData(int position) { WaitMVBean.DataBean.ComingBean coming = comingslist.get(position);
String name = coming.getNm(); mv_name.setText(name);
String date = coming.getShowInfo(); mv_date.setText(date);
String dec = coming.getScm(); mv_dec.setText(dec);
//注:当你发下图片无法打开是,做个字符串替换即可 String imagUrl = coming.getImg(); String newImagUrl = imagUrl.replaceAll("w.h", "50.80");
//使用Glide加载图片 Glide.with(mContext) .load(newImagUrl) .into(imageView); } } } |
item的布局:
Java
想要更多 加qq群私聊群主:584508688
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 | <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="wrap_content" android:layout_height="wrap_content" android:background="#ffffff" android:gravity="center_vertical" android:orientation="horizontal">
<ImageView android:id="@+id/image" android:layout_width="70dp" android:layout_height="110dp" android:layout_marginBottom="5dp" android:layout_marginLeft="10dp" android:layout_marginRight="8dp" android:layout_marginTop="5dp" />
<LinearLayout android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginLeft="6dp" android:layout_weight="1" android:orientation="vertical">
<TextView android:id="@+id/mv_name" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="神奇動物在哪裏" android:textColor="#000000" android:textSize="15sp" />
<LinearLayout android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="horizontal">
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="观众" android:textColor="#55000000" android:textSize="14sp" />
<TextView android:id="@+id/tv_people" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="9.0 " android:textColor="#FFCE42" android:textSize="18sp" />
<TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text=" | 专业" android:textColor="#55000000" android:textSize="14sp" />
<TextView android:id="@+id/tv_professional" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="6.7" android:textColor="#FFCE42" android:textSize="18sp" /> </LinearLayout>
<TextView android:id="@+id/mv_dec" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="8dp" android:text="神奇動物城,法師顯超能" android:textColor="#99000000" android:textSize="11sp" />
<TextView android:id="@+id/mv_date" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginTop="10dp" android:text="今天165家影院放映2088场" android:textColor="#99000000" android:textSize="11sp" /> </LinearLayout>
</LinearLayout> |
第五步:一定不能忘!!!
recycleView不仅要设置适配器还要设置布局管理者,否则图片不显示
Java
想要更多 加qq群私聊群主:584508688
1 2 | GridLayoutManager manager = new GridLayoutManager(this, 1); recyclerView.setLayoutManager(manager); |
此时RecyclerView简单的完成效果如下:
下面开始做 可推动的 悬浮导航栏:
第一步:首先我们来写一个类,它起标记的作用,来放每一个item的对应的悬浮栏的字符串
Java
想要更多 加qq群私聊群主:584508688
1 2 3 4 5 6 7 8 9 10 11 | public class NameBean { String name;
public String getName() { return name; }
public void setName(String name) { this.name = name; } } |
第二步:自定义一个SectionDecoration 类 继承 RecyclerView的ItemDecoration
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 | public class SectionDecoration extends RecyclerView.ItemDecoration { private static final String TAG = "SectionDecoration";
private List<NameBean> dataList;
private DecorationCallback callback; private TextPaint textPaint; private Paint paint; private int topGap; private int alignBottom; private Paint.FontMetrics fontMetrics;
public SectionDecoration(List<NameBean> dataList, Context context, DecorationCallback decorationCallback) { Resources res = context.getResources(); this.dataList = dataList; this.callback = decorationCallback; //设置悬浮栏的画笔---paint paint = new Paint(); paint.setColor(res.getColor(R.color.colorGray));
//设置悬浮栏中文本的画笔 textPaint = new TextPaint(); textPaint.setAntiAlias(true); textPaint.setTextSize(DensityUtil.dip2px(context, 14)); textPaint.setColor(Color.DKGRAY); textPaint.setTextAlign(Paint.Align.LEFT); fontMetrics = new Paint.FontMetrics(); //决定悬浮栏的高度等 topGap = res.getDimensionPixelSize(R.dimen.sectioned_top); //决定文本的显示位置等 alignBottom = res.getDimensionPixelSize(R.dimen.sectioned_alignBottom); }
@Override public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) { super.getItemOffsets(outRect, view, parent, state); int pos = parent.getChildAdapterPosition(view); Log.i(TAG, "getItemOffsets:" + pos); String groupId = callback.getGroupId(pos); if (groupId.equals("-1")) return; //只有是同一组的第一个才显示悬浮栏 if (pos == 0 || isFirstInGroup(pos)) { outRect.top = topGap; if (dataList.get(pos).getName() == "") { outRect.top = 0; } } else { outRect.top = 0; } }
@Override public void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDraw(c, parent, state); int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); int childCount = parent.getChildCount(); for (int i = 0; i < childCount; i++) { View view = parent.getChildAt(i); int position = parent.getChildAdapterPosition(view); String groupId = callback.getGroupId(position); if (groupId.equals("-1")) return; String textLine = callback.getGroupFirstLine(position).toUpperCase(); if (textLine == "") { float top = view.getTop(); float bottom = view.getTop(); c.drawRect(left, top, right, bottom, paint); return; } else { if (position == 0 || isFirstInGroup(position)) { float top = view.getTop() - topGap; float bottom = view.getTop(); //绘制悬浮栏 c.drawRect(left, top - topGap, right, bottom, paint); //绘制文本 c.drawText(textLine, left, bottom, textPaint); } } } }
@Override public void onDrawOver(Canvas c, RecyclerView parent, RecyclerView.State state) { super.onDrawOver(c, parent, state); int itemCount = state.getItemCount(); int childCount = parent.getChildCount(); int left = parent.getPaddingLeft(); int right = parent.getWidth() - parent.getPaddingRight(); float lineHeight = textPaint.getTextSize() + fontMetrics.descent;
String preGroupId = ""; String groupId = "-1"; for (int i = 0; i < childCount; i++) { View view = parent.getChildAt(i); int position = parent.getChildAdapterPosition(view);
preGroupId = groupId; groupId = callback.getGroupId(position); if (groupId.equals("-1") || groupId.equals(preGroupId)) continue;
String textLine = callback.getGroupFirstLine(position).toUpperCase(); if (TextUtils.isEmpty(textLine)) continue;
int viewBottom = view.getBottom(); float textY = Math.max(topGap, view.getTop()); //下一个和当前不一样移动当前 if (position + 1 < itemCount) { String nextGroupId = callback.getGroupId(position + 1); //组内最后一个view进入了header if (nextGroupId != groupId && viewBottom < textY) { textY = viewBottom; } } //textY - topGap决定了悬浮栏绘制的高度和位置 c.drawRect(left, textY - topGap, right, textY, paint); //left+2*alignBottom 决定了文本往左偏移的多少(加-->向左移) //textY-alignBottom 决定了文本往右偏移的多少 (减-->向上移) c.drawText(textLine, left + 2 * alignBottom, textY - alignBottom, textPaint); } }
/** * 判断是不是组中的第一个位置 * * @param pos * @return */ private boolean isFirstInGroup(int pos) { if (pos == 0) { return true; } else { // 因为是根据 字符串内容的相同与否 来判断是不是同意组的,所以此处的标记id 要是String类型 // 如果你只是做联系人列表,悬浮框里显示的只是一个字母,则标记id直接用 int 类型就行了 String prevGroupId = callback.getGroupId(pos - 1); String groupId = callback.getGroupId(pos); //判断前一个字符串 与 当前字符串 是否相同 if (prevGroupId.equals(groupId)) { return false; } else { return true; } } }
//定义一个借口方便外界的调用 interface DecorationCallback { String getGroupId(int position);
String getGroupFirstLine(int position); } } |
第三步:在向list集合中先把每一个item的 起“标记”作用的字符串都加进去
Java
想要更多 加qq群私聊群主:584508688
1 | setPullAction(comingslist); |
Java
1 2 3 4 5 6 7 8 9 10 | private void setPullAction(List<WaitMVBean.DataBean.ComingBean> comingslist) { dataList = new ArrayList<>();
for (int i = 0; i < comingslist.size(); i++) { NameBean nameBean = new NameBean(); String name0 = comingslist.get(i).getComingTitle(); nameBean.setName(name0); dataList.add(nameBean); } } |
第四步:在setAdapter() 前,为RecyclerView添加ItemDecoration:
Java
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | recyclerView.addItemDecoration(new SectionDecoration(dataList,mContext, new SectionDecoration.DecorationCallback() { //返回标记id (即每一项对应的标志性的字符串) @Override public String getGroupId(int position) { if(dataList.get(position).getName()!=null) { return dataList.get(position).getName(); } return "-1"; }
//获取同组中的第一个内容 @Override public String getGroupFirstLine(int position) { if(dataList.get(position).getName()!=null) { return dataList.get(position).getName(); } return ""; } })); |
这样就完成了~
再看一眼最终效果感受一下: