【Android】实现Recyclerview的Item可以左右侧滑动的效果

news2025/9/18 8:49:09
项目需要

使用Recyclerview进行列表的数据加载的时候,需要对这个Item进行左右滑动进行操作的功能,
比如这样
在这里插入图片描述
在这里插入图片描述

需求实现

上面图来源于
https://github.com/anzaizai/EasySwipeMenuLayout
这是一个可以用来进行列表左滑、右滑的项目,可以集成到自己的项目中

compile 'com.github.anzaizai:EasySwipeMenuLayout:1.1.4'

推荐搭配Brvah框架使用

api 'com.github.CymChad:BaseRecyclerViewAdapterHelper:2.9.49'

使用方式业非常简单
例如

        <com.guanaj.easyswipemenulibrary.EasySwipeMenuLayout
                  android:layout_width="match_parent"
                  android:layout_height="wrap_content"
                  app:contentView="@+id/content"
                  app:leftMenuView="@+id/left"
                  app:rightMenuView="@+id/right">
                      <LinearLayout
                          android:id="@+id/left"
                          android:layout_width="100dp"
                          android:layout_height="wrap_content"
                          android:background="@android:color/holo_blue_dark"
                          android:orientation="horizontal"
                          android:padding="20dp">
                              <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="分享" />
                        </LinearLayout>
                      <LinearLayout
                          android:id="@+id/content"
                          android:layout_width="match_parent"
                          android:layout_height="wrap_content"
                          android:background="#cccccc"
                          android:orientation="vertical"
                          android:padding="20dp">
                              <TextView
                                    android:layout_width="wrap_content"
                                    android:layout_height="wrap_content"
                                    android:text="内容区域" />
                      </LinearLayout>
                      <LinearLayout
                          android:id="@+id/right"
                          android:layout_width="wrap_content"
                          android:layout_height="wrap_content"
                          android:background="@android:color/holo_red_light"
                          android:orientation="horizontal">
                          <TextView
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:background="@android:color/holo_blue_bright"
                              android:padding="20dp"
                              android:text="删除" />
                          <TextView
                              android:id="@+id/right_menu_2"
                              android:layout_width="wrap_content"
                              android:layout_height="wrap_content"
                              android:background="@android:color/holo_orange_dark"
                              android:padding="20dp"
                              android:text="收藏" />
                      </LinearLayout>
                </com.guanaj.easyswipemenulibrary.EasySwipeMenuLayout>
    public class MyAdapter extends BaseQuickAdapter<String, BaseViewHolder> {


        public MyAdapter(@LayoutRes int layoutResId, @Nullable List<String> data) {
            super(layoutResId, data);
        }

        @Override
        protected void convert(final BaseViewHolder helper, String item) {

            helper.getView(R.id.right_menu_2).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this, "收藏", Toast.LENGTH_SHORT).show();
                    EasySwipeMenuLayout easySwipeMenuLayout = helper.getView(R.id.es);

                    easySwipeMenuLayout.resetStatus();
                }
            });
            helper.getView(R.id.content).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this, "setOnClickListener", Toast.LENGTH_SHORT).show();

                }
            });

        }

    }

按照这个Demo上面讲的,这样基本上就可以了,但是有问题需要注意:

使用这个框架之后,虽然实现了左右滑动显示不用的按钮的效果,但是这个整个Item的点击事件是被拦截了,这就导致

//        rvAdapter.setOnItemClickListener(new BaseQuickAdapter.OnItemClickListener() {
//            @Override
//            public void onItemClick(BaseQuickAdapter adapter, View view, int position) {
//
//            }
//        });

这个方法是失效的,要是对这个没有什么需求的话这个可以不用管,但是我们要是对某一个Item进行操作的时候,怎么获得这个position呢?
需要这样做

 helper.getView(R.id.content).setOnClickListener(new View.OnClickListener() {
                @Override
                public void onClick(View v) {
                    Toast.makeText(MainActivity.this, "setOnClickListener", Toast.LENGTH_SHORT).show();
//在这个方法里面,因为此方法在【convert】里面,所以可以在这里获取到我们需要的position
 int pos = helper.getAdapterPosition();
 //这样就可以操作了
                }
            });

但是有时候我们的页面要复用,需要这个点击事件的时候,这个时候该怎么办呢,这个时候就要修改这个代码了,修改的地方不多

首先我们需要在github上面把这个项目下载下来,把里面的代码放到我们项目中,代码很少,我们在这个【EasySwipeMenuLayout】里面
加入一个字段

 private boolean isNeedClick = false; //是否需要(非滑动之后的)点击事件
    public boolean isNeedClick() {
        return isNeedClick;
    }

    public void setNeedClick(boolean needClick) {
        isNeedClick = needClick;
    }

