RecyclerView 的使用(androidx)

article/2025/11/10 15:59:12

文章目录

    • 一、导包
    • 二、基本使用
    • 三、设置分割线
    • 四、自定义点击事件
    • 五、实现 GridView
    • 六、实现瀑布流
    • 七、更多效果
    • 八、RecyclerView 常见问题
    • 九、RecyclerView 和 ScrollView 嵌套的问题

一、导包

 implementation 'androidx.recyclerview:recyclerview:1.1.0'

二、基本使用

2.1、首先是两个布局文件

Activity 的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent"android:orientation="vertical"><androidx.recyclerview.widget.RecyclerViewandroid:id="@+id/recyclerView"android:layout_width="match_parent"android:layout_height="wrap_content" />
</LinearLayout>

item 的布局文件

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:orientation="vertical"><TextViewandroid:id="@+id/tvItem"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center" /></LinearLayout>

2.2、Adapter 代码

public class HomeAdapter extends RecyclerView.Adapter<HomeAdapter.MyViewHolder> {private List<String> mList;private Context mContext;public HomeAdapter(Context mContext, List<String> mList) {this.mContext = mContext;this.mList = mList;}public void removeData(int position) {mList.remove(position);notifyDataSetChanged();}@NonNull@Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_recycler, parent, false);MyViewHolder holder = new MyViewHolder(itemView);return holder;}@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {holder.tv.setText(mList.get(position));}@Overridepublic int getItemCount() {return mList.size();}class MyViewHolder extends RecyclerView.ViewHolder {private TextView tv;public MyViewHolder(@NonNull View itemView) {super(itemView);tv = itemView.findViewById(R.id.tvItem);}}
}

2.3、Activity 中的代码

public class MainActivity extends AppCompatActivity {private RecyclerView mRecyclerView;private HomeAdapter mHomeAdapter;private List<String> mList;@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);mRecyclerView = this.findViewById(R.id.recyclerView);// 设置布局管理器LinearLayoutManager linearLayoutManager = new LinearLayoutManager(this);linearLayoutManager.setOrientation(RecyclerView.VERTICAL);mRecyclerView.setLayoutManager(linearLayoutManager);// 设置 item 增加和删除时的动画mRecyclerView.setItemAnimator(new DefaultItemAnimator());mList = getList();mHomeAdapter = new HomeAdapter(this, mList);mRecyclerView.setAdapter(mHomeAdapter);}private List<String> getList() {List<String> list = new ArrayList<>();for (int i = 0; i < 100; i++) {list.add(i + "");}return list;}
}

2.4、排列方向

垂直排列(默认): linearLayoutManager.setOrientation(RecyclerView.VERTICAL);
水平排列: linearLayoutManager.setOrientation(RecyclerView.HORIZONTAL);

运行效果

在这里插入图片描述

三、设置分割线

参考博客:
RecyclerView之ItemDecoration由浅入深
RecyclerView 之 ItemDecoration 讲解及高级特性实践
正确使用RecyclerView分割线

3.1、默认分割线。

 mRecyclerView.addItemDecoration(new DividerItemDecoration(this, RecyclerView.VERTICAL));

效果图:

在这里插入图片描述
3.2、复制 DividerItemDecoration 的源码进行修改。参考 5.2 中示例

我们可以根据默认分割线的源码,继承 RecyclerView.ItemDecoration 来自定义分割线。里面核心的方法就是 onDraw 方法,它根据传进来的 orientation 来判断是绘制横向 item 的分割线还是纵向 item 的分割线。getItemOffsets 方法则用于设置 item 的 padding 属性。

四、自定义点击事件

1、自定义接口并提供回调方法

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

2、Adapter 继承 View.OnClickListener 和 View.OnLongClickListener 并实现其中的方法。

3、OnBindViewHolder 方法中给 item 设置 tag。

    @Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {holder.itemView.setTag(position);holder.tv.setText(mList.get(position));}

