博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
Android RecyclerView从入门到玩坏
阅读量:7121 次
发布时间:2019-06-28

本文共 13071 字,大约阅读时间需要 43 分钟。

目录

  • 前言
  • 基础使用
  • 分隔线
  • 点击监听
  • 搭配CardView
  • 更丰富的条目
  • 增删条目
  • 快速添加视图
  • 让RecyclerView支持复杂视图
  • 最后

前言

RecyclerView在Android界面开发当中是很重要的, 那掌握它也是很必要的. 但是有些时候会觉得它很厚重, 这里就从RecyclerView的基础一直说到扩展, 让你把RecyclerView学薄了.

也是非常厚重.

这篇文章融合了自己原来的多篇文章, 并进行了修正和改进, 而且添加了很多很有趣的内容.

本文需要20分钟以上的阅读时间, 请合理安排.
多图预警, 转载请注明出处!


基础使用

要使用RecyclerView在Android Studio 2.x(以下简称AS), 要这样:

compile 'com.android.support:cardview-v7:25.3.1'compile 'com.android.support:recyclerview-v7:25.3.1'

到了AS 3.x, 要这样:

implementation 'com.android.support:cardview-v7:26.1.0'implementation 'com.android.support:recyclerview-v7:26.1.0'

之后在布局文件中写入如下代码就引入了RecyclerView了.

接下来说说介绍些各种布局. 可以看.

布局类 效果
LinearLayoutManager 以垂直或水平滚动列表方式显示项目
GridLayoutManager 在网格中显示项目
StaggeredGridLayoutManager 在分散对齐网格中显示项目
mRvMain = (RecyclerView) findViewById(R.id.rv_main);// 设置布局LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);mRvMain.setLayoutManager(linearLayoutManager);

最关键的还是适配器的撰写. 但是理解起来不是很难, 你只要将ListView的适配器写法带入理解就好. 这里把全部代码贴出来, 因为后面要在这个基础上不断扩充.

public class MyRVAdapter2 extends RecyclerView.Adapter
{ private final LayoutInflater mLayoutInflater; private final Context mContext; private final ArrayList
mData; public MyRVAdapter2(Context context) { mLayoutInflater = LayoutInflater.from(context); mContext = context; mData = new ArrayList<>(); for (int i = 0; i < 40; i++) { mData.add("hello " + i); } } @Override public MyRVAdapter2.MyTVHolder onCreateViewHolder(ViewGroup parent, int viewType) { return new MyRVAdapter2.MyTVHolder(mLayoutInflater.inflate(R.layout.rv_txt_item, parent, false)); } @Override public void onBindViewHolder(final MyRVAdapter2.MyTVHolder holder, int pos) { holder.mTextView.setText(mData.get(pos)); } @Override public int getItemCount() { return mData == null ? 0 : mData.size(); } class MyTVHolder extends RecyclerView.ViewHolder { TextView mTextView; MyTVHolder(View itemView) { super(itemView); mTextView = (TextView) itemView.findViewById(R.id.tv_txt); } }}

然后写个最基础的TextView条目. 让它跑起来看看效果.

基础

分隔线

前面的部分已经是基础的RecyclerView使用了. 那比起ListView是不是没有了分隔线. 这里上一个简单好用的开源库.

引入:

implementation 'com.yqritc:recyclerview-flexibledivider:1.4.0'

使用:

mRvMain.addItemDecoration(        new HorizontalDividerItemDecoration.Builder(this).build());

看效果就达到了吧.

分隔线

觉得不好看, 还可以自定义, 更多写法可以参见.

mRvMain.addItemDecoration(        new HorizontalDividerItemDecoration.Builder(this)                .color(Color.BLUE)                .sizeResId(R.dimen.two_dp)                .marginResId(R.dimen.eight_dp, R.dimen.eight_dp)                .build());
自定义分隔线

而且而且, 竖着的分隔线也大丈夫哦.

GridLayoutManager gridLayoutManager        = new GridLayoutManager(this, 2);mRvMain.setLayoutManager(gridLayoutManager);
mRvMain.addItemDecoration(        new VerticalDividerItemDecoration.Builder(this).build());
竖线

点击监听

再回忆一下在天国的ListView, 还有item的点击吧, 这个也要自己写.

适配器中:

