android_基础_recyclerView实现多种item布局

121 篇文章 1 订阅
6 篇文章 0 订阅

转载自: https://www.jianshu.com/p/66702b7a6881

RecyclerView实现多种item布局

Demo1

在项目中列表是基本都会用到的,然而在显示列表时,我们需要的数据可能需要不止一种item显示,对于复杂的数据就需要多种item,以不同的样式显示出来,这样效果是很棒的,我们先看一下效果

在这里插入图片描述

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

首先我们重写了getItemViewType这个方法,在这个方法中根据position对item对象做了一些判断,如果存储item对象的集合大小为空,返回空view标识(这里为1),如果item对象为null,返回进度条标识,这个主要是用于实现下拉加载更多,如果item对象类型属于图片类型,就返回图片类型对应的Item,这个就是效果图中的第一个Item类型,否则就是其它类型,也就是效果图中的另一种item布局,然后我们在onCreatViewHolder中具体的为每一种类型引入其布局
在这里插入图片描述

上面的代码就是具体为每种viewType引入其对应的布局,这样就基本实现了多种item布局,但是仅仅是这些还不够,因为我们还要对每种item设置数据,所以还要对每种item写一个VIewHolder来为item显示数据

在这里插入图片描述

上面就是item对应的几个ViewHolder,判断viewHolder属于那种对象,然后在onBindViewHolder中根据对应的ViewHolder对其控件设置数据并显示
在这里插入图片描述

整个过程基本就是这样,这种方式在项目中经常会用到,我们就可以这样去处理,下拉加载更多就可以这样实现,在加载完数据后再往对象集合中传入null,然后判断如果出现null就加载progressBar布局,再加上Google官方的SwipeRefreshLayout,下拉刷新,上拉加载就搞定了,其实很容易,而且也有点Material

Design 的感觉~~~~~~

看下Adapter的全部代码

在这里插入图片描述

Demo2(即时通讯对话列表)

实现多种item有许多种方式,我们这里就用RecyclerView提供给我们的方式,getItemViewType。

这个方法是RecyclerView专门开放给我们用来实现多item类型的方法,所以他是最优雅的。

我仔细看过源码,这种方式用来实现多种Item,绝对是丝毫不影响性能的,请放心使用。

以即时通讯app为例子,你肯定要有一左一右的对话框吧。

所以在Adapter中先定义这两种ViewHolder。

private static class MeViewHolder extends RecyclerView.ViewHolder {
    TextView mTvMyMsg;
    ImageView mIvMyAvatar;

    public MeViewHolder(View view) {
        super(view);
        mTvMyMsg = (TextView) view.findViewById(R.id.tv_my_msg);
        mIvMyAvatar = (ImageView) view.findViewById(R.id.iv_my_avatar);
    }
}

private static class FriendViewHolder extends RecyclerView.ViewHolder {
    TextView mTvFriendMsg;
    ImageView mIvFriendAvatar;

    public FriendViewHolder(View view) {
        super(view);
        mTvFriendMsg = (TextView) view.findViewById(R.id.tv_friend_msg);
        mIvFriendAvatar = (ImageView) view.findViewById(R.id.iv_friend_avatar);
    }
}

getItemViewType方法,我这里list装的是bean,每个bean里都有一个,0代表我自己的对话,1代表对方的对话。

@Override
public int getItemViewType(int position) {
    return list.get(position).getMsgType();
}

onCreateViewHolder方法,一目了然

@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
    if (context == null) {
        context = parent.getContext();
    }
    if (viewType == TYPE_ME) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv_chat_me, parent, false);
        return new MeViewHolder(view);
    } else {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv_chat_friend, parent, false);
        return new FriendViewHolder(view);
    }
}

onBindViewHolder方法,也很简单

@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof MeViewHolder) {
        ((MeViewHolder) holder).mTvMyMsg.setText(list.get(position).getMsgContent());
    } else {
        ((FriendViewHolder) holder).mTvFriendMsg.setText(list.get(position).getMsgContent());
    }
}

