RecyclerView系列 - RecyclerView的基本使用

2023-10-26

文章欢迎转载,转载请注明出处:文章首发于【Karen Chia の 程序人生】RecyclerView系列 - RecyclerView的基本使用

按照惯例,先上效果图

在这里插入图片描述
效果图不是我想要的效果,怎么办?

查看关于 RecyclerView 系列的其它文章,总有你想要的效果 ↓↓↓

KarenChia 的 RecyclerView 系列文章

RecyclerView系列 - RecyclerView的基本使用

RecyclerView系列 - 如何优雅的实现分割线

前言

RecyclerView 在本文发布之前,已经出来很久了,之前也有很多关于 RecyclerView 的优秀文章,那我为什么还要在这里写下本文呢,实不相瞒,我是 ListView 的忠实粉,之前很少使用到 RecyclerView,最近发现了不少关于 RecyclerView 的优秀框架,于是开始使用 RecyclerView,在使用第三方优秀框架的同时,也需要了解框架背后对组件进行的处理及封装,便于后期对项目维护。

为什么选择 RecyclerView?

相对于 ListView、GridView 这类滑动列表组件来说,RecyclerView 具有:

  • 使用更加灵活
    1 通过设置布局管理器,可轻松实现组件列表垂直滑动或水平滑动效果
    2 给列表的 item 项设置【增加或删除】动画
    3 当列表组件滑动到顶端或底部时,带有波纹效果,更显列表立体感
  • 代码高度解耦
    代码高幅度降低了耦合度,维护起来非常方便
  • 拓展方便
    1 轻松实现 ListView 及 Gridview 组件的相关列表效果,学会 RecyclerView,相当于学会了 ListView + Gridview
    2 难得一见的【瀑布流】列表滑动效果

RecyclerView 不是万能的,存在以下不足:

  • 不像 ListView那样,它没有分割线的设置方法
  • 没有实现 item 的相关点击事件

但是,重点来了:

也正是由于 RecyclerView 存在的这些缺点,我们不就可以根据自己的需求去定义嘛,怎么开心怎么玩!!!

下面开始进入我们今天的主题 ↓↓↓

1 添加依赖

在 module(一般都是在 app 下) 的 build.gradle 文件下添加组件依赖:

implementation 'androidx.recyclerview:recyclerview:1.0.0'

注意:由于使用的 Android Studio 版本不同,依赖语句也有所不同,我这里使用的 AS 版本是 V3.4.1

2 在布局文件中使用 RecyclerView

<?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:background="@color/app_bg"
    android:orientation="vertical">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/rvTest"
        android:layout_width="match_parent"
        android:layout_height="match_parent" />
</LinearLayout>

3 为 RecycleView 设置布局管理器 LinearLayoutManager

这里列表默认是垂直滑动的

rvTest.setLayoutManager(new LinearLayoutManager(this));

不要问我为什么,问就【看源码】,看 LinearLayoutManager 构造器源码:

    /**
     * Creates a vertical LinearLayoutManager
     *
     * @param context Current context, will be used to access resources.
     */
    public LinearLayoutManager(Context context) {
        this(context, RecyclerView.DEFAULT_ORIENTATION, false);
    }

关于 DEFAULT_ORIENTATION 的定义如下:

static final int DEFAULT_ORIENTATION = VERTICAL;

关于 VERTICAL 的定义如下:

public static final int VERTICAL = LinearLayout.VERTICAL;

源码中使用的属性还是线性布局 LinearLayout 的垂直属性

那么问题来了,我要让 RecyclerView 水平滑动怎么办?

3.1 设置 RecyclerView 列表水平滑动

        LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(this);
        mLinearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        rvTest.setLayoutManager(mLinearLayoutManager);

4 设置 item 增加和删除时的动画效果

rvTest.setItemAnimator(new DefaultItemAnimator());

这里设置的是 RecyclerView 默认的动画效果

