一个滑动选中RecyclerView中Item的布局SlidingCheckLayout,手指滑过Item时多项选中。
SlidingCheckLayout是一个滑动选中RecyclerView中Item的布局,手指滑过Item时多项选中。
作者:竹尘居士
github:https://github.com/homgwu/SlidingCheckLayout
示例

特性
SlidingCheckLayout继承自FrameLayout,使用时把RecyclerView放在SlidingCheckLayout里层。
左右滑动时手指滑到某项即回调该项的Position,上下滑动时根据position,回调开始和结束的position。
长按进入滑选模式。
实现方式
在dispatchTouchEvent中检测长按和处理滑动的位置:
@Override
public boolean dispatchTouchEvent(MotionEvent event) {if (!isSlidingEnable() || !isEnabled()) {return super.dispatchTouchEvent(event);
}
if (!isCanIntercept()) {return super.dispatchTouchEvent(event);
}
final int action = event.getActionMasked();
switch (action) {case MotionEvent.ACTION_DOWN:
// Log.i(TAG, "dispatchTouchEvent ACTION_DOWN mStartingCheck:" + mStartingCheck);
mInitDownY = mLastY = event.getY();
mInitDownX = mLastX = event.getX();
checkForLongClick(0, mInitDownX, mInitDownY);
break;
case MotionEvent.ACTION_UP:
case MotionEvent.ACTION_CANCEL:
// Log.i(TAG, "dispatchTouchEvent ACTION_CANCEL||ACTION_UP mStartingCheck:" + mStartingCheck);
removeLongPressCallback();
mLastPosition = RecyclerView.NO_POSITION;
mIncrease = 0;
if (mStartingCheck) {mStartingCheck = false;
return true;
}
break;
case MotionEvent.ACTION_MOVE:
// Log.i(TAG, "dispatchTouchEvent ACTION_MOVE mStartingCheck:" + mStartingCheck);
float y = event.getY();
float x = event.getX();
final float yInitDiff = y - mInitDownY;
final float xInitDiff = x - mInitDownX;
mLastY = y;
mLastX = x;
if (!mStartingCheck && (Math.abs(yInitDiff) > mTouchSlop || Math.abs(xInitDiff) > mTouchSlop)) {removeLongPressCallback();
}
if (mStartingCheck) {checkSlidingPosition(x, y);
return true;
}
break;
}
boolean result = super.dispatchTouchEvent(event);
// Log.i(TAG, "dispatchTouchEvent super.dispatchTouchEvent result:" + result);
return result;
}
为何要在dispatchTouchEvent中处理而不在onInterceptTouchEvent和onTouchEvent中处理呢,因为如果是一些复杂的界面,SlidingCheckLayout的某上层还有可以滑动的布局如RecyclerView,ViewPager,他们可能会在Down或Move你返回false,里层RecyclerView也返回false时截断事件(而你又不能直接都返回True,在没进入滑选模式时要保证里层的RecyclerView还可以响应点击等事件),那么SlidingCheckLayout会收不到后续的事件,而dispatchTouchEvent方法可以在SlidingCheckLayout不截断事件的情况下每次被调用到(询问是否要截断或分发到里层)。
为何要在ACTION_UP时返回true,因为如果不在up时返回true那么这个up事件可能会被里层的RecyclerView响应成点击事件而多次处理点击的这个item。
长按处理:
检查长按和移除(长按的代码是从View长按源码中copy出来改改的),
private void checkForLongClick(int delayOffset, float x, float y) {if (mPendingCheckForLongPress == null) {mPendingCheckForLongPress = new CheckForLongPress();
}
mPendingCheckForLongPress.setAnchor(x, y);
mPendingCheckForLongPress.rememberPressedState();
mHandler.postDelayed(mPendingCheckForLongPress,
sLongPressTime - delayOffset);
}
private void removeLongPressCallback() {if (mPendingCheckForLongPress != null) {mHandler.removeCallbacks(mPendingCheckForLongPress);
}
}
进入长按:
private final class CheckForLongPress implements Runnable {private float mX;
private float mY;
private boolean mOriginalPressedState;
@Override
public void run() {if ((mOriginalPressedState == isPressed()) && (mLastPosition = checkDownPosition(mX, mY)) != RecyclerView.NO_POSITION) {if (mOnSlidingPositionListener != null) {mOnSlidingPositionListener.onSlidingPosition(mLastPosition);
}
requestDisallowInterceptTouchEvent(true);
mStartingCheck = true;
}
}
public void setAnchor(float x, float y) {mX = x;
mY = y;
}
public void rememberPressedState() {mOriginalPressedState = isPressed();
}
}
检查滑过的是哪个item,并回调position
private void checkSlidingPosition(float x, float y) {View childViewUnder = mTargetRv.findChildViewUnder(x, y);
if (mOnSlidingPositionListener == null || childViewUnder == null) return;
int currentPosition = mTargetRv.getChildAdapterPosition(childViewUnder);
// Log.w(TAG, "checkSlidingPosition currentPosition:" + currentPosition + ",mLastPosition:" + mLastPosition);
if (currentPosition == mLastPosition || currentPosition == RecyclerView.NO_POSITION) return;
if (mLastPosition != RecyclerView.NO_POSITION && Math.abs(currentPosition - mLastPosition) > 1) {if (mLastPosition > currentPosition) {mOnSlidingPositionListener.onSlidingRangePosition(currentPosition, mIncrease > 0 ? mLastPosition : mLastPosition - 1);
} else {mOnSlidingPositionListener.onSlidingRangePosition(mIncrease < 0 ? mLastPosition : mLastPosition + 1, currentPosition);
}
} else {if ((mIncrease > 0 && mLastPosition > currentPosition) || (mIncrease < 0 && currentPosition > mLastPosition)) {mOnSlidingPositionListener.onSlidingPosition(mLastPosition);
}
mOnSlidingPositionListener.onSlidingPosition(currentPosition);
}
mIncrease = currentPosition > mLastPosition ? 1 : -1;
mLastPosition = currentPosition;
}
通过RecyclerView的findChildViewUnder方法用坐标找到对应的子View,再getChildAdapterPosition就可以得到子View的位置了。
使用方法
布局:
<?xml version="1.0" encoding="utf-8"?>
<com.homg.scl.SlidingCheckLayout
android:id="@+id/scl"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/reminder_tv">
<android.support.v7.widget.RecyclerView
android:id="@+id/rv"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</com.homg.scl.SlidingCheckLayout>
设置Listener:
mSlidingCheckLayout.setOnSlidingPositionListener(this);
@Override
public void onSlidingPosition(int position) {MainEntity entity = mMainRvAdapter.getEntityByPosition(position);
entity.setSelect(!entity.isSelect());
mMainRvAdapter.notifyItemChanged(position);
}
@Override
public void onSlidingRangePosition(int startPosition, int endPosition) {for (int i = startPosition; i <= endPosition; i++) {MainEntity entity = mMainRvAdapter.getEntityByPosition(i);
entity.setSelect(!entity.isSelect());
}
mMainRvAdapter.notifyItemRangeChanged(startPosition, endPosition - startPosition + 1);
}
一个滑动选中RecyclerView中Item的布局SlidingCheckLayout,手指滑过Item时多项选中。的更多相关文章
- 每次选中数组中的N条数据, 如果让每条数据被选中的次数做到平均??
经常有这样的需求, 有一组数据, 每次展示其中的1条或N条,希望每条数据展示量可以做到平均. 一开始想依次展示每条数据并做记录,整组数据全展示一遍之后清除记录, 然后一直循环下去. 实现的过程中又觉得 ...
- Android解决RecyclerView中的item显示不全方案
最近的项目中实现订单确定页面.需要使用ScrollView嵌套RecyclerView,当RecyclerView中的item数量比较多时,就会出现item只显示一部分数据,并没有将用户勾选的商品数量 ...
- RecyclerView中item无法充满的问题
首先致谢:https://blog.csdn.net/yuanlvmao/article/details/51694211 咱们不是代码的生产者,只是代码的搬运工. 今天写了一个RecyclerVie ...
- WPF中的常用布局 栈的实现 一个关于素数的神奇性质 C# defualt关键字默认值用法 接口通俗理解 C# Json序列化和反序列化 ASP.NET CORE系列【五】webapi整理以及RESTful风格化
WPF中的常用布局 一 写在开头1.1 写在开头微软是一家伟大的公司.评价一门技术的好坏得看具体的需求,没有哪门技术是面面俱到地好,应该抛弃对微软和微软的技术的偏见. 1.2 本文内容本文主要内容 ...
- RecyclerView中装饰者模式应用
近段时间一直在加班,在赶一个项目,现在项目接近尾声,那么需要对过去一段时间工作内容进行复盘,总结下比较好的解决方案,积累一些经验,我认为的学习方式,是「理论-实践-总结-分享」,这一种很好的沉淀方式. ...
- 在RecyclerView中集成QQ汽泡一
上次已经实现了QQ汽泡的自定义View的效果[http://www.cnblogs.com/webor2006/p/7726174.html],接着再将它应用到列表当中,这样才算得上跟QQ的效果匹配, ...
- 【从零开始撸一个App】RecyclerView的使用
目标 前段时间打造了一款简单易用功能全面的图片上传组件,现在就来将上传的图片以图片集的形式展现到App上.出于用户体验考虑,加载新图片采用[无限]滚动模式,Android平台上我们优选Recycler ...
- 列举至少3种Support包中提供的布局或工具
android.support.v7.widget.CardView 继承自FrameLayout并实现了圆角和阴影效果,常用于ListView或RecyclerView中Item布局的根节点 示例代 ...
- 在RecyclerView中集成QQ汽泡二
上次已经将GooView集成到RecyclerView当中了[http://www.cnblogs.com/webor2006/p/7787511.html],但是目前还有很多问题,下面先来运行看一下 ...
随机推荐
- CSS属性:定位属性(图文详解)
本文最初发表于博客园,并在GitHub上持续更新前端的系列文章.欢迎在GitHub上关注我,一起入门和进阶前端. 以下是正文. CSS的定位属性有三种,分别是绝对定位.相对定位.固定定位. posit ...
- python基础之实现sql增删改查
# encoding:utf-8 # Author:"richie" # Date:2017/8/2 import re key_l = ['id', 'name', 'age', ...
- HTTP 首部字段详细介绍
本文是HTTP解析系列第二篇,如果对http协议不是很了解,可以选去看第一篇:带新手走进神秘的HTTP协议,本文主要是对Http的首部字段进行详细解析. HTTP 协议的请求和响应报文中必定包含 HT ...
- SPI通讯协议
一.SPI概述 SPI,是英语Serial Peripheral Interface的缩写,顾名思义就是串行外围设备接口.SPI,是一种高速的,全双工,同步的通信总线,并且在芯片的管脚上只占用四根线, ...
- Java与算法之(7) - 完全二叉树
树 下图是一"棵"树的样子.树这个名称起的很形象,整个数据结构由根.枝.叶组成,其中1为根节点,2.3是1的子节点,4.5.6.8.9.10这几个没有子节点的节点称为叶节点. 节点 ...
- set使用实例1+lower_bound(val)(个人模版)
set使用实例1+lower_bound(val): #include<stdio.h> #include<set> #include<iostream> #inc ...
- 我的第五个网页制作:pre、html转义、abbr标签的使用
<!doctype html> <html> <head> <meta charset="utf-8"> <title> ...
- hdu_3483A Very Simple Problem(C(m,n)+快速幂矩阵)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=3483 A Very Simple Problem Time Limit: 4000/2000 MS ( ...
- I Hate It(线段树点修改区间查询)
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1754 I Hate It Time Limit: 9000/3000 MS (Java/Others) ...
- c#版 K线控件(Stock)
K线起源于日本米市交易,它的基本用途就是为了寻找"买卖点".股市及期货市场中的K线图的画法包含四个数据,即开盘价.最高价.最低价.收盘价,所有的k线都是围绕这四个数据展开,反映大势 ...