public interface OnItemClickListener {    void onItemClick(View view, int position);    void onItemLongClick(View view, int position);}private MyRVAdapter2.OnItemClickListener mOnItemClickListener;public void setOnItemClickListener(MyRVAdapter2.OnItemClickListener mOnItemClickListener) {    this.mOnItemClickListener = mOnItemClickListener;}

onBindViewHolder中设置点击监听.

@Overridepublic void onBindViewHolder(final MyRVAdapter2.MyTVHolder holder, int pos) {    holder.mTextView.setText(mData.get(pos));    if (mOnItemClickListener != null) {        holder.itemView.setOnClickListener(new View.OnClickListener() {            @Override            public void onClick(View v) {                int pos = holder.getLayoutPosition();                mOnItemClickListener.onItemClick(holder.itemView, pos);            }        });        holder.itemView.setOnLongClickListener(new View.OnLongClickListener() {            @Override            public boolean onLongClick(View v) {                int pos = holder.getLayoutPosition();                mOnItemClickListener.onItemLongClick(holder.itemView, pos);                return false;            }        });    }}

使用监听:

mAdapter.setOnItemClickListener(new MyRVAdapter2.OnItemClickListener() {    @Override    public void onItemClick(View view, int position) {        Toast.makeText(UIUtil.getContext(), "click" + position, Toast.LENGTH_SHORT).show();    }    @Override    public void onItemLongClick(View view, int position) {        Toast.makeText(UIUtil.getContext(), "long click" + position, Toast.LENGTH_SHORT).show();    }});
点击

搭配CardView

是不是这个点击看着没啥感觉, 没事, 我们换上CardView再来一次.

布局文件:

cardview

给CardView加上水波纹点击特效:

波纹点击

在老版本就只能用选择器了, 其实效果也还好:

低版本兼容

更丰富的条目

大家应该都知道TextView可以设置图标吧, 这里来看下效果图, 顺带感受下android界面设计语言的变化.

4.x
8.x

让GridLayoutManager展示不同宽度的条目

方的是4.x上的, 圆的是8.x上的, 可以看到, 变化还是很大的. 我们回正题. GridLayoutManager布局是可以设置宽度的, 不一定都是一样大的, 来看下实现.

// 指定item宽度gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {    @Override    public int getSpanSize(int position) {        if (position == 0                || position == (mAdapter.getItemCount() - 1) / 2                || position == (mAdapter.getItemCount() - 1)) {            return gridLayoutManager.getSpanCount();        } else {            return 1;        }    }});

来看效果图, 发现我们的分隔线崩了是吧, 如果真想用这个分隔线也还是要自己动手修补修补, 改动改动, 开源库再棒也猜不到你的项目需求呀.

分隔线异常
设置宽度

当然了, 我还是很喜欢这个分隔线的, 我们来看看横着滚动的效果.

布局文件要改动:

gridLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL);
横滑

展示不同布局

之前变化宽度其实还是相同条目, 现在要展示不同条目:

写一个图的条目:

public enum ITEM_TYPE {    ITEM_TYPE_IMAGE,    ITEM_TYPE_TEXT}

这里多了判断条目类型, 还要注意返回值的变化, 用了更基类的RecyclerView.ViewHolder.

@Overridepublic RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {    if (viewType == ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal()) {        return new MyRVAdapter2.MyIVHolder(mLayoutInflater.inflate(R.layout.rv_img_item, parent, false));    } else {        return new MyRVAdapter2.MyTVHolder(mLayoutInflater.inflate(R.layout.rv_txt_item, parent, false));    }}

类继承上面也要变成RecyclerView.ViewHolder, 这些都是要对应的.

extends RecyclerView.Adapter

当然了, holder也是不能少的.