4、监听 item 的点击事件并回调给我们自定义的监听。

    @Overridepublic MyViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {View itemView = LayoutInflater.from(mContext).inflate(R.layout.item_recycler, parent, false);MyViewHolder holder = new MyViewHolder(itemView);itemView.setOnClickListener(this);itemView.setOnLongClickListener(this);return holder;}
    @Overridepublic void onClick(View v) {if (mOnItemClickListener != null) {mOnItemClickListener.onItemClick(v, (int) v.getTag());}}@Overridepublic boolean onLongClick(View v) {if (mOnItemClickListener != null) {mOnItemClickListener.onItemLongClick(v, (int) v.getTag());}return false;}

5、最后在 Activity 中进行监听

        mHomeAdapter.setOnItemClickListener(new HomeAdapter.OnItemClickListener() {@Overridepublic void onItemClick(View view, int position) {Toast.makeText(MainActivity.this, "点击了第" + (position + 1) + "条", Toast.LENGTH_SHORT).show();}@Overridepublic void onItemLongClick(View view, final int position) {new AlertDialog.Builder(MainActivity.this).setTitle("确认删除吗?").setNegativeButton("取消", null).setPositiveButton("确定", new DialogInterface.OnClickListener() {@Overridepublic void onClick(DialogInterface dialog, int which) {mHomeAdapter.removeData(position);}}).show();}});

长按时会弹出对话框,效果如下。

在这里插入图片描述

五、实现 GridView

5.1、布局管理器

这里设置 4 列

  GridLayoutManager gridLayoutManager = new GridLayoutManager(this,4);mRecyclerView.setLayoutManager(gridLayoutManager);

或者用瀑布流布局管理器

  StaggeredGridLayoutManager staggeredGridLayoutManager = new StaggeredGridLayoutManager(4, StaggeredGridLayoutManager.HORIZONTAL);mRecyclerView.setLayoutManager(staggeredGridLayoutManager);

注意StaggeredGridLayoutManager.VERTICAL 的情况下,4 是列数,表示只有 4 列。改为 StaggeredGridLayoutManager.HORIZONTAL 方向时,4 是行数,表示只有 4 行。

5.2、分割线

没有默认的网格布局分割线,这里我们通过修改 DividerItemDecoration 的源码自定义一个分割线。代码如下:

public class DividerGridItemDecoration extends RecyclerView.ItemDecoration {public static final int HORIZONTAL = LinearLayout.HORIZONTAL;public static final int VERTICAL = LinearLayout.VERTICAL;private static final String TAG = "DividerItem";private static final int[] ATTRS = new int[]{android.R.attr.listDivider};private Drawable mDivider;private int mOrientation;private final Rect mBounds = new Rect();public DividerGridItemDecoration(Context context) {final TypedArray a = context.obtainStyledAttributes(ATTRS);mDivider = a.getDrawable(0);if (mDivider == null) {Log.w(TAG, "@android:attr/listDivider was not set in the theme used for this "+ "DividerItemDecoration. Please set that attribute all call setDrawable()");}a.recycle();}public void setDrawable(@NonNull Drawable drawable) {if (drawable == null) {throw new IllegalArgumentException("Drawable cannot be null.");}mDivider = drawable;}@Nullablepublic Drawable getDrawable() {return mDivider;}@Overridepublic void onDraw(Canvas c, RecyclerView parent, RecyclerView.State state) {if (parent.getLayoutManager() == null || mDivider == null) {return;}drawVertical(c, parent);drawHorizontal(c, parent);}private void drawVertical(Canvas canvas, RecyclerView parent) {canvas.save();final int left;final int right;//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.if (parent.getClipToPadding()) {left = parent.getPaddingLeft();right = parent.getWidth() - parent.getPaddingRight();canvas.clipRect(left, parent.getPaddingTop(), right,parent.getHeight() - parent.getPaddingBottom());} else {left = 0;right = parent.getWidth();}final int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {final View child = parent.getChildAt(i);parent.getDecoratedBoundsWithMargins(child, mBounds);final int bottom = mBounds.bottom + Math.round(child.getTranslationY());final int top = bottom - mDivider.getIntrinsicHeight();mDivider.setBounds(left, top, right, bottom);mDivider.draw(canvas);}canvas.restore();}private void drawHorizontal(Canvas canvas, RecyclerView parent) {canvas.save();final int top;final int bottom;//noinspection AndroidLintNewApi - NewApi lint fails to handle overrides.if (parent.getClipToPadding()) {top = parent.getPaddingTop();bottom = parent.getHeight() - parent.getPaddingBottom();canvas.clipRect(parent.getPaddingLeft(), top,parent.getWidth() - parent.getPaddingRight(), bottom);} else {top = 0;bottom = parent.getHeight();}final int childCount = parent.getChildCount();for (int i = 0; i < childCount; i++) {final View child = parent.getChildAt(i);parent.getLayoutManager().getDecoratedBoundsWithMargins(child, mBounds);final int right = mBounds.right + Math.round(child.getTranslationX());final int left = right - mDivider.getIntrinsicWidth();mDivider.setBounds(left, top, right, bottom);mDivider.draw(canvas);}canvas.restore();}@Overridepublic void getItemOffsets(Rect outRect, View view, RecyclerView parent,RecyclerView.State state) {if (mDivider == null) {outRect.set(0, 0, 0, 0);return;}if (mOrientation == VERTICAL) {outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());} else {outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);}}
}

添加分割线