然后在里面的【dispatchTouchEvent】和【onInterceptTouchEvent】方法里面加入

    if (isNeedClick()) {
            return super.dispatchTouchEvent(ev);
        }

    if (isNeedClick()) {
            return super.onInterceptTouchEvent(event);
        }

全部代码如下

 @Override
    public boolean dispatchTouchEvent(MotionEvent ev) {
        if (isNeedClick()) {
            return super.dispatchTouchEvent(ev);
        }
        switch (ev.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                //   System.out.println(">>>>dispatchTouchEvent() ACTION_DOWN");
                isSwipeing = false;
                if (mLastP == null) {
                    mLastP = new PointF();
                }
                mLastP.set(ev.getRawX(), ev.getRawY());
                if (mFirstP == null) {
                    mFirstP = new PointF();
                }
                mFirstP.set(ev.getRawX(), ev.getRawY());
                if (mViewCache != null) {
                    if (mViewCache != this) {
                        mViewCache.handlerSwipeMenu(State.CLOSE);
                    }
                    // Log.i(TAG, ">>>有菜单被打开");
                    getParent().requestDisallowInterceptTouchEvent(true);
                }

                break;
            }
            case MotionEvent.ACTION_MOVE: {
                //   System.out.println(">>>>dispatchTouchEvent() ACTION_MOVE getScrollX:" + getScrollX());
                float distanceX = mLastP.x - ev.getRawX();
                float distanceY = mLastP.y - ev.getRawY();
                if (Math.abs(distanceY) > mScaledTouchSlop && Math.abs(distanceY) > Math.abs(distanceX)) {
                    break;
                }
//                if (Math.abs(distanceX) <= mScaledTouchSlop){
//                    break;
//                }
                // Log.i(TAG, ">>>>>distanceX:" + distanceX);

                scrollBy((int) (distanceX), 0);//滑动使用scrollBy
                //越界修正
                if (getScrollX() < 0) {
                    if (!mCanRightSwipe || mLeftView == null) {
                        scrollTo(0, 0);
                    } else {//左滑
                        if (getScrollX() < mLeftView.getLeft()) {

                            scrollTo(mLeftView.getLeft(), 0);
                        }

                    }
                } else if (getScrollX() > 0) {
                    if (!mCanLeftSwipe || mRightView == null) {
                        scrollTo(0, 0);
                    } else {
                        if (getScrollX() > mRightView.getRight() - mContentView.getRight() - mContentViewLp.rightMargin) {
                            scrollTo(mRightView.getRight() - mContentView.getRight() - mContentViewLp.rightMargin, 0);
                        }
                    }
                }
                //当处于水平滑动时,禁止父类拦截
                if (Math.abs(distanceX) > mScaledTouchSlop
//                        || Math.abs(getScrollX()) > mScaledTouchSlop
                ) {
                    //  Log.i(TAG, ">>>>当处于水平滑动时,禁止父类拦截 true");
                    getParent().requestDisallowInterceptTouchEvent(true);
                }
                mLastP.set(ev.getRawX(), ev.getRawY());


                break;
            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                //     System.out.println(">>>>dispatchTouchEvent() ACTION_CANCEL OR ACTION_UP");

                finalyDistanceX = mFirstP.x - ev.getRawX();
                if (Math.abs(finalyDistanceX) > mScaledTouchSlop) {
                    //  System.out.println(">>>>P");

                    isSwipeing = true;
                }
                result = isShouldOpen(getScrollX());
                handlerSwipeMenu(result);


                break;
            }
            default: {
                break;
            }
        }

        return super.dispatchTouchEvent(ev);

    }
@Override
    public boolean onInterceptTouchEvent(MotionEvent event) {
        if (isNeedClick()) {
            return super.onInterceptTouchEvent(event);
        }
        //  Log.d(TAG, "<<<<dispatchTouchEvent() called with: " + "ev = [" + event + "]");
        switch (event.getAction()) {
            case MotionEvent.ACTION_DOWN: {
                break;
            }
            case MotionEvent.ACTION_MOVE: {
                //滑动时拦截点击时间
                if (Math.abs(finalyDistanceX) > mScaledTouchSlop) {
                    // 当手指拖动值大于mScaledTouchSlop值时,认为应该进行滚动,拦截子控件的事件
                    //   Log.i(TAG, "<<<onInterceptTouchEvent true");
                    return true;
                }
//                if (Math.abs(finalyDistanceX) > mScaledTouchSlop || Math.abs(getScrollX()) > mScaledTouchSlop) {
//                    Log.d(TAG, "onInterceptTouchEvent: 2");
//                    return true;
//                }
                break;

            }
            case MotionEvent.ACTION_UP:
            case MotionEvent.ACTION_CANCEL: {
                //滑动后不触发contentView的点击事件
                if (isSwipeing) {
                    isSwipeing = false;
                    finalyDistanceX = 0;
                    return true;
                }
            }

        }
        return super.onInterceptTouchEvent(event);
    }

