前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >RecyclerView实现混合布局

RecyclerView实现混合布局

作者头像
cMusketeer
发布2019-08-21 15:24:55
2.2K0
发布2019-08-21 15:24:55
举报
文章被收录于专栏:Android机器圈

PS:好长时间不写博客了,起初是不知道写些什么,后来接触了到了很多东西,原本看似简单的东西,背后都隐藏着巨大的秘密,想handler的使用,一般情况下会引起内存泄漏问题,想着找到方法结局不就得了吗,可是谁想查阅资料发现,这个东西没想到牵扯的这么深, Activity -> handler -> message -> queue -> UI线程作为GC Root引用链,看都看懵逼了,赶紧看一些稍微简单的UI 实现,突发奇想,RecyclerView的混合布局界面的实现。如下图

。。。

像这些布局,可以用listview来实现,也可以RecyclerView来实现,每个布局文件都是不一样的,第一张图:上面是一行三个图,下面是一行四个图。第二张图一行分左右。作为一个新手来说,估计就有点难以招架了,不过用recyclerview就比较好实现了,只要指定Type,来加载不同的布局就可以。下面来简单实现一个简单点的。有一行两个数据,有一行一个数据界面。

我们可以看到,这个RecyclerView中有多种item显示出来,那么具体怎么实现呢,其实在RecyclerView中,我们可以重写方法getItemViewType(),这个方法会传进一个参数position表示当前是第几个Item,然后我们可以通过position拿到当前的Item对象,然后判断这个item对象需要那种视图,返回一个int类型的视图标志,然后在onCreatViewHolder方法中给引入布局,这样就能够实现多种item显示了,我们先来看一下,一共要实现多少方法,他们分别是什么,我都加了注释。

代码语言:javascript
复制
/**
     * 加载视图
     * */
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        return null;
    }
    /**
     * 加载数据
     * */
    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {

    }

    /**
     * 返回数据数量
     * */
    @Override
    public int getItemCount() {
        return 0;
    }

    /**
     * 返回数据类型
     * */
    @Override
    public int getItemViewType(int position) {
        return super.getItemViewType(position);
    }

 我们一般情况下会在上面这些方法中做一些具体操作,所以只要掌握了上面这几个方法,就完全OK了。

步骤:

1:item的布局文件(xml)

2:item的bean类(第二个方法写一个)

3:自定义ViewHolder类继承RecyclerView.ViewHolder

4:自定义adapter继承RecyclerView.Adapter<RecyclerView.ViewHolder>

  a:getItemViewType返回type值

  b:onCreateViewHolder加载不同的视图

  c:onBindViewHolder绑定数据

5:主文件中设置recyclerview的布局样式,赋值调试

 1:Item  xml布局文件和Bean类,ViewHolder创建。

注:bean因demo简洁,并没有用到bean类。一共两个布局,这里只给出一个,类似写出即可。

代码语言:javascript
复制
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
			  android:layout_width="match_parent"
			  android:layout_height="wrap_content">
	<TextView
			android:layout_width="match_parent"
			android:layout_height="50dp"
			android:gravity="center"
			android:background="@color/colorPrimary"
			android:id="@+id/id_one_tv1"/>
</LinearLayout>

public class TypeViewHolderOne extends RecyclerView.ViewHolder {

    public  TextView textView;

    public TypeViewHolderOne(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.id_one_tv1);
    }
}

 2:方法讲解

注意:一般情况下后天会给移动端返回一串JSON字符串,里面有一些数据是需要自己来专门跳出来的,

方法:

  • 你可以写多个list来存放不同的数据,但是如果是多个的话,返回的数据就一串字符串,你不仅要挑出来,还要存放在多个list里面,下次下拉刷新时还要在多个list中累加数据,这样就有点麻烦了
  • 不挑出来直接就只判断type,然后根据type去调用不同的layout,然后在绑定数据的方法中再次判断是不是自己想要的ViewHolder,最后赋值显示。

返回type类型方法

代码语言:javascript
复制
//返回类型,有单列显示还是双列显示
@Override
    public int getItemViewType(int position) {
        return mList.get(position).getType();
}

我们重写了getItemViewType()方法后,就要写不同的item(布局文件),然后在onCreatViewHolder方法引入布局。这里的类型就简单直接写的1和2。