        DividerGridItemDecoration gridItemDecoration=new DividerGridItemDecoration(this);mRecyclerView.addItemDecoration(gridItemDecoration);

运行效果如下

在这里插入图片描述

5.3、每个item占用的格数

使用setSpanSizeLookup函数,其中传入一个GridLayoutManager.SpanSizeLookup对象,其内部有一个抽象函数getSpanSize(),你可以设置返回的数值,让当前的item占据几个位置,当然返回的int型数值只能小于等于GridLayoutManager设置span的个数,比如每行item的个数为4个,然后你设置返回5,就会报错。

首先我们不能再以上面的方式添加分割线了,而是通过设置item的样式来设置分割线,为了更加直观添加了一个颜色。

<?xml version="1.0" encoding="utf-8"?>
<shape xmlns:android="http://schemas.android.com/apk/res/android"><strokeandroid:width="1dp"android:color="#000000" /><solid android:color="@color/colorAccent" />
</shape>

设置每个数据占用的格数。

        GridLayoutManager gridLayoutManager = new GridLayoutManager(this, 4);gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {@Overridepublic int getSpanSize(int position) {if (position == 0) {return 4;} else if (position == 2) {return 3;} else {return 1;}}});

这里设置第1个数据占用4格,第3个数据占用3格,其余的都只占用一格。效果图如下。

在这里插入图片描述

六、实现瀑布流

6.1、修改 item 布局

为了实现方便,瀑布流不用分割线,我们定义 item 的分割距离为 2dp,为了更加直观,我们还给 item 添加了一个颜色。

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_margin="2dp"android:background="@color/colorPrimary"android:orientation="vertical"><TextViewandroid:id="@+id/tvItem"android:layout_width="match_parent"android:layout_height="50dp"android:gravity="center" /></LinearLayout>

6.2、每个 item 的高度

通常这个高度是由服务器返回的数据高度来控制的,在这里我们写一个随机高度来控制 item。

        mHeights = new ArrayList<>();for (int i = 0; i < mList.size(); i++) {mHeights.add((int) (100 + Math.random() * 300));}

设置 item 的高度

@Overridepublic void onBindViewHolder(@NonNull MyViewHolder holder, int position) {holder.itemView.setTag(position);holder.tv.setText(mList.get(position));ViewGroup.LayoutParams lp = holder.tv.getLayoutParams();lp.height = mHeights.get(position);holder.tv.setLayoutParams(lp);}

运行效果如下
在这里插入图片描述

七、更多效果

Recyclerview实现滑动放大ItemView

八、RecyclerView 常见问题

  • 给 RecyclerView 设置 padding 时,滚动内容时与屏幕边缘存在一个间隙
    给 RecyclerView 设置布局属性:android:clipToPadding=“false”