然后我们在Adapter里面

            if (helper.getView(R.id.easy_swipe_ly) instanceof EasySwipeMenuLayout) {
                        ((EasySwipeMenuLayout) helper.getView(R.id.easy_swipe_ly)).setNeedClick(true);
                    }

这样就可以了,但是需要注意的是,如果这样设置了,我们的左右滑动就失效了,但是点击事件生效了。需要根据具体需求自行设置。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1822503.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

盒马鲜生礼品卡如何使用?

盒马鲜生的礼品卡除了在门店用以外&#xff0c;还有什么用处啊 毕竟家附近的盒马距离都太远了&#xff0c;好多卡最后都闲置下来了&#xff0c;而且以前都不知道盒马卡还会过期&#xff0c;浪费了好多 还好最近发现了 盒马鲜生礼品卡现在也能在收卡云上兑现了&#xff0c;而且…

01_点亮LED

这节课的标题是点亮 LED&#xff0c;虽然任务很简单&#xff0c;但是需要大家了解的单片机基础知识的内容却很多&#xff0c;特别是对于初学者&#xff0c;刚开始要在头脑中建立一个单片机的概念&#xff0c;课程最后通过点亮一个 LED 小灯来增加初学者对单片机的兴趣和自信。 …

GLS-3004K 端子排静态双位置继电器 AC115V 导轨安装约瑟 JOSEF

系列型号&#xff1a; GLS-3002K端子排静态双位置继电器&#xff1b; GLS-3204K端子排静态双位置继电器&#xff1b; GLS-3220端子排静态双位置继电器; GLS-3004K端子排静态双位置继电器; 一、用途 GLS系列端子排静态双位置继电器用于交直流操作的各种保护与自动控制系统中,作为…

Dubbo-使用zookeeper作为注册中心时节点的概述

本文内容很容易理解&#xff0c;会阐述当dubbo使用zookeeper作为注册中心时候&#xff0c;zookeeper节点是什么样子的 本文的代码使用的dubbo版本是2.7.x&#xff0c;几年前的版本了&#xff0c;但是不影响探究 首先我们创建一个简单的maven项目&#xff0c;然后写出一段dubb…

分布式事务的八种方案解析(1)

针对不同的分布式场景业界常见的解决方案有2PC、TCC、可靠消息最终一致性、最大努力通知等方案&#xff0c;以下总结8 种常见的解决方案&#xff0c;帮助大家在实际的分布式系统中更好地运用事务。 1.2PC 二阶段提交协议&#xff08;Two-phase commit protocol&#xff09;&…

Tensorflow入门实战 T04-猴痘识别

本篇文章主要&#xff1a;tensorflow 运行环境&#xff1a;本地cpu 运行epoch&#xff1a;50 1、tensorflow官网 tensorflow的官网教程。初学者的 TensorFlow 2.0 教程 | TensorFlow Core 官网上有图像分类的相关详细描述还有代码示例。 2、完整代码展示 from tensorflo…

进阶篇04——视图

简介及基本语法 视图的检查选项 可以通过视图进行数据的增删改查操作&#xff0c;但由于视图是一张虚拟表&#xff0c;所以操作的实际上是视图的基表&#xff0c;即创建视图时select语句操作的表 cascaded 自己还测试了一下这种情况&#xff1a;当V1和V2都没有加检查选项&…

华三HCL模拟器安装及华三防火墙配置

0、前言 最近跟模拟器杠上了&#xff0c;主要是需要运行防火墙&#xff0c;目前已经成功模拟出华为、山石防火墙&#xff0c;而且模拟出来的设备能与物理网络环境进行互联。现在我又盯上华三防火墙了。 首先下载模拟器&#xff1a; 下载地址&#xff1a;H3C网络设备模拟器官方免…

EasyExcel文件导出,出现有文件但没有数据的问题

一开始由于JDK版本过高&#xff0c;我用的17&#xff0c;一直excel没有数据&#xff0c;表头也没有&#xff0c;后来摸索了好久&#xff0c;找了资料也没有&#xff0c;后来改了代码后报了一个错误&#xff08;com.alibaba.excel.exception.ExcelGenerateException: java.lang.…

