Android 实现当下最流行的吸顶效果
程序员文章站
2022-06-14 09:33:49
开始逐渐领略到itemdecoration的美~
今天让我 使用 itemdecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图:
具体实现步...
开始逐渐领略到itemdecoration的美~
今天让我 使用 itemdecoration 来完成 可推动的悬浮导航栏的效果,最终实现的效果如下图:
具体实现步骤如下:
根据我前面的文章所讲的recyclerview的基本使用,我们先来完成基本的recyclerview:
第一步:布局里写一个recyclerview
第二步:实例化
recyclerview = (recyclerview) findviewbyid(r.id.recyclerview);
第三步:获取所需的数据 (这里我们来个真实点的情景,去联网请求数据)
/** * 联网请求所需的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;
//联网获取数据 getdatafromnet();
/** * 使用okhttputils进行联网请求数据 */ private void getdatafromnet() { okhttputils. get() .url(url) .build() .execute(new stringcallback() { @override public void onerror(okhttp3.call call, exception e, int id) { log.e("tag", "联网失败" + e.getmessage()); } @override public void onresponse(string response, int id) { log.e("tag", "联网成功==" + response); //联网成功后使用fastjson解析 processdata(response); } }); }
/** * 使用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"); //解析数据成功,设置适配器--> } }
第四步:解析数据成功后,创建并设置适配器,并传递相关数据
//解析数据成功,设置适配器 myrecycleradapter adapter = new myrecycleradapter( mcontext,comingslist); recyclerview.setadapter(adapter);
适配器:
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); } @override public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) { return new myviewholder(mlayoutinflater.inflate(r.layout.date_item, null)); } @override 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的布局:
<?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不仅要设置适配器还要设置布局管理者,否则图片不显示
gridlayoutmanager manager = new gridlayoutmanager(this, 1); recyclerview.setlayoutmanager(manager);
此时recyclerview简单的完成效果如下:
下面开始做 可推动的 悬浮导航栏:
第一步:首先我们来写一个类,它起标记的作用,来放每一个item的对应的悬浮栏的字符串
public class namebean { string name; public string getname() { return name; } public void setname(string name) { this.name = name; } }
第二步:自定义一个sectiondecoration 类 继承 recyclerview的itemdecoration
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的 起“标记”作用的字符串都加进去
setpullaction(comingslist);
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:
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 ""; } }));
这样就完成了~
再看一眼最终效果感受一下:
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!