九、RecyclerView 和 ScrollView 嵌套的问题

  • 滑动不流畅
    代码中:RecyclerView 使用 setNestedScrollingEnabled(false) 方法禁止嵌套滑动。
    或者布局中:android:nestedScrollingEnabled=“false”
  • 首次进入会占用焦点,导致 ScrollView 不能显示最上方
    RecyclerView 设置 setFocusable(false) 。
  • 显示不全
    外层嵌套布局并使用 android:descendantFocusability=“blocksDescendants” 属性。
            <RelativeLayoutandroid:layout_width="match_parent"android:layout_height="wrap_content"android:descendantFocusability="blocksDescendants"><android.support.v7.widget.RecyclerViewandroid:id="@+id/recyclerview"android:layout_width="match_parent"android:layout_height="wrap_content" /></RelativeLayout>

http://chatgpt.dhexx.cn/article/Y3kyqRtf.shtml

相关文章

RecyclerView简单使用(非常详细)

星期六&#xff0c;又是撸代码的一天 作为一个初级都算不上的小白&#xff0c;一步一个脚印的学吧&#xff0c;学一个记一个 今天记录的是RecyclerView RecyclerView 简述创建布局添加 RecyclerView和每个list布局&#xff08;偏新手向&#xff0c;选择性跳过&#xff09; 创建…

androidx.recyclerview:recyclerview的使用

添加扩展 或手动修改app/build.gradle&#xff1a; 在dependencies里添加 implementation androidx.recyclerview:recyclerview:1.0.0新建布局layout item布局fruit_item.xml&#xff1a; <?xml version"1.0" encoding"utf-8"?> <LinearLayo…

Android学习之RecyclerView的使用

RecyclerView是Android 5.0推出的&#xff0c;是support-v7包中的新组件,它被用来代替ListView和GridView&#xff0c;并且能够实现瀑布流的布局&#xff0c;更加高级并且更加灵活&#xff0c;提供更为高效的回收复用机制&#xff0c;同时实现管理与视图的解耦合。 官方文档解释…

RecyclerView剖析

####简介   本文将从RecyclerView实现原理并结合源码详细分析这个强大的控件。阅读本文要求&#xff1a;1、熟悉android控件绘制&#xff0c;2、了解动画&#xff0c;3、了解Scroller.本文所示源码版本是23.2.0。 ####基本使用   RecyclerView的基本使用并不复杂&#xff…

RecyclerView的使用(一)

目录 1.RecyclerView概述 2.RecyclerView的简单使用 3.改变布局管理器&#xff0c;RecyclerView的变化 1.RecyclerView概述 在谷歌Android官网&#xff0c;给RecyclerView的描述是: 那RecyclerView凭什么要比ListView要更高级&#xff1f;更灵活&#xff1f; 答案是&#x…

RecyclerView详解

RecyclerView 简称 RV&#xff0c; 是作为 ListView 和 GridView 的加强版出现的&#xff0c;目的是在有限的屏幕之上展示大量的内容&#xff0c;因此 RecyclerView 的复用机制的实现是它的一个核心部分。 RV 常规使用方式如下&#xff1a; 解释说明。 setLayoutManager&…

RecyclerView(三)—— RecyclerView的缓存机制

RecyclerView内存优越性&#xff0c;得益于它独特的缓存机制。 1 如何复用表项 如果列表中的每个表项在移出屏幕时被销毁&#xff0c;移入时又被重新创建&#xff0c;是很消耗资源&#xff0c;所以RecyclerView引入了缓存机制。缓存是为了复用&#xff0c;复用的好处是有可能…

RecyclerView详解一,使用及缓存机制

本文大致会先讲解RecyclerView的基础知识及使用&#xff0c;最后会深入讲解一点原理。当然&#xff0c;本人知识水平有限哈&#xff0c;太深入的东西我现在还没接触到&#xff0c;还请大家包容&#xff0c;阿里嘎多~ 一、RecyclerView的历史与发展 既然讲到了RV&#xff0c;那…

Android开发—RecyclerView使用

1.RecyclerView是什么 RecyclerView 在Android中用于创建列表。 官网的解释为&#xff1a; RecyclerView 可以让您轻松高效地显示大量数据。您提供数据并定义每个列表项的外观&#xff0c;而 RecyclerView 库会根据需要动态创建元素。 当RecyclerView的列表项滚出屏幕的时候&a…

Android RecyclerView使用简述

