目录

前言

基础使用

分隔线

点击监听

搭配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了.

android:id="@+id/rv_main"

android:layout_width="match_parent"

android:layout_height="match_parent"

android:scrollbars="vertical" />

布局类

效果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条目. 让它跑起来看看效果.

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:id="@+id/tv_txt"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_horizontal"

android:padding="@dimen/eight_dp"

android:text="@string/tmp"

android:textSize="@dimen/thirty_sp" />

分隔线

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

引入:

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中设置点击监听.

@Override

public 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再来一次.

布局文件:

xmlns:card_view="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="@dimen/eight_dp"

android:foreground="@drawable/card_foreground"

card_view:cardCornerRadius="@dimen/four_dp">

android:id="@+id/tv_txt"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:gravity="center_horizontal"

android:padding="@dimen/eight_dp"

android:text="@string/tmp"

android:textSize="@dimen/thirty_sp" />

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

android:color="@color/colorPrimary" />

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

android:drawable="@drawable/card_foreground_selector"

android:insetBottom="@dimen/four_dp"

android:insetLeft="@dimen/three_dp"

android:insetRight="@dimen/three_dp"

android:insetTop="@dimen/four_dp" />

更丰富的条目

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

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="horizontal">

android:id="@+id/tv_txt"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:drawableLeft="@mipmap/ic_launcher"

android:drawablePadding="@dimen/sixteen_dp"

android:drawableStart="@mipmap/ic_launcher"

android:gravity="center_vertical"

android:padding="@dimen/eight_dp"

android:text="@string/tmp"

android:textSize="@dimen/thirty_sp" />

让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;

}

}

});

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

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

布局文件要改动:

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:orientation="horizontal">

android:id="@+id/tv_txt"

android:layout_width="wrap_content"

android:layout_height="match_parent"

android:gravity="center_vertical"

android:text="@string/tmp"

android:textSize="@dimen/thirty_sp" />

gridLayoutManager.setOrientation(GridLayoutManager.HORIZONTAL);

展示不同布局

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

写一个图的条目:

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:padding="@dimen/eight_dp">

android:id="@+id/iv_img"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_centerInParent="true"

android:class="lazyload" src="https://img-blog.csdnimg.cn/2022010702381440793.png" data-original="@mipmap/ic_launcher" />

public enum ITEM_TYPE {

ITEM_TYPE_IMAGE,

ITEM_TYPE_TEXT

}

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

@Override

public 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);

}

}

@Override

public 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));

}

// 点击监听

...

}

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

@Override

public 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:

xmlns:card_view="http://schemas.android.com/apk/res-auto"

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:layout_margin="@dimen/eight_dp"

card_view:cardCornerRadius="@dimen/four_dp">

android:layout_width="match_parent"

android:layout_height="wrap_content"

android:orientation="vertical">

android:id="@+id/iv_img"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:class="lazyload" src="https://img-blog.csdnimg.cn/2022010702381440793.png" data-original="@mipmap/ic_launcher" />

android:id="@+id/tv_txt"

android:layout_width="wrap_content"

android:layout_height="wrap_content"

android:layout_gravity="center_horizontal"

android:text="@string/tmp"

android:textSize="@dimen/thirty_sp" />

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);

}

});

增删条目开源库

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

分类

动画类名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大神的库baseAdapter

引入:

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支持复杂视图

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

引入:

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

