Android控件RecyclerView实现混排效果仿网易云音乐
前言
最近在使用网易云音乐的时候,看到如下图的排版效果图,自己也想实现一个
这里采用网上用法最多的方式,而且是比较简单的方式实现的,想要做项目的同学也可以快速入手搞定首页界面,可以在最快的时间内模仿出来,且效果达到90%以上的相似
效果演示
至于图片的加载你们可以根据网上的api获取相应的图片加载到对应的位置,这里只是采用本地图片来演示
实现分析
这里是采用recyclerview的gridlayoutmanager的一个spansize这么一个东西,从下图很容易知道其意思
项目结构
项目结构可能对初学者感觉很庞大,不用担心,这里我会按照下面的包名划分,从最简单的开始分析
引入依赖
首先是在gradle中引入对recyclerview的依赖
compile 'com.android.support:recyclerview-v7:25.3.1'
view包
由于项目用到的图片是有规格限定的,所以需要对imageview覆写,得到我们想要尺寸的图片
squareimageview:正方形图片
rectimageview:长方形图片
public class squareimageview extends android.support.v7.widget.appcompatimageview { public squareimageview(context context) { this(context,null); } public squareimageview(context context, @nullable attributeset attrs) { this(context, attrs,0); } public squareimageview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); setscaletype(scaletype.fit_xy); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { super.onmeasure(widthmeasurespec, widthmeasurespec); } }
public class rectimageview extends android.support.v7.widget.appcompatimageview { public rectimageview(context context) { this(context, null); } public rectimageview(context context, @nullable attributeset attrs) { this(context, attrs, 0); } public rectimageview(context context, @nullable attributeset attrs, int defstyleattr) { super(context, attrs, defstyleattr); setscaletype(scaletype.fit_xy); } @override protected void onmeasure(int widthmeasurespec, int heightmeasurespec) { int widthmode = measurespec.getmode(widthmeasurespec); int width = measurespec.getsize(widthmeasurespec); // 设置大小为宽度的三分之二 int halfwidthmeasurespec = measurespec.makemeasurespec(width / 3 * 2, widthmode); super.onmeasure(widthmeasurespec, halfwidthmeasurespec); } }
music包
这里是我们存储实体的地方,其中四种类型的划分,分别对应项目展示中的前三个模块的划分,其中还有一个标题也算是一种类型,所以共四种
public class music { public int type; public string title; // 后期可加入glide加载网络图片url public int imageid; public interface type { int type_grid_three = 0x01; int type_grid_two = 0x02; int type_list = 0x03; int type_title = 0x04; } }
listener包
由于recyclerview自身是没有点击事件的,所以这个包是recyclerview的点击事件接口
public interface onitemclicklistener { void onitemclick(int position); }
decoration包
由于recyclerview是不提供分割线的,所以这个包是自定义的分割线
public class spacesitemdecoration extends recyclerview.itemdecoration { private int space; public spacesitemdecoration(int space) { this.space = space; } @override public void getitemoffsets(rect outrect, view view, recyclerview parent, recyclerview.state state) { outrect.left = space; outrect.right = space; outrect.bottom = space; outrect.top = space; } }
viewholder
这里存储的是我们混排效果的控件,标题可能会有点区别,其他是一样的效果,为了后期方便拓展,我们就把他们分开,不代码复用
public class gridthreeviewholder extends recyclerview.viewholder { public squareimageview iv_icon; public textview tv_content; public gridthreeviewholder(view itemview) { super(itemview); iv_icon = (squareimageview) itemview.findviewbyid(r.id.iv_icon); tv_content = (textview) itemview.findviewbyid(r.id.tv_content); } }
public class gridtwoviewholder extends recyclerview.viewholder { public rectimageview iv_icon; public textview tv_content; public gridtwoviewholder(view itemview) { super(itemview); iv_icon = (rectimageview) itemview.findviewbyid(r.id.iv_icon); tv_content = (textview) itemview.findviewbyid(r.id.tv_content); } }
public class listviewholder extends recyclerview.viewholder { public rectimageview iv_icon; public textview tv_content; public listviewholder(view itemview) { super(itemview); iv_icon = (rectimageview) itemview.findviewbyid(r.id.iv_icon); tv_content = (textview) itemview.findviewbyid(r.id.tv_content); } }
public class titleviewholder extends recyclerview.viewholder { public textview tv_content; public titleviewholder(view itemview) { super(itemview); tv_content = (textview) itemview.findviewbyid(r.id.tv_content); } }
adapter包
这里就是对所有viewholder的控制器,然而这里并不是混排效果实现的最终地方,只不过是填充数据的地方
public class recycleradapter extends recyclerview.adapter<recyclerview.viewholder> implements view.onclicklistener { private list<music> mlist; private context mcontext; private layoutinflater minflater; /** * 点击事件 */ private onitemclicklistener monitemclicklistener; public void setonitemclicklistener(onitemclicklistener onitemclicklistener) { this.monitemclicklistener = onitemclicklistener; } public recycleradapter(context context, list<music> list) { this.mlist = list; this.mcontext = context; this.minflater = layoutinflater.from(context); } @override public recyclerview.viewholder oncreateviewholder(viewgroup parent, int viewtype) { view view; recyclerview.viewholder mviewholder = null; if (viewtype == music.type.type_grid_three) { view = minflater.inflate(r.layout.item_grid_three, parent, false); mviewholder = new gridthreeviewholder(view); } else if (viewtype == music.type.type_grid_two) { view = minflater.inflate(r.layout.item_grid_two, parent, false); mviewholder = new gridtwoviewholder(view); } else if (viewtype == music.type.type_list) { view = minflater.inflate(r.layout.item_list, parent, false); mviewholder = new listviewholder(view); } else if (viewtype == music.type.type_title) { view = minflater.inflate(r.layout.item_title, parent, false); mviewholder = new titleviewholder(view); } return mviewholder; } @override public void onbindviewholder(recyclerview.viewholder holder, int position) { switch (getitemviewtype(position)) { case music.type.type_grid_three: gridthreeviewholder gholder_three = (gridthreeviewholder) holder; gholder_three.tv_content.settext(mlist.get(position).title); gholder_three.iv_icon.setimageresource(mlist.get(position).imageid); //点击事件 gholder_three.itemview.setonclicklistener(this); gholder_three.itemview.settag(position); break; case music.type.type_grid_two: gridtwoviewholder gholder_two = (gridtwoviewholder) holder; gholder_two.tv_content.settext(mlist.get(position).title); gholder_two.iv_icon.setimageresource(mlist.get(position).imageid); //点击事件 gholder_two.itemview.setonclicklistener(this); gholder_two.itemview.settag(position); break; case music.type.type_list: listviewholder lholder = (listviewholder) holder; lholder.tv_content.settext(mlist.get(position).title); lholder.iv_icon.setimageresource(mlist.get(position).imageid); //点击事件 lholder.itemview.setonclicklistener(this); lholder.itemview.settag(position); break; case music.type.type_title: titleviewholder tholder = (titleviewholder) holder; tholder.tv_content.settext(mlist.get(position).title); //点击事件 tholder.itemview.setonclicklistener(this); tholder.itemview.settag(position); break; } } @override public int getitemviewtype(int position) { return mlist.get(position).type; } @override public int getitemcount() { return mlist.size(); } @override public void onclick(view v) { if (monitemclicklistener != null) { int position = (int) v.gettag(); monitemclicklistener.onitemclick(position); } } }
activity
这里就是我们实现混排效果的关键,我们会根据不同类型的数据,对recyclerview的spansize的进行设置
public class mainactivity extends appcompatactivity implements onitemclicklistener { private recyclerview ry; private gridlayoutmanager layoutmanager; private recycleradapter madapter; private static list<music> mlist; /** * 模拟本地数据 */ static { mlist = new arraylist<>(); for (int i = 0; i < 1; i++) { music music = new music(); music.type = music.type.type_title; music.imageid = r.drawable.ic_cover; music.title = "推荐歌单"; mlist.add(music); } for (int i = 0; i < 6; i++) { music music = new music(); music.type = music.type.type_grid_three; music.imageid = r.drawable.ic_cover; music.title = "先不要降温!我没钱买衣服"; mlist.add(music); } for (int i = 0; i < 1; i++) { music music = new music(); music.type = music.type.type_title; music.imageid = r.drawable.ic_cover; music.title = "推荐mv"; mlist.add(music); } for (int i = 0; i < 4; i++) { music music = new music(); music.type = music.type.type_grid_two; music.imageid = r.drawable.ic_cover; music.title = "perfect day"; mlist.add(music); } for (int i = 0; i < 1; i++) { music music = new music(); music.type = music.type.type_title; music.imageid = r.drawable.ic_cover; music.title = "精选专栏"; mlist.add(music); } for (int i = 0; i < 3; i++) { music music = new music(); music.type = music.type.type_list; music.imageid = r.drawable.ic_cover; music.title = "去看《银翼杀手2049》前,你应该知道的三件事"; mlist.add(music); } for (int i = 0; i < 1; i++) { music music = new music(); music.type = music.type.type_title; music.imageid = r.drawable.ic_cover; music.title = "最新音乐"; mlist.add(music); } for (int i = 0; i < 6; i++) { music music = new music(); music.type = music.type.type_grid_three; music.imageid = r.drawable.ic_cover; music.title = "[bgm]一定听过的神级背景配乐"; mlist.add(music); } } @override protected void oncreate(bundle savedinstancestate) { super.oncreate(savedinstancestate); setcontentview(r.layout.activity_main); ry = (recyclerview) findviewbyid(r.id.ry); layoutmanager = new gridlayoutmanager(this, 6); layoutmanager.setspansizelookup(new gridlayoutmanager.spansizelookup() { @override public int getspansize(int position) { int type = mlist.get(position).type; if (type == music.type.type_grid_three) { return 2; } else if (type == music.type.type_grid_two) { return 3; } else if (type == music.type.type_list) { return 6; } else if (type == music.type.type_title) { return 6; } return 0; } }); ry.setlayoutmanager(layoutmanager); ry.additemdecoration(new spacesitemdecoration(2)); // 填充数据 madapter = new recycleradapter(this, mlist); madapter.setonitemclicklistener(this); ry.setadapter(madapter); } @override public void onitemclick(int position) { string title = mlist.get(position).title; toast.maketext(this, title, toast.length_short).show(); } }
layout布局文件
这里的布局很简单,比如用到我们的正方形图片,长方形图片等,这里就不做代码贴出,详细可以查看源码
源码下载
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。