代码语言:javascript
复制
@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    //视图显示
    //创建view视图
    switch (viewType) {
        case 1:
            return new TypeViewHolderOne(layoutInflater.inflate(R.layout.model_view1, parent, false));
        case 2:
            return new TypeViewHolderTwo(layoutInflater.inflate(R.layout.model_view2, parent, false));
    }
    return null;
}

我们看到的TypeViewHolderOne(View view);这个方法是自定义的需要继承RecyclerView.ViewHolder

代码语言:javascript
复制
public class TypeViewHolderOne extends RecyclerView.ViewHolder {
    public  TextView textView;
    public TypeViewHolderOne(View itemView) {
        super(itemView);
        textView = itemView.findViewById(R.id.id_one_tv1);
    }
}

 写到这里,布局有了,viewholder有了,数据的判断类型有了,就差展示了,所以重写onBindViewHolder方法

代码语言:javascript
复制
/**
 * 方法作用:绑定数据,
 * 方法描述:根据holder对控件进行赋值,同时如果有回调接口,在该方法中写。
 */
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    //优化   绑定数据
    if(holder instanceof TypeViewHolderOne){//判断是哪个对象
        TypeViewHolderOne viewHolderOne= (TypeViewHolderOne) holder;
        viewHolderOne.textView.setText(mList.get(position).getName());
    }else if(holder instanceof TypeViewHolderTwo){
        TypeViewHolderTwo viewHolderTwo= (TypeViewHolderTwo) holder;
        viewHolderTwo.textView1.setText(mList.get(position).getName());
        viewHolderTwo.textView2.setText("类型"+mList.get(position).getType());
    }
}

所有预备工作已经做完了,开始赋值。

代码语言:javascript
复制
recyclerViewAdapter = new RecyclerViewAdapter2(this, list);
recyclerView.setAdapter(recyclerViewAdapter);
//本地模拟数据
public void addData() {
    int a=(int)(Math.random()*10);
    TypeBean typeBean;
    for (int i = 0; i < 10; i++) {
        typeBean = new TypeBean();
        typeBean.setName("样式:" + (i + 1));
        typeBean.setType(1);
        if (i == a) {
            typeBean.setType(2);
        }
        list.add(typeBean);
    }
    recyclerViewAdapter.notifyDataSetChanged();
}

现在还不能运行,因为还没有给recyclerview指定一个布局格式,下面是指定了布局格式,一共两列,获取一开始咱们设置的type,如果type=2,则要让他独自占2列,也就是说,他自己一行。

代码语言:javascript
复制
final GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 2);
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
    @Override
    public int getSpanSize(int position) {
        int itemViewType = recyclerView.getAdapter().getItemViewType(position);
        if (itemViewType == 2) {
            return 2;
        }
        return 1;
    }
});

装饰可写可不写

代码语言:javascript
复制
//设置各个item的装饰,如间距,大小等,可写可不写,不写可以在xml文件中设置。
recyclerView.addItemDecoration(new RecyclerView.ItemDecoration() {
    @Override
    public void getItemOffsets(Rect outRect, View view, RecyclerView parent, RecyclerView.State state) {
        //super.getItemOffsets(outRect, view, parent, state);
        //拿到Grid管理器
        GridLayoutManager.LayoutParams layoutParams = (GridLayoutManager.LayoutParams) view.getLayoutParams();
        //拿到grid管理器所设置的总列数
        int spanSize = layoutParams.getSpanSize();
        //拿到当前所在列数
        int spanIndex = layoutParams.getSpanIndex();
        //设置顶部间距
        outRect.top = 20;
        if (spanSize != gridLayoutManager.getSpanCount()) {
            if (spanIndex == 1) {
                outRect.left = 10;
            } else {
                outRect.right = 10;
            }
        }
    }
});
recyclerView.setLayoutManager(gridLayoutManager);

 现在运行试试吧

总结:

1:使用RecyclerView必须要写的就是适配器要继承RecyclerView.Adapter<RecyclerView.ViewHolder>,当然这里面你也可以自定义。

2:加载多个布局文件时(item)需要加入Type字段去判断是哪一个item。在activity中加载recyclerview时,要加入布局样式,比如说,普通的LinearLayoutManager,或者GridLayoutManager,StaggeredGridLayoutManager。不加是不显示的。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2019-08-20 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  •  1:Item  xml布局文件和Bean类,ViewHolder创建。
  •  2:方法讲解
    • 总结:
    领券
    问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档