Android view.settran,Android RecyclerView从入门到玩坏相关推荐

  1. android view选中状态,RecyclerView选中

    ###**RecyclerView选中状态** ~~~ package com.wxx.fragmentaction.recycler; import android.content.Context; ...

  2. android view嵌套,Android RecyclerView嵌套RecyclerView点击事件

    RecyclerView嵌套RecyclerView点击事件遇到取值错乱的问题 其实问题根本就是咱们没有处理好被嵌套的那层recycleview的position 那么解决思路也很简单,想办法把被嵌套 ...

  3. android view禁用,Android 禁止ViewPager的自带滑动效果

    由于最近在做墨水屏的相关工作,ViewPager自带的滑动效果在墨水屏上表现的很不好,残影太重了.所以禁止自带的滑动效果,用接口来接管相关逻辑实现自处理. import android.content ...

  4. Android view变形,android仿变形金刚效果实现MatchView

    what?变形金刚!先看效果吧! MainActivity.javapackage com.lee.matchview; import com.example.matchview.R; import ...

  5. android.view.surface,Android SurfaceView 源码分析及使用

    概述 SurfaceView 是 Android 中一种比较特殊的视图(View),它跟平时时候的 TextView.Button 最大的区别是它跟它的视图容器并不是在同一个视图层上,它的 UI 显示 ...

  6. android view flipper,Android之ViewFlipper的简单使用

    大家都使用过ViewPager,但是ViewPager还有一个兄弟,那就是ViewFlipper.两者的名字非常相似,我们可以将ViewPager理解成"一页一页的视图",View ...

  7. android view 虚线分割线,RecyclerView设置分割线---DividerItemDecoration

    官方提供的分割线处理方案,也是继承的RecyclerView.ItemDecoration实现的. divider.png 用法很简单,注释里面有demo.同时也可以通过自定义drawable来实现d ...

  8. android view setleft,android – 在新textview上使用setLeft / setRight方法

    我正在以编程方式使用TextViews,我需要动态添加新视图并在RelativeLayout父级中设置它们的左/顶位置. 我正在做的是这样的: RelativeLayout global=(Relat ...

  9. android view 平滑,Android移动view动画问题(让移动更平滑)

    Android写动画效果不是一般的麻烦,网上找了好久,终于解决了动画的问题,总结记录以共勉. 仅以水平方向移动效果做说明,垂直方向类似. 完整动画函数代码: public void slideview ...

最新文章

  1. vue 组件以字符串插入_今日分享:vue3多层嵌套组件如何访问到最外层组件的数据?...
  2. 【Alertmanager】腾讯企业邮箱配置
  3. go io.reader 多次读取_Go 经典入门系列 24:Select
  4. 了解Scaffold Generator (转载)
  5. java slf4j_SLF4J 使用手册
  6. 关于Linux线程的线程栈以及TLS
  7. Dell PowerEdge R740xd可以做什么?
  8. 在使用DelphiXE3和SQLite3进行程序开发时,解决最后一个字符乱码的问题
  9. javascript紧接上一张for循环的问题,我自己的理解
  10. php数组array_filter,php数组array_filter()函数和array_slice()函数
  11. 【历史上的今天】8 月 31 日:人工智能起源;GPU诞生;Windows 98中文版来了
  12. 室内定位之蓝牙定位精度(蓝牙AOA定位)
  13. 专升本C语言必刷编程题
  14. 计算智能3--进化计算
  15. kubernetes 1.10.3 cAdvisor + Heapster + InfluxDB + Grafana
  16. Android开发 之 OpenGL ES系列(5--3D立体图形)
  17. Docker推送镜像到自己的阿里云卡住,也不报错
  18. 理县“有福童享”“牵手圆梦 陪伴成长”关爱折翼天使志愿服务活动
  19. 信息系统项目管理师-业务流程管理知识点
  20. Android 存储相册,Android 相册图片存储

热门文章

  1. java音频实时传输_会议室智能系统建设方案,实时远程视频协作
  2. html中两个图片叠放,CSS实现图片叠放(勾选图标)
  3. python多线程输出_萌新python多线程
  4. python词云乱码_python词云库wordCloud使用方法详解(解决中文乱码)
  5. jdbc mysql分页_JDBC【数据库连接池、DbUtils框架、分页】
  6. Latex 表格 行合并,列合并,控制行间距 单元格宽度
  7. 编写第二个Spring程序——AOP实现
  8. 理解lua中 . : self
  9. EMC VMAX的磁盘构成,fast policy(重要)
  10. windows(win7,win8,xp)hosts文件找不到原因分析及解决方法