5 设置适配器

        mRecyclerViewTestAdapter = new RecyclerViewTestAdapter(this, testData);
        rvTest.setAdapter(mRecyclerViewTestAdapter);

RecyclerView 的适配器继承至 RecyclerView.Adapter < VH extends ViewHolder >,泛型类型为ViewHolder。

RecyclerView 对 ViewHolder 进行了封装,使得我们使用起来更加的方便,自定义的 ViewHolder 只需继承 RecyclerView.ViewHolder 即可

package com.karenchia.andprimarylp.adapter;

import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.TextView;

import androidx.annotation.NonNull;
import androidx.recyclerview.widget.RecyclerView;

import com.karenchia.andprimarylp.R;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * RecyclerView 测试数据适配器
 * <p>
 * Created by KarenChia on 2019/9/4.
 */
public class RecyclerViewTestAdapter extends RecyclerView.Adapter<RecyclerViewTestAdapter.RecyclerViewTestViewHolder> {
    /**
     * 上下文对象
     */
    private Context mContext;
    /**
     * 测试数据
     */
    private List<String> testDataList;

    /**
     * 函数构造器
     *
     * @param mContext     上下文对象
     * @param testDataList 测试数据
     */
    public RecyclerViewTestAdapter(Context mContext, List<String> testDataList) {
        this.mContext = mContext;
        this.testDataList = testDataList;
    }

    /**
     * 加载 item 的布局文件
     */
    @NonNull
    @Override
    public RecyclerViewTestViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new RecyclerViewTestViewHolder(
                LayoutInflater.from(mContext).inflate(R.layout.item_recycler_view_test, parent, false));
    }

    /**
     * 将数据与 item 视图进行绑定
     */
    @Override
    public void onBindViewHolder(@NonNull RecyclerViewTestViewHolder holder, int position) {
        holder.tvData.setText(testDataList.get(position));
    }

    @Override
    public int getItemCount() {
        return testDataList == null ? 0 : testDataList.size();
    }

    /**
     * RecycleView 中 ViewHolder 的定义方式
     */
    public class RecyclerViewTestViewHolder extends RecyclerView.ViewHolder {

        @BindView(R.id.tvData)
        TextView tvData;

        public RecyclerViewTestViewHolder(@NonNull View itemView) {
            super(itemView);
            ButterKnife.bind(this, itemView);
        }
    }
}

列表 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"
    android:padding="10dp">

    <TextView
        android:id="@+id/tvData"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:textColor="@android:color/black" />
</LinearLayout>

至此,RecyclerView 的基本用法结束。

6 相关类的代码

这里贴一下相关类的代码实现

项目使用的是 MVP 模式,别问我为什么要使用 MVP 模式,问就请看这里:https://blog.csdn.net/ZhaiKun68/article/details/100033584#1_AndroidMVP_3

6.1 RecyclerViewDemoContract 类

package com.karenchia.andprimarylp.ui.contract;

import java.util.List;

/**
 * MVP 模式接口抽取
 * <p>
 * Created by KarenChia on 2019/9/4.
 */
public interface RecyclerViewDemoContract {

    interface Model {
        /**
         * 加载测试数据
         *
         * @return 测试数据
         */
        List<String> testData();
    }

    interface View {
        /**
         * 显示测试数据列表
         *
         * @param testData 测试数据
         */
        void showTestData(List<String> testData);
    }

    interface Presenter {
        /**
         * 获取测试数据
         */
        void getTestData();
    }
}

6.2 RecyclerViewDemoModel 类

package com.karenchia.andprimarylp.ui.model;

import com.karenchia.andprimarylp.ui.contract.RecyclerViewDemoContract;

import java.util.ArrayList;
import java.util.List;

/**
 * model 层数据逻辑处理
 * <p>
 * Created by KarenChia on 2019/9/4.
 */
public class RecyclerViewDemoModel implements RecyclerViewDemoContract.Model {