public class MyIVHolder extends RecyclerView.ViewHolder {    ImageView mImageView;    MyIVHolder(View view) {        super(view);        mImageView = (ImageView) view.findViewById(R.id.iv_img);    }}
@Overridepublic void onBindViewHolder(final RecyclerView.ViewHolder holder, int pos) {    if (holder instanceof MyRVAdapter2.MyTVHolder) {        ((MyRVAdapter2.MyTVHolder) holder).mTextView.setText(mData.get(pos));    } else if (holder instanceof MyRVAdapter2.MyIVHolder) {        ((MyRVAdapter2.MyIVHolder) holder).mImageView.setImageDrawable(UIUtil.getDrawable(R.mipmap.ic_launcher));    }    // 点击监听    ...}

顺带的, 我们把之前放宽的条目变成不同的视图, 也就是对应起来:

@Overridepublic int getItemViewType(int position) {    if (position == 0            || position == (getItemCount() - 1) / 2            || position == (getItemCount() - 1)) {        return ITEM_TYPE.ITEM_TYPE_IMAGE.ordinal();    } else {        return ITEM_TYPE.ITEM_TYPE_TEXT.ordinal();    }}

看看效果:

不同布局

它还能继续地复杂, 试试瀑布流StaggeredGridLayoutManager:

StaggeredGridLayoutManager staggeredGridLayoutManager        = new StaggeredGridLayoutManager(3, StaggeredGridLayoutManager.VERTICAL);mRvMain.setLayoutManager(staggeredGridLayoutManager);
瀑布流

分割线又崩了, 嘿嘿, 其实用上了CardView, 分割线没什么必要再用了.

分隔线异常

增删条目

现在适配器中添加增删方法:

public void addData(int position) {    mData.add(position, "hello x");    notifyItemInserted(position);}public void removeData(int position) {    mData.remove(position);    notifyItemRemoved(position);}

再写入点击事件中, 点击增加, 长按删除:

mAdapter.setOnItemClickListener(new MyRVAdapter2.OnItemClickListener() {    @Override    public void onItemClick(View view, int position) {        mAdapter.addData(position);    }    @Override    public void onItemLongClick(View view, int position) {        mAdapter.removeData(position);    }});
增删条目

增删条目开源库

这里再上一个开源库, 可以修改增删动画, 种类也很丰富, 还能在它基础上自定义:

分类 动画类名
Cool LandingAnimator
Scale ScaleInAnimator, ScaleInTopAnimator, ScaleInBottomAnimator, ScaleInLeftAnimator, ScaleInRightAnimator
Fade FadeInAnimator, FadeInDownAnimator, FadeInUpAnimator, FadeInLeftAnimator, FadeInRightAnimator
Flip FlipInTopXAnimator, FlipInBottomXAnimator, FlipInLeftYAnimator, FlipInRightYAnimator
Slide SlideInLeftAnimator, SlideInRightAnimator, OvershootInLeftAnimator, OvershootInRightAnimator, SlideInUpAnimator, SlideInDownAnimator

引入:

implementation 'jp.wasabeef:recyclerview-animators:2.3.0'

使用:

mRvMain.setItemAnimator(new SlideInLeftAnimator());

这里给大家展示两种效果, 其它的自己尝试吧.

增删动画
mRvMain.setItemAnimator(new LandingAnimator());
增删动画

快速添加视图

还有像Header, Foot这样的视图, 自己写也还是要费些功夫的, 这里推荐Android大神的库

引入:

implementation 'com.zhy:base-rvadapter:3.0.3'

添加头尾视图

HeaderAndFooterWrapper mHeaderAndFooterWrapper = new HeaderAndFooterWrapper(mAdapter);TextView t1 = new TextView(this);t1.setText("Header 1");t1.setTextSize(30);TextView t2 = new TextView(this);t2.setText("Foot 1");t2.setTextSize(30);mHeaderAndFooterWrapper.addHeaderView(t1);mHeaderAndFooterWrapper.addFootView(t2);mRvMain.setAdapter(mHeaderAndFooterWrapper);
头尾

添加更多视图

LoadMoreWrapper mLoadMoreWrapper = new LoadMoreWrapper(mAdapter);mLoadMoreWrapper.setLoadMoreView(R.layout.rv_cv_img_txt_item);mLoadMoreWrapper.setOnLoadMoreListener(new LoadMoreWrapper.OnLoadMoreListener() {    @Override    public void onLoadMoreRequested() {    }});mRvMain.setAdapter(mLoadMoreWrapper);
更多

是不是感觉特别爽, 那看看更爽的, 在不写适配器的情况下快速添加条目:

final ArrayList
mData = new ArrayList<>();for (int i = 0; i < 40; i++) { mData.add("hello " + i);}mRvMain.setAdapter(new CommonAdapter
(this, R.layout.rv_cv_txt_item, mData) { @Override protected void convert(ViewHolder holder, String s, int position) { holder.setText(R.id.tv_txt, mData.get(position)); }});
快速添加条目

是不是感觉省了一万个小时呢.


让RecyclerView支持复杂视图

每次加入新的视图都要对适配器进行比较大程度的改动, 这样是很容易出错的. 这里引入一个非常棒的开源库-, 降低下代码耦合性.

引入:

implementation 'com.hannesdorfmann:adapterdelegates3:3.0.1'

先不说使用细节, 来看看实现后想加入不同视图有多简单吧:

ArrayList data = new ArrayList<>();for (int i = 0; i < 10; i++) {    data.add(new B("b " + i));}for (int i = 0; i < 10; i++) {    data.add(new A("a " + i));}BaseAdapter animalAdapter = new BaseAdapter(this, data);mRvMain.setAdapter(animalAdapter);
添加复杂条目

是不是惊了, 也就是说, 你只要实现了A, B这些视图类, 直接新建放入数组就完事了.

需要写基础适配器:

public class BaseAdapter extends RecyclerView.Adapter {    private AdapterDelegatesManager
> delegatesManager; private List
items; public BaseAdapter(Activity activity, List
items) { this.items = items; delegatesManager = new AdapterDelegatesManager<>(); delegatesManager.addDelegate(new AAdapterDelegate(activity)) .addDelegate(new BAdapterDelegate(activity)); } @Override public int getItemViewType(int position) { return delegatesManager.getItemViewType(items, position); } @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) { return delegatesManager.onCreateViewHolder(parent, viewType); } @Override public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) { delegatesManager.onBindViewHolder(items, position, holder); } @Override public int getItemCount() { return items.size(); }}

