logo头像
Snippet 博客主题

Android侧滑删除另一种实现,SwipeListView补充

本文于558天之前发表,文中内容可能已经过时。

前不久在在做聊天删除功能的时候使用SwipeListView进行侧滑删除有一点小问题,因为SwipeListView嵌套在Fragment内的时候,会报一个转换错误,原因是SwipeListView是基于ListView实现的SwipeListView
针对这个问题,首先想到的就是自定义View。首先看一下实现的效果。
这里写图片描述

自定义侧滑实现

实现的思路很简单,通过对onTouchEvent方法进行重写,判断滑动的距离来实现删除按钮的显示与隐藏。核心代码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
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。

1
2
3
4
5
6
7
8
9
10
<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的子布局方面,相关代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
<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代码

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
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中直接调用即可。

1
2
3
4
5
6
7
controller.getAdapter().setRemoveListener(new MsgAdapter.OnRemoveListener() {
@Override
public void onRemoveItem(int position) {
//删除聊天逻辑
}
});

就写到这里吧,有任何问题欢迎留言。

支付宝打赏 微信打赏

如果文章对你有帮助,欢迎点击上方按钮打赏作者

上一篇