    /**
     * 加载测试数据
     *
     * @return 测试数据
     */
    @Override
    public List<String> testData() {
        List<String> testData = new ArrayList<>();
        for (int i = 0; i < 20; i++) {
            testData.add("我是 Karen Chia " + i);
        }
        return testData;
    }
}

6.3 RecyclerViewDemoActivity 类

package com.karenchia.andprimarylp.ui.activity.newfeature;

import android.content.Context;
import android.os.Bundle;

import androidx.annotation.Nullable;
import androidx.appcompat.app.AppCompatActivity;
import androidx.recyclerview.widget.DefaultItemAnimator;
import androidx.recyclerview.widget.LinearLayoutManager;
import androidx.recyclerview.widget.RecyclerView;

import com.karenchia.andprimarylp.R;
import com.karenchia.andprimarylp.adapter.RecyclerViewTestAdapter;
import com.karenchia.andprimarylp.ui.contract.RecyclerViewDemoContract;
import com.karenchia.andprimarylp.ui.presenter.RecyclerViewDemoPresenter;
import com.socks.library.KLog;

import java.util.List;

import butterknife.BindView;
import butterknife.ButterKnife;

/**
 * RecyclerView 演示类 view 层逻辑处理
 * <p>
 * Created by KarenChia on 2019/9/3.
 */
public class RecyclerViewDemoActivity extends AppCompatActivity implements RecyclerViewDemoContract.View {
    /**
     * view层与model层交互的桥梁
     */
    private RecyclerViewDemoContract.Presenter mPresenter;

    /**
     * RecyclerView 组件
     */
    @BindView(R.id.rvTest)
    RecyclerView rvTest;

    /**
     * RecyclerView 的数据适配器
     */
    private RecyclerViewTestAdapter mRecyclerViewTestAdapter;

    @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_recycler_view_demo);
        ButterKnife.bind(this);
        mPresenter = new RecyclerViewDemoPresenter(this);
        initData();
        initView();
    }

    private void initData() {
        mPresenter.getTestData();
    }

    /**
     * 组件初始化
     */
    private void initView() {
        //为 RecycleView 设置布局管理器
        rvTest.setLayoutManager(new LinearLayoutManager(this));
        //LinearLayoutManager mLinearLayoutManager = new LinearLayoutManager(this);
        //mLinearLayoutManager.setOrientation(LinearLayoutManager.HORIZONTAL);
        //rvTest.setLayoutManager(mLinearLayoutManager);
        //设置 item 增加和删除时的动画效果
        rvTest.setItemAnimator(new DefaultItemAnimator());
    }

    /**
     * 显示测试数据列表
     *
     * @param testData 测试数据
     */
    @Override
    public void showTestData(List<String> testData) {
        //设置适配器
        mRecyclerViewTestAdapter = new RecyclerViewTestAdapter(this, testData);
        rvTest.setAdapter(mRecyclerViewTestAdapter);
    }
}

6.4 RecyclerViewDemoPresenter 类

package com.karenchia.andprimarylp.ui.presenter;

import com.karenchia.andprimarylp.ui.contract.RecyclerViewDemoContract;
import com.karenchia.andprimarylp.ui.model.RecyclerViewDemoModel;

/**
 * model层 与 View层 通信的桥梁
 * <p>
 * Created by KarenChia on 2019/9/4.
 */
public class RecyclerViewDemoPresenter implements RecyclerViewDemoContract.Presenter {
    /**
     * model层数据逻辑处理
     */
    private RecyclerViewDemoContract.Model mModel;
    /**
     * view层交互逻辑处理
     */
    private RecyclerViewDemoContract.View mView;

    public RecyclerViewDemoPresenter(RecyclerViewDemoContract.View mView) {
        mModel = new RecyclerViewDemoModel();
        this.mView = mView;
    }

    /**
     * 获取测试数据
     */
    @Override
    public void getTestData() {
        mView.showTestData(mModel.testData());
    }
}
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