进程状态及其转换

0号进程(idle):在linux系统启动的时候最先运行的进程就是0号进程&#xff0c;0号进程又叫空闲进程。如果系统上没有其他进程执行那么0号进程就执行。0号进程是1号进程和2号进程的父进程 1号进程(init):init进程是由0号进程创建得到的&#xff0c;它的主要工作是系统的初始化。…

Spring Security 与 JWT、OAuth 2.0 整合详解:构建安全可靠的认证与授权机制

Spring Security 与 OAuth 2.0 整合详解&#xff1a;构建安全可靠的认证与授权机制 将 JWT&#xff08;JSON Web Token&#xff09;与 OAuth 2.0 整合到 Spring Security 中可以为应用程序提供强大的认证和授权功能。以下是详细的整合步骤和代码示例。 1. 引入依赖 首先&am…

【开源项目】重庆智慧城市案例~实景三维数字孪生城市CIM/BIM

飞渡科技数字孪生重庆管理平台&#xff0c;以实景三维平台为支撑&#xff0c;以城市数据库对接为核心&#xff0c;利用数字孪生技术&#xff0c;结合云计算、物联网IOT等技术&#xff0c;对接城市规划、智能交通、和公共安全等系统。 利用平台强大的国产自研渲染引擎&#xff0…

怎么压缩视频大小

在数字时代&#xff0c;视频已成为我们日常生活和工作中不可或缺的一部分。然而&#xff0c;视频文件的大小也越来越大&#xff0c;这给存储和传输带来了不小的挑战。因此&#xff0c;学会如何有效地压缩视频文件&#xff0c;就显得尤为重要。本文将详细介绍一种常用的视频压缩…

vscode中模糊搜索和替换

文章目录 调出搜索&#xff08;快捷键&#xff09;使用正则&#xff08;快捷键&#xff09;替换&#xff08;快捷键&#xff09;案例假设给定文本如下目标1&#xff1a;查找所有函数名目标2&#xff1a;替换所有函数名为hello目标3&#xff1a;给url增加查询字符串参数 调出搜索…

Coursera耶鲁大学金融课程:Financial Markets 笔记Week 01

Financial Markets 本文是学习 https://www.coursera.org/learn/financial-markets-global这门课的学习笔记 这门课的老师是耶鲁大学的Robert Shiller https://en.wikipedia.org/wiki/Robert_J._Shiller Robert James Shiller (born March 29, 1946)[4] is an American econ…

如何用Xcode创建你的第一个项目?学起来

前言 上一期&#xff0c;咱们已经有安装XCode的教程了。有小伙伴说建议跳过&#xff0c;嗯。。。如果你对开发很熟悉&#xff0c;那可以。但如果不熟悉&#xff0c;建议还是按照教程一步步来哦&#xff01; 毕竟统一了开发工具&#xff0c;咱们后续讲的内容学习起来也会简单一…

U-Mail反垃圾邮件网关助力企业抵御垃圾邮件,守护邮箱安全

在数字化时代&#xff0c;电子邮件已成为企业沟通不可或缺的工具&#xff0c;它在促进信息流通和提高工作效率方面扮演着关键角色。然而&#xff0c;随着电子邮件使用的普及&#xff0c;垃圾邮件问题也日益凸显&#xff0c;特别是那些携带恶意软件或钓鱼链接的邮件&#xff0c;…

2024 年最新 Python 调用 OpenAi 详细教程实现问答、图像合成、图像理解、语音合成、语音识别(详细教程)

OpenAi 环境安装 首先确保您的计算机上已经安装了 Python。您可以从 Python 官方网站下载并安装最新版本 Python。安装时&#xff0c;请确保勾选 “Add Python to PATH” &#xff08;添加环境变量&#xff09;选项&#xff0c;以便在 cmd 命令行中直接使用 Python。 安装 Op…

如何将ai集成到项目中,方法二

上一篇文章&#xff1a;如何将ai集成到radsystems项目中&#xff0c;在项目中引入ai-CSDN博客 上一篇文章内容主要针对于未实现权限分离的项目&#xff0c;这篇文章主要来说一下权限分离的项目怎么做&#xff0c;以及注意的细节。 一、编写前端router.js 二、编写前端askai.vu…

qemu microvm 测试运行记录

[v3] Introduce the microvm machine type | Patchew 下载获取rootfs wget http://dl-cdn.alpinelinux.org/alpine/v3.10/releases/x86_64/alpine-minirootfs-3.10.2-x86_64.tar.gz qemu-img create -f raw alpine-rootfs-x86_64.raw 1G losetup /dev/loop0 alpine-rootfs-x86…