就完了!
效果图:(我这里是点击添加一个对话,点击添加一个,即时通讯这里先不实现)

在这里插入图片描述

全部代码

package com.example.wechat.adapter;


import android.content.Context;
import android.content.Intent;
import android.support.v7.widget.RecyclerView;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.ImageView;
import android.widget.TextView;

import com.bumptech.glide.Glide;
import com.example.wechat.R;
import com.example.wechat.bean.ChatDetailBean;
import com.example.wechat.bean.ChatItemBean;
import com.example.wechat.chat.ChatActivity;

import java.util.List;

import static com.example.wechat.R.id.view;


public class ChatDetailAdapter extends RecyclerView.Adapter<RecyclerView.ViewHolder> {

    private List<ChatDetailBean> list;

    public ChatDetailAdapter(List<ChatDetailBean> list) {
        this.list = list;
    }

    private Context context = null;

    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        if (context == null) {
            context = parent.getContext();
        }
        if (viewType == TYPE_ME) {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv_chat_me, parent, false);
            return new MeViewHolder(view);
        } else {
            View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.item_rv_chat_friend, parent, false);
            return new FriendViewHolder(view);
        }
    }

    @Override
    public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof MeViewHolder) {
            ((MeViewHolder) holder).mTvMyMsg.setText(list.get(position).getMsgContent());
        } else {
            ((FriendViewHolder) holder).mTvFriendMsg.setText(list.get(position).getMsgContent());
        }
    }

    private static final int TYPE_ME = 0;
    private static final int TYPE_FRIEND = 1;

    @Override
    public int getItemViewType(int position) {
        return list.get(position).getMsgType();
    }

    @Override
    public int getItemCount() {
        return list.size();
    }

    private static class MeViewHolder extends RecyclerView.ViewHolder {
        TextView mTvMyMsg;
        ImageView mIvMyAvatar;

        public MeViewHolder(View view) {
            super(view);
            mTvMyMsg = (TextView) view.findViewById(R.id.tv_my_msg);
            mIvMyAvatar = (ImageView) view.findViewById(R.id.iv_my_avatar);
        }
    }

    private static class FriendViewHolder extends RecyclerView.ViewHolder {
        TextView mTvFriendMsg;
        ImageView mIvFriendAvatar;

        public FriendViewHolder(View view) {
            super(view);
            mTvFriendMsg = (TextView) view.findViewById(R.id.tv_friend_msg);
            mIvFriendAvatar = (ImageView) view.findViewById(R.id.iv_friend_avatar);
        }
    }
}

Demo3(电商app界面)

第一家公司做外包,做过不少电商项目,首页设计基本都是这个样

在这里插入图片描述

从上至下分别一个轮播图框,一个横向滑动的view用来展示一些特殊的列表,几个快捷菜单,和一个显示商品的列表。

实际应用里截图:

界面1
在这里插入图片描述


界面2
在这里插入图片描述

这里就用一个基本的例子来实现如何RecyclerView怎么进行多item布局。

先看效果图:

图片三
在这里插入图片描述


图片四
在这里插入图片描述


图片五
在这里插入图片描述

首先,轮播图的bean,横向List的bean,和正常list的bean肯定不同,而adapter只有一个与一个数组绑定,所以三种bean要可以是统一类型的bean,所以我定义了一个三种bean的父类bean就叫它ExampleBaseBean

public class ExampleBaseBean {

    private int viewType;

    public int getViewType() {
        return viewType;
    }

    public void setViewType(int viewType) {
        this.viewType = viewType;
    }
}

如代码所示,这个BaseBean主要作用就是提供一个int类型的vieType的对象用来区分不同类型的bean。

有了BaseBean,接下来就是三种bean了。

public class TitleBean extends ExampleBaseBean {
    //轮播bean,为了方便叫titleBean
    private List<String> titles;//轮播的数据源一般都为数组。

    public List<String> getTitles() {
        return titles;
    }