RecyclerView系列 - RecyclerView的基本使用 的相关文章

  • 安卓市场API

    有谁知道Android市场是否有一个API 可以自动提交新应用程序 而无需手动填写市场表格 不 抱歉 没有程序化的方式来提交市场列表 据推测 这是一种反垃圾邮件发送者措施
  • Flutter ListView 未更新

    我想在 Flutter 中创建一个 ListView 当新数据到达时它会更新 我正在使用 RefreshIndicator 来触发列表加载以进行测试 对于我的列表 我使用 ListBuilder 将对象映射到视图对象 据我了解 setSta
  • CustomWebViewRenderer DownloadManager 与 CopyBackForwardList 的问题

    我仍在学习 android 我正在使用它创建一个混合应用程序推荐 https stackoverflow com questions 58967929 xamarin webview webpage cant download files
  • “_Smi”不是“bool”类型的子类型 - Flutter MethodChannel

    收到这个奇怪的错误 似乎 MethodChannel 正在转换为 int 而不是 bool 06 07 00 16 26 589 3678 4993 E flutter ERROR topaz lib tonic logging dart
  • 如何将图片保存到文件中?

    我正在尝试使用标准意图来拍照 然后允许批准或重新拍摄 然后我想将图片保存到文件中 这是我正在使用的意图 Intent intent new Intent android provider MediaStore ACTION IMAGE CA
  • 使用react-native测量音频的响度

    我正在创建一个应用程序 Android 来使用本机反应录制手机中的语音 一项要求是实时测量声音的响度并基于它制作动画 我尝试使用react native audio库 但问题是响度监控仅在IOS中支持 我检查了世博会音频库 但找不到方法 有
  • 更换电池后广播接收器会导致某些手机上的应用程序崩溃

    每当手机插入电源时 我都会激活我的应用程序 这是我的清单
  • AlertDialog 关闭不起作用

    我有以下警报对话框 AlertDialog Builder dialogBuilder new AlertDialog Builder mContext dialogBuilder setTitle R string title dialo
  • 获取TextView的高度

    我有一些文字将被放入TextView 我这样做是使用setText 现在我需要找到文本在文本中占据的行数或高度TextView 我尝试使用getHeight 但它总是返回 0 无论如何 有没有办法获得文本中存在的文本的高度TextView
  • Android SIP 客户端 SipManager.open() 未打开

    我一直在使用 Android SDK 的本机 SIP 库编写 SIP 客户端 由于某种原因 我无法让我的帐户在服务器上注册 以下是测试场地 Linux Mint 17 XFCE 运行 Kamailio 服务器 启用 MySQL 和 TLS
  • 为什么某些手机会出现“此应用程序的配置不正确”错误?

    我已经在 android 6 中构建了我的应用程序 没有任何错误 但是当我在 android 4 4 2 中构建我的应用程序时 我收到此错误 This app has been built with an incorrect configu
  • 何时取消订阅

    我有一个关于如何取消订阅可观察的问题 我有两个代码 但我不确定哪一个更好 示例 1 gt 流结束后取消订阅订阅者 Subscriber
  • 将 EditText 聚焦在设备上运行的 PopupWindow 中时出现异常

    我正在为 Android 开发一个弹出窗口 它正在工作 我在上面添加了一个 EditText 和一个按钮 当在 ADV 上运行时 它可以正常工作 而在设备上运行时 当我专注于 EditText 时 这会抛出一个奇怪的异常 android v
  • 没有 ContentProvider 的 SyncAdapter

    我想为我想要与服务器同步的内容实现 SyncAdapter 看来要做到这一点 您需要为 SyncAdapter XML 属性文件中指定的权限注册一个 ContentProvider 由于我不希望手机的其余部分可以访问此内容 因此我没有实现自
  • Android:制作/显示 9patch 图像时的对齐错误

    九号补丁 截屏 布局 XML
  • 设置 JAVA_HOME 变量时出现问题

    所以我刚刚下载了 Android Studio 并尝试设置 JAVA HOME 变量以便我可以运行它 我使用的是 Windows 8 并按照我找到的所有说明进行操作 但无济于事 转到高级系统设置 gt 环境变量 然后使用包含我的 jre7
  • 如何隐藏或删除 Android HoneyComb 中的状态栏?

    如何隐藏或删除 Android HoneyComb 中的状态栏 每次运行应用程序时 我都会发现某些内容必须被状态栏覆盖 我尝试改变AndroidManifest xml 但没有任何改变 你不知道 它被认为是永久的屏幕装饰 就像电容式主页 菜
  • 在 Android Studio 中打开上次关闭的选项卡

    我是 Android Studio 的新手 想知道是否有任何快捷方式 选项可以重新打开上次关闭的选项卡 没有分配快捷方式 但您可以轻松分配新的快捷方式 Go to IDE settings Keymap Main menu Window E
  • 在另一个布局中以编程方式膨胀布局

    我的 Android 应用程序需要帮助 我需要在另一个布局中膨胀一个布局 但我不知道该怎么做 我的xml代码是这样的 item xml 我需要膨胀多个 xml 取决于可变数量
  • 如何将上下文从一个活动传递到另一个活动?

    我有一个主要活动 它调用另一个活动来显示一些数据 我有一个私有数据库帮助程序对象 我在整个主要活动代码中使用它 有没有办法以优雅的方式将我的主要活动的上下文传递给我的子活动 即 来自子类 类似getCallingActivityContex