RecyclerView使用简述 前言正文一、创建项目二、RecyclerView基本使用① item布局和适配器② 显示数据③ 添加Item点击事件④ 添加Item子控件点击事件⑤ 添加长按事件⑥ 多个子控件点击事件 三、RecyclerView ViewBinding使用① 适配器② 显示数据③ 添加控件点击和长按 四、R…

es6新特性总结及使用说明

目录 简介 新特性说明 let语法 const语法 解构赋值 模板字符串 对象简写 对象操作--深拷贝 箭头函数 小结 简介 1. ECMAScript 6.0是 JavaScript 语言的下一代标准&#xff0c; 2015 年 6 月发布。 ES6 设计目标是达到 JavaScript 语言可以用来编写复杂的大型程序&a…

ES6有哪些新特性

ES6有哪些新特性(1)变量声明:由var变为let和const; (2)模板字符串:使用反引号;在模板字符串里面支持换行,并可以在里面使用${}来包裹一个变量或表达式; (3)解构:有数组解构和对象解构;可以快速获取数组和对象的值; (4) 展开运算符:在ES6中用…来表示展开运算符,它可以将数组…

ES6 新特性知识点总结

文章目录 ES6let及const解构赋值模板字符串Symbol类型Set和Map数据结构箭头函数类 ES6 ES 的全称是 ECMAScript , 它是由 ECMA 国际标准化组织,制定的一项脚本语言的标准化规范。 ES6 实际上是一个泛指&#xff0c;泛指 ES2015 及后续的版本。 每一次标准的诞生都意味着语言的…

ES6 新特性

1 、ES6 新特性 现在使用主流的前端框架中&#xff0c;如ReactJS、Vue.js、angularjs等&#xff0c;都会使用到ES6的新特性&#xff0c;作为一名高级工程师而言&#xff0c;ES6也就成为了必修课&#xff0c;所以本套课程先以ES6的新特性开始。 1.1、了解ES6 ES6&#xff0c;…

ES6新特性总结-面试必会

文章目录 一、let和const二、Symbol三、模板字符串3.1 什么是模板字符串3.2 字符串新方法 四、解构表达式4.1 数组解构4.2 对象解构 五、Set()、map()数据结构5.1 map()是什么及写法&#xff1f;5.1.1 map()是什么及写法&#xff1f;5.1.2 map()下的内置方法&#xff1a; 5.2 S…

JavaScript ES6新特性

JavaScript ES6带来了新的语法和特性&#xff0c;使得代码更加的现代和可读。它包括许多重要功能&#xff0c;如箭头函数、模板字符串、解构赋值等等。 const 和 let const 是 ES6 中用于声明变量的新关键字。const 比 var 强大。一旦使用&#xff0c;变量就不能重新分配。换…

ES6必须知道的六大新特性

ES6 ES6新特性-let&const 使用const表示常量&#xff08;声明之后不允许改变&#xff0c;一旦声明必须初始化&#xff0c;否则会报错&#xff09; //ES6 常量 不能修改const b2;b3;//Uncaught TypeError: Assignment to constant variable.console.log(b);使用var声明的…

ES6中有哪些新特性?

ES6中的新特性(一) ECMAScript6.0&#xff08;以下简称 ES6&#xff09;是 JavaScript 语言的下一代标准&#xff0c;已经在 2015 年 6 月正式发布了。它的目标&#xff0c;是使得 JavaScript 语言可以用来编写复杂的大型应用程序&#xff0c;成为企业级开发语言。 我们来看看…

面试题!es6新特性

es6新特性 ECMAScript 6(ES6) 目前基本成为业界标准&#xff0c;它的普及速度比 ES5 要快很多&#xff0c;主要原因是现代浏览器对 ES6的支持相当迅速&#xff0c;尤其是 Chrome 和 Firefox 浏览器&#xff0c;已经支持 ES6 中绝大多数的特性。 以下是一些常用到的es6新特性&…

es6的8条新特性总结

es6的8条新特性总结 认识es61.块级作用域变量&#xff08;let和const&#xff09;2.箭头函数3.模板字符串4.解构赋值5.默认参数6. 扩展运算符7. 类和继承8.Promise 认识es6 ES6&#xff08;ECMAScript 2015&#xff09;是JavaScript的新版本&#xff0c;引入了许多新特性和语法…