Android侧滑删除另一种实现,SwipeListView补充
时间:2022-04-27
本文章向大家介绍Android侧滑删除另一种实现,SwipeListView补充,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
前不久在在做聊天删除功能的时候使用SwipeListView进行侧滑删除有一点小问题,因为SwipeListView嵌套在Fragment内的时候,会报一个转换错误,原因是SwipeListView是基于ListView实现的SwipeListView。 针对这个问题,首先想到的就是自定义View。首先看一下实现的效果。
自定义侧滑实现
实现的思路很简单,通过对onTouchEvent方法进行重写,判断滑动的距离来实现删除按钮的显示与隐藏。核心代码如下:
package com.shihui.butler.butler.msg.view;
import android.content.Context;
import android.content.res.TypedArray;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.widget.AdapterView;
import android.widget.ListView;
import android.widget.Scroller;
import com.shihui.butler.R;
public class SwipeListView extends ListView {
public static int MODE_FORBID = 0;
public static int MODE_RIGHT = 1;
private int mode = MODE_FORBID;
private int rightLength = 0;
private int slidePosition;
private int downY;
private int downX;
private View itemView;
private Scroller scroller;
private int mTouchSlop;
private boolean canMove = false;
private boolean isSlided = false;
public SwipeListView(Context context) {
this(context, null);
}
public SwipeListView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SlideMode);
mode = a.getInt(R.styleable.SlideMode_mode, 0);
}
public SwipeListView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
TypedArray a = context.obtainStyledAttributes(attrs,
R.styleable.SlideMode);
mode = a.getInt(R.styleable.SlideMode_mode, 0);
scroller = new Scroller(context);
mTouchSlop = ViewConfiguration.get(getContext()).getScaledTouchSlop();
}
@Override
public boolean onTouchEvent(MotionEvent ev) {
final int action = ev.getAction();
int lastX = (int) ev.getX();
switch (action) {
case MotionEvent.ACTION_DOWN:
System.out.println("touch-->" + "down");
if (this.mode == MODE_FORBID) {
return super.onTouchEvent(ev);
}
if (isSlided) {
scrollBack();
return false;
}
if (!scroller.isFinished()) {
return false;
}
downX = (int) ev.getX();
downY = (int) ev.getY();
slidePosition = pointToPosition(downX, downY);
if (slidePosition == AdapterView.INVALID_POSITION) {
return super.onTouchEvent(ev);
}
itemView = getChildAt(slidePosition - getFirstVisiblePosition());
if (this.mode == MODE_RIGHT) {
this.rightLength = -itemView.getPaddingRight();
}
break;
case MotionEvent.ACTION_MOVE:
System.out.println("touch-->" + "move");
if (!canMove
&& slidePosition != AdapterView.INVALID_POSITION
&& (Math.abs(ev.getX() - downX) > mTouchSlop && Math.abs(ev
.getY() - downY) < mTouchSlop)) {
int offsetX = downX - lastX;
if (offsetX > 0 && this.mode == MODE_RIGHT) {
canMove = true;
} else {
canMove = false;
}
MotionEvent cancelEvent = MotionEvent.obtain(ev);
cancelEvent
.setAction(MotionEvent.ACTION_CANCEL
| (ev.getActionIndex() << MotionEvent.ACTION_POINTER_INDEX_SHIFT));
onTouchEvent(cancelEvent);
}
if (canMove) {
requestDisallowInterceptTouchEvent(true);
int deltaX = downX - lastX;
if (deltaX > 0 && this.mode == MODE_RIGHT) {
itemView.scrollTo(deltaX, 0);
} else {
itemView.scrollTo(0, 0);
}
return true;
}
case MotionEvent.ACTION_UP:
System.out.println("touch-->" + "up");
if (canMove) {
canMove = false;
scrollByDistanceX();
}
break;
}
return super.onTouchEvent(ev);
}
private void scrollByDistanceX() {
if (this.mode == MODE_FORBID) {
return;
}
if (itemView.getScrollX() > 0 && this.mode == MODE_RIGHT) {
if (itemView.getScrollX() >= rightLength / 2) {
scrollLeft();
} else {
scrollBack();
}
} else {
scrollBack();
}
}
private void scrollLeft() {
isSlided = true;
final int delta = (rightLength - itemView.getScrollX());
scroller.startScroll(itemView.getScrollX(), 0, delta, 0,
Math.abs(delta));
postInvalidate(); // 刷新itemView
}
private void scrollBack() {
isSlided = false;
scroller.startScroll(itemView.getScrollX(), 0, -itemView.getScrollX(),
0, Math.abs(itemView.getScrollX()));
// 刷新itemView
postInvalidate();
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
itemView.scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
public void slideBack() {
this.scrollBack();
}
}
然后我们在界面上引入上面的SwipeListView。
<SwipeListView
android:id="@+id/msg_listView"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:animationCache="false"
android:divider="#E4E4E4"
android:dividerHeight="0.5px"
android:scrollbars="none"
android:scrollingCache="false"
app:mode="right"/>
在Adapter的子布局中,通过对SwipeListView滑动监听即可。 下面是Adapter的子布局方面,相关代码:
<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal"
android:background="@color/white"
android:paddingRight="-100dp"
>
//...省略部分代码
android:background="@android:color/holo_red_light"
android:gravity="center"
android:text="删除"
android:textColor="@android:color/white"
android:textSize="18sp" />
</LinearLayout>
为了实现点击删除按钮删除,我们需要在Adapter中给按钮绑定点击事件,并通过接口回传给页面进行刷新。 adapter代码
private void initItemClick(ViewHolder viewHolder, final int position) {
viewHolder.itemDel.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View view) {
if (mRemoveListener != null)
mRemoveListener.onRemoveItem(position);
}
});
}
//声明接口监听
public void setRemoveListener(OnRemoveListener removeListener) {
this.mRemoveListener = removeListener;
}
public interface OnRemoveListener {
void onRemoveItem(int position);
}
然后我们在Fragment中直接调用即可。
controller.getAdapter().setRemoveListener(new MsgAdapter.OnRemoveListener() {
@Override
public void onRemoveItem(int position) {
//删除聊天逻辑
}
});
- 一条简单的sql语句运行15天的原因分析(r5笔记第17天)
- 巧用flashback database实现灵活的数据回滚(r5笔记第16天)
- Spring Cache For Redis.
- css重写checkbox样式
- 通过shell脚本同时监控多个数据库负载(r5笔记第14天)
- Java 定时器 Timer 的使用.
- 通过shell脚本来统计段大小(r5笔记第14天)
- Linux下配置MySQL主从复制(r5笔记第13天)
- Final 关键字
- ArrayList 和 LinkedList的执行效率比较
- 关于consistent gets(r5笔记第12天)
- wait/notify 实现多线程交叉备份
- 01.SVN介绍与安装
- 由sqlplus中的一个小细节所做的折腾(r5笔记第11天)
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Docker 入门到实战教程(十一)部署Vue+SpringBoot 前后端分离项目
- Docker 入门到实战教程(十二)ELK+Filebeat搭建日志分析系统
- Docker 入门到实战教程(十三)Docker Compose
- 解决IDEA2020.1版本的lombok插件问题
- 工具系列 | 视频监控RTSP转HLS解决方案
- Redis系列 |(一)六种基本数据结构
- 工具系列 | Jenkins 构建伟大,无所不能
- 工具系列 | H5自定义视频播放器实现
- 前端系列 |原生JS和jQuery循环遍历函数
- 工具系列 | H5如何实现人脸识别
- 形式化分析工具(六):HLPSL Tutorial(Example3)
- CODING DevOps + Nginx-ingress 实现自动化灰度发布
- TF入门04-TF实现Word2Vec
- TF入门03-实现线性回归&逻辑回归
- TF入门02-TensorFlow Ops