    public void setTitles(List<String> titles) {
        this.titles = titles;
    }
}
public class BodyBean extends ExampleBaseBean {
    //中间横向滑动的bean  ,通常都有图片展示,这里用本地图片展示
    private List<Integer> res;

    public List<Integer> getRes() {
        return res;
    }

    public void setRes(List<Integer> res) {
        this.res = res;
    }
}
public class FootBean extends ExampleBaseBean {
    //正常列表的bean
    private String str;

    public FootBean(String str) {
        this.str = str;
    }

    public String getStr() {
        return str;
    }

}

三种bean定义完,该着手adapter了。

public class ExampleAdapter extends RecyclerView.Adapter {

    public final static int TITLE = 1001;//标题的viewType
    public final static int BODY = 1002;//横向列表的viewType
    public final static int FOOT = 1003;//正常列表的viewType

    private List<ExampleBaseBean> mlist;//adapter的数据源
    private Context context;
    private LayoutInflater inflater;


    public ExampleAdapter(List<ExampleBaseBean> mlist) {
        this.mlist = mlist;
    }

首先在这个adapter里将会用到viewtype写成静态常量,方便外面统一。

先写三种bean对应的ViewHolder:

private class TitleHolder extends RecyclerView.ViewHolder {

    ViewPager vp;

    public TitleHolder(View itemView) {
        super(itemView);
        vp = itemView.findViewById(R.id.vp);
    }
}

private class BodyHolder extends RecyclerView.ViewHolder {

    RecyclerView rv;

    public BodyHolder(View itemView) {
        super(itemView);
        rv = itemView.findViewById(R.id.rv);
    }
}

private class FootHolder extends RecyclerView.ViewHolder {

    TextView tv_foot;

    public FootHolder(View itemView) {
        super(itemView);
        tv_foot = itemView.findViewById(R.id.tv_foot);
    }
}

三种ViewHolder写完了,然后就是复写RecyclerView.Adapter的getItemViewType方法来控制它返回给onCreateViewHolder的viewType:

@Override
public int getItemViewType(int position) {
    if (mlist.size() > 0) {
        return mlist.get(position).getViewType();
    }
    return super.getItemViewType(position);
}

然后就是adapter的主要方法onCreateViewHolder方法:

@NonNull
@Override
public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
    if (context == null)
        context = parent.getContext();
    if (inflater == null)
        inflater = LayoutInflater.from(context);
    View view;
    switch (viewType) {
        case TITLE:
            view = inflater.inflate(R.layout.listitem_title, parent, false);
            return new TitleHolder(view);
        case BODY:
            view = inflater.inflate(R.layout.listitem_body, parent, false);
            return new BodyHolder(view);
        case FOOT:
            view = inflater.inflate(R.layout.listitem_foot, parent, false);
            return new FootHolder(view);
    }
    return null;
}

根据onCreateViewHolder方法传来的viewType进行判断然后返回对应item布局的ViewHolder。

ViewHolder会被传到onBindViewHolder方法,接下来就只再要实现onBindViewHolder里就OK了。

@Override
public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
    if (holder instanceof TitleHolder) {
        TitleBean titleBean = (TitleBean) mlist.get(position);
        ((TitleHolder) holder).vp.setAdapter(new PagerAdapter(titleBean.getTitles()));
    }

    if (holder instanceof BodyHolder) {
        BodyBean bodyBean = (BodyBean) mlist.get(position);
        ((BodyHolder) holder).rv.setLayoutManager(new LinearLayoutManager(context, LinearLayout.HORIZONTAL, false));
        ((BodyHolder) holder).rv.setAdapter(new BodyAdapter(bodyBean.getRes()));
    }

    if (holder instanceof FootHolder) {
        FootBean footBean = (FootBean) mlist.get(position);
        ((FootHolder) holder).tv_foot.setText(footBean.getStr());
    }
}

这里的viewPager的adapter我图省事直接写成内部类了

private class PagerAdapter extends android.support.v4.view.PagerAdapter {