随机推荐

  • 使用动软.net代码生成器生成数据库文档

    首先 进入动软 net代码生成器主界面 选择服务器 右击 选择 连接服务器 按照弹出的界面 操作 就可以将需要生成数据库文档的相关服务器添加进来 然后 选中服务器 选择工具栏中的 生成数据库文档 按钮 在弹出的 生成数据库文档 窗口中 依次
  • Blender一步一步用灰度图生成3D模型用于Gazebo/gzweb

    我们经常能在SDF格式文件中见到 dae stl模型文件 比如如下代码
  • 地址总线与数据总线

    CPU通过地址总线寻址 然后通过数据总线与外部设备互换信息 地址总线 地址总线的位数决定CPU寻址范围 若CPU的地址总线宽度是32位 那么CPU的寻址范围是4G 所以最多支持4G内存 数据总线 数据总线的位数决定CPU单次通信能交换的信息
  • C++编程题

    1 计算字符串最后一个单词的长度 单词以空格隔开 字符串长度小于5000 注 字符串末尾不以空格为结尾 贴代码 include
  • 虚拟机扩容

    文章目录 虚拟机扩容 扩容背景 软件版本 操作步骤 1 VM上修改磁盘信息 2 在系统中挂载磁盘 1 使用命令查看磁盘状态 2 通过命令查看到新磁盘的分区 3 然后对新加的磁盘进行分区操作 4 重启虚拟机 5 再次用以下命令查看到磁盘当前情
  • 专访XRuby贡献者郑晔:软件开发不是自娱自乐(上)

    郑晔 是一个热爱编程的程序员 网络ID dreamhead 也许有人会说 我还是一个超热爱编程的程序员呢 那么我想你一定不知道 郑晔是第一个加入到XRuby这个开源项目的 XRuby今天优异的成绩与郑晔有着不可分割的联系 在郑晔的blog中
  • tablesorter ajax,jquery tablesorter ajax表只排序一个方向

    我遇到了同样的问题 但设置不同 这个帖子中提到的答案没有解决我的问题 为我的方案添加解决方案 以防其他人遇到同样的问题 我的表体行是在页面加载时从 ajax调用动态创建的 并且一列被设置为默认sortList 以在加载数据后进行排序 根据提
  • 1~100带圈的数字_输入带圈字符的几种方法,你会几种?

    我们在编辑Word的时候 会需要输入带圈序号 今天零壹学长就给大家介绍几种输入带圈字符的方法 一起来看看吧 利用带圈字符 先输入数字 再选中数字 然后点击 开始 点击 字体 组中的 带圈字符 就可以了 利用符号功能 使用符号功能只能应用1
  • Cobalt Strike渗透神器详解

    Cobalt Strike 前言 简介 功能使用 下载与安装 基础使用 CS如何成功上线 所需环境 添加监听 生成后门木马 钓鱼链接 成功拿到shell CS如何联动MSF 所需环境 前提条件 MSF配置监听模块 CS新建监听器 成功交互
  • uniapp项目中使用第三方的包@escook/request-miniprogram来创建网络请求

    1 安装 npm install escook request miniprogram 2 在main js中导入 import App from App import Vue from vue 导入网络请求的包 import http f
  • 计算机原理--浮点数的加减法运算

    浮点数的加减法 对阶 尾数求和 尾数规格化 溢出判断 乘除 对阶 对阶的目的是使得两个浮点数阶码一致 使得尾数可以进行运算 浮点数尾数运算简单 浮点数位数实际小数位与阶码有关 阶码按小阶看齐大阶的原则 尾数求和 使用补码进行运算 减法运算转
  • web端导航菜单系列

    导航菜单属于导航中最常规的一种导航模式 它有2个显而易见的用途 帮助我们找到想要的任何东西和告诉我们现在身在何处 帮助用户在不同页面之间跳转找到目标功能 导航作为网站或者平台的骨架 是产品设计中不容忽视的一环 结合自身对于导航设计的理解 并
  • Unknown initial character set index ‘255‘ received from server.Initial client character set can be..

    在MySQL8 0向DM8 达梦数据库 迁移数据时 使用默认驱动报错 报错信息 Unknown initial character set index 255 received from server Initial client char
  • 如何在Java中实现线程同步?

    在Java中 线程同步是一种机制 用于确保多个线程按照特定的顺序访问共享资源 从而避免数据竞争和不一致的结果 以下是几种常用的线程同步方法 synchronized关键字 synchronized关键字用于修饰方法或代码块 确保同一时间只有
  • 处理Element 日期选择器el-date-picker 限制时间跨度一年

    处理Element 日期选择器el date picker 限制时间跨度一年 主要通过pickerOptions里的disabledDate来控制禁止选中的日期 实现思想就是 当选中第一个开始日期时 拿到该时间戳计算时间范围 然后控制接下来
  • 【100天精通Python】Day57:Python 数据分析_Pandas数据描述性统计,分组聚合,数据透视表和相关性分析

    目录 1 描述性统计 Descriptive Statistics 2 数据分组和聚合 3 数据透视表 4 相关性分析 1 描述性统计 Descriptive Statistics 描述性统计是一种用于汇总和理解数据集的方法 它提供了关于数
  • 编译android版本llvm编译器

    编译android版本llvm编译器 准备 编译环境 ubuntu 20 04 2 编译器版本 ndk 24 0 8215888 llvm版本 15 0 7 最近需要在android上编译C 项目 需要在android上使用arm版本的编译
  • fieldset 元素添加 display: flex不生效的问题

    问题 最近写项目时候 对 fieldset 元素 添加 display flex 但是没有达到预期中的效果 在网上 stackoverflow 上都提到了这个 bug 然后查看了官方文档 解决方案 在 fieldset 中添加 一个 div
  • Python 读取 Excel 详解(openyxl)

    文章目录 1 概述 1 1 Python 安装第三方库 2 常用对象 2 1 工作簿 workbook 2 1 1 新建 2 1 2 打开 2 1 3 常用属性和方法 2 1 3 常用操作 2 2 工作表 sheet 2 2 1 新增 2
  • RecyclerView系列 - RecyclerView的基本使用

    文章欢迎转载 转载请注明出处 文章首发于 Karen Chia 程序人生 RecyclerView系列 RecyclerView的基本使用 按照惯例 先上效果图 效果图不是我想要的效果 怎么办 查看关于 RecyclerView 系列的其它