需要对每个类进行进行具体设置, 这里以A为例.

public class AAdapterDelegate extends AdapterDelegate
> { private LayoutInflater inflater; public AAdapterDelegate(Activity activity) { inflater = activity.getLayoutInflater(); } @Override public boolean isForViewType(@NonNull List
items, int position) { return items.get(position) instanceof A; } @NonNull @Override public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent) { return new CatViewHolder(inflater.inflate(R.layout.rv_cv_img_txt_item, parent, false)); } @Override public void onBindViewHolder(@NonNull List
items, int position, @NonNull RecyclerView.ViewHolder holder, @Nullable List
payloads) { CatViewHolder vh = (CatViewHolder) holder; A cat = (A) items.get(position); vh.name.setText(cat.getName()); } static class CatViewHolder extends RecyclerView.ViewHolder { public TextView name; public ImageView img; public CatViewHolder(View itemView) { super(itemView); name = (TextView) itemView.findViewById(R.id.tv_txt); img = (ImageView) itemView.findViewById(R.id.iv_img); } }}

最后

看完这篇应该是对RecyclerView有个大体认识了, 多练习练习就会得心应手起来了. 那还是有一点, 就像分隔线库的几次不理想表现, 具体项目要求还是要具体对待, 开源库也不是万能的. 最近不是又有什么开源项目套壳事件了嘛, 别人一开源就说自己有自主产权了真的好吗? 喜欢记得点赞或者关注我哦, 有意见或者建议评论区见~


你可能感兴趣的文章
实验1
查看>>
CF915E Physical Education Lessons(珂朵莉树)
查看>>
洛谷P5050 【模板】多项式多点求值
查看>>
第十章:基本数据结构(2)
查看>>
php处理管道文件流
查看>>
Centos 6 搭建安装 Gitlab
查看>>
2012.02.13(rtsp)
查看>>
关于设置安卓屏幕的显示方向
查看>>
面试题10-二进制中1的个数
查看>>
cmd 查看域名对应的 IP
查看>>
LED流水灯程序——小白的单片机笔记
查看>>
sysdate
查看>>
股指期货模拟系统
查看>>
基于Spark的电影推荐系统(电影网站)
查看>>
【HNOI 2016】序列
查看>>
PowerShell定时记录操作系统行为
查看>>
Angular2之路由学习笔记
查看>>
JSP中文件上传的关键步骤
查看>>
数据结构上机3栈-括号匹配
查看>>
xfire冲突问题解决(maven配置)
查看>>