    List<String> stringList;

    public PagerAdapter(List<String> stringList) {
        this.stringList = stringList;
    }

    @NonNull
    @Override
    public Object instantiateItem(@NonNull ViewGroup container, int position) {
        ViewPager.LayoutParams params = new ViewPager.LayoutParams();
        params.width = ViewPager.LayoutParams.WRAP_CONTENT;
        params.height = ViewPager.LayoutParams.WRAP_CONTENT;
        params.gravity = Gravity.CENTER;
        TextView textView = new TextView(container.getContext());
        textView.setText(stringList.get(position));
        textView.setTextSize(30);
        textView.setTextColor(Color.parseColor("#333333"));
        textView.setLayoutParams(params);
        container.addView(textView);
        return textView;
    }

    @Override
    public void destroyItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
        container.removeView((View) object);
    }

    @Override
    public int getCount() {
        return stringList.size();
    }

    @Override
    public boolean isViewFromObject(@NonNull View view, @NonNull Object object) {
        return view == object;
    }
}

还有一个Body的adapter就是平时展示一种数据的adapter,这里也贴一下。

public class BodyAdapter extends RecyclerView.Adapter {

    private List<Integer> res;

    public BodyAdapter(List<Integer> res) {
        this.res = res;
    }

    @NonNull
    @Override
    public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = LayoutInflater.from(parent.getContext()).inflate(R.layout.listitem_body_img, parent, false);
        return new ImgHolder(view);
    }

    @Override
    public void onBindViewHolder(@NonNull RecyclerView.ViewHolder holder, int position) {
        if (holder instanceof ImgHolder) {
            ((ImgHolder) holder).iv.setImageResource(res.get(position));
        }
    }

    private class ImgHolder extends RecyclerView.ViewHolder {

        ImageView iv;

        public ImgHolder(View itemView) {
            super(itemView);
            iv = itemView.findViewById(R.id.iv);
        }
    }

    @Override
    public int getItemCount() {
        return res.size();
    }
}

还有就是Acitivy里模拟数据的添加代码:

public class ExampleActivity extends AppCompatActivity {

    private ExampleAdapter adapter;
    private List<ExampleBaseBean> mlist = new ArrayList<>();
    private RecyclerView rv;
    private Context context;
    
    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_example);
        context = this;
        rv = findViewById(R.id.rv);
        initTitle();
        initBody();
        initFoot();
        initAdapter();
    }

    private void initFoot() {
        for (int i = 0; i < 10; i++) {
            FootBean footBean=new FootBean("foot:"+i);
            footBean.setViewType(ExampleAdapter.FOOT);//正常列表
            mlist.add(footBean);
        }
    }

    private void initBody() {
        List<Integer> res = new ArrayList<>(6);
        res.add(R.mipmap.pic1);
        res.add(R.mipmap.pic2);
        res.add(R.mipmap.pic3);
        res.add(R.mipmap.pic4);
        res.add(R.mipmap.pic5);
        res.add(R.mipmap.pic6);
        BodyBean bodyBean = new BodyBean();
        bodyBean.setRes(res);
        bodyBean.setViewType(ExampleAdapter.BODY);//设置横向列表的类型
        mlist.add(bodyBean);
    }

    private void initTitle() {
        List<String> titles = new ArrayList<>(5);
        for (int i = 0; i < 5; i++) {
            titles.add(new StringBuilder("标题").append(i).toString());
        }
        TitleBean titleBean = new TitleBean();
        titleBean.setTitles(titles);
        titleBean.setViewType(ExampleAdapter.TITLE);//设置为轮播类型
        mlist.add(titleBean);
    }

    private void initAdapter() {
        if (adapter == null) {
            adapter = new ExampleAdapter(mlist);
            rv.setLayoutManager(new LinearLayoutManager(context));
            rv.setAdapter(adapter);
        } else {
            adapter.notifyDataSetChanged();
        }
    }

}

Item的xml布局也极其简单都是只有一个控件,就不贴了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值