先给大家分享一下,侧滑删除,布局也就是前面一个item,然后有两个隐藏的按钮(TextView也可以),然后我们可以向左侧滑动,然后显示出来,然后对delete(删除键)实现监听,就可以了哈。好了那就来看看代码怎么实现的吧
正文
Android高仿QQ6.0侧滑删除实例代码
推荐阅读:
先给大家分享一下,侧滑删除,布局也就是前面一个item,然后有两个隐藏的按钮(textview也可以),然后我们可以向左侧滑动,然后显示出来,然后对delete(删除键)实现监听,就可以了哈。好了那就来看看代码怎么实现的吧。
首先和之前一样
自定义view,初始化viewdraghelper:
|
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
|
package com.example.removesidepull;import android.content.context;import android.support.v4.widget.viewdraghelper;import android.util.attributeset;import android.view.motionevent;import android.view.view;import android.widget.framelayout;/*** created by 若兰 on 2016/2/2.* 一个懂得了编程乐趣的小白,希望自己* 能够在这个道路上走的很远,也希望自己学习到的* 知识可以帮助更多的人,分享就是学习的一种乐趣* qq:1069584784* csdn:http://blog.csdn.net/wuyinlei*/public class swipelayout extends framelayout {private viewdraghelper mdraghelper;public swipelayout(context context) {this(context, null);}public swipelayout(context context, attributeset attrs) {this(context, attrs, 0);}public swipelayout(context context, attributeset attrs, int defstyleattr) {super(context, attrs, defstyleattr);//第一步 初始化viewdraghelpermdraghelper = viewdraghelper.create(this, mcallback);}viewdraghelper.callback mcallback = new viewdraghelper.callback() {@overridepublic boolean trycaptureview(view child, int pointerid) {//返回true return true;}};} |
然后我们就要去处理拦截事件也就是重写一些onintercepttouchevent和ontouchevent方法,默认是不拦截的:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
|
/*** 传递触摸事件** @param ev* @return*/@overridepublic boolean onintercepttouchevent(motionevent ev) {//交给viewdraghelper判断是否去拦截事件return mdraghelper.shouldintercepttouchevent(ev);}@overridepublic boolean ontouchevent(motionevent event) {try {mdraghelper.processtouchevent(event);} catch (exception e) {e.printstacktrace();}//返回true,这里表示去拦截事件return true;} |
然后我们去重写一下viewdraghelper里面的clampviewpositionhorizontal方法:
|
1
2
3
4
|
@overridepublic int clampviewpositionhorizontal(view child, int left, int dx) {return left;} |
好了这个时候,就已经可以实现滑动了,我们先来看下结果:

这里我们可以看到,已经可以滑动了,好了接下来的就是要处理滑动事件,去放置到正确的地方(call me 和删除刚开始不能见,还有只能左滑显示,右滑隐藏)。
好了,我们先获取两个view吧:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
/*** 当xml填充完毕的时候*/@overrideprotected void onfinishinflate() {super.onfinishinflate();/*** 后view*/mbackview = getchildat(0);/*** 前view*/mfrontview = getchildat(1);} |
获取想要的宽和高:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
|
/*** 在这里获取宽和高** @param w* @param h* @param oldw* @param oldh*/@overrideprotected void onsizechanged(int w, int h, int oldw, int oldh) {super.onsizechanged(w, h, oldw, oldh);/*** 高度*/mheight = mfrontview.getmeasuredheight();/*** 宽度*/mwidth = mfrontview.getmeasuredwidth();/*** 移动距离*/mrange = mbackview.getmeasuredwidth();} |
摆放这两个view的位置:
|
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
|
/*** 摆放位置* @param changed* @param left* @param top* @param right* @param bottom*/@overrideprotected void onlayout(boolean changed, int left, int top, int right, int bottom) {super.onlayout(changed, left, top, right, bottom);layoutcontent(false);}private void layoutcontent(boolean isopen) {//摆放前viewrect frontrect = computefrontviewrect(isopen);mfrontview.layout(frontrect.left, frontrect.top, frontrect.right, frontrect.bottom);//摆放后viewrect backrect = computebackviewrect(frontrect);mbackview.layout(backrect.left,backrect.top,backrect.right,backrect.bottom);//前置前viewbringchildtofront(mfrontview);}/*** 我们可以把前view相当于一个矩形** @param frontrect* @return*/private rect computebackviewrect(rect frontrect) {int left = frontrect.right;return new rect(left, 0, left + mrange, 0 + mheight);}private rect computefrontviewrect(boolean isopen) {int left = 0;if (isopen) {left = -mrange;}return new rect(left, 0, left + mwidth, 0 + mheight);} |
当然这个实现,只是可以拖拽了前view,因为我们没有把改变的dx传递下去,好了来实现拖拽前view的时候,后view也跟着出来(viewdraghelper里面的方法):
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
/*** 当view位置改变的时候* @param changedview 改变的view* @param left* @param top* @param dx x轴偏移量* @param dy*/@overridepublic void onviewpositionchanged(view changedview, int left, int top, int dx, int dy) {super.onviewpositionchanged(changedview, left, top, dx, dy);//传递事件,如果是拖拽的前view,if (changedview == mfrontview){//offset this view's horizontal location by the specified amount of pixels.//也就是说我的我的前view左滑了dx,那么我的后view也是左滑dx,右滑同理mbackview.offsetleftandright(dx);} else if (changedview == mbackview){//拖拽的是后view的话,前view的处理方式一样mfrontview.offsetleftandright(dx);}//兼容老版本invalidate();} |
好了这个时候我们来看下效果:

是不是发现了问题,就是我的前view想要的结果是不能右滑的(只允许左滑和返回),那么接下来就实现这个想要的结果吧。以下的代码是在clampviewpositionhorizontal()方法里面:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
|
//在这里处理放置的逻辑拖拽的前viewif (child == mfrontview) {if (left > 0) {return 0;} else if (left < -mrange) {return -mrange;}}//拖拽的后viewelse if (child == mbackview) {if (left > mwidth) {return mwidth;} else if (left < mwidth - mrange) {return mwidth - mrange;}} |
看下效果图:

好了,这个时候已经基本实现了,接下来实现以下滑动的距离和速度【判断是否打开和关闭:
|
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
|
/*** 拖拽的view释放的时候** @param releasedchild* @param xvel* @param yvel*/@overridepublic void onviewreleased(view releasedchild, float xvel, float yvel) {if (xvel == 0 && mfrontview.getleft() < -mrange / 2.0f) {open();} else if (xvel < 0) {open();} else {close();}}/*** 关闭*/public void close() {utils.showtoast(getcontext(), "close");layoutcontent(false);}//打开public void open() {//utils.showtoast(getcontext(), "open");layoutcontent(true);} |
好了,接下来实现以下平滑的关闭和打开:
|
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
|
public void close() {close(true);}/*** 关闭** @param issmooth*/public void close(boolean issmooth) {int finalleft = 0;if (issmooth) {//开始动画 如果返回true表示没有完成动画if (mdraghelper.smoothslideviewto(mfrontview, finalleft, 0)) {viewcompat.postinvalidateonanimation(this);}} else {layoutcontent(false);}}public void open() {open(true);}/*** 打开** @param issmooth*/public void open(boolean issmooth) {int finalleft = -mrange;if (issmooth) {//开始动画if (mdraghelper.smoothslideviewto(mfrontview, finalleft, 0)) {viewcompat.postinvalidateonanimation(this);}} else {layoutcontent(true);}}/*** 持续动画 */@overridepublic void computescroll() {super.computescroll();//这个是固定的if (mdraghelper.continuesettling(true)) {viewcompat.postinvalidateonanimation(this);}} |
我们看下最终的效果吧:

好了,在这里我们加上一些回调,以方便外部使用的时候可以回调:
|
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
|
/*** 默认状态是关闭*/private status status = status.close;private onswipelayoutlistener swipelayoutlistener;public status getstatus() {return status;}public void setstatus(status status) {this.status = status;}public onswipelayoutlistener getswipelayoutlistener() {return swipelayoutlistener;}public void setswipelayoutlistener(onswipelayoutlistener swipelayoutlistener) {this.swipelayoutlistener = swipelayoutlistener;}/*** 定义三种状态*/public enum status {close, open, draging}/*** 定义回调接口 这个在我们*/public interface onswipelayoutlistener {/*** 关闭** @param mswipelayout*/void onclose(swipelayout mswipelayout);/*** 打开** @param mswipelayout*/void onopen(swipelayout mswipelayout);/*** 绘制** @param mswipelayout*/void ondraging(swipelayout mswipelayout);/*** 要去关闭*/void onstartclose(swipelayout mswipelayout);/*** 要去开启*/void onstartopen(swipelayout mswipelayout);} |
dispatchswipeevent()方法(在onviewpositionchanged()方法中调用)
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
protected void dispatchswipeevent() {//判断是否为空if (swipelayoutlistener != null) {swipelayoutlistener.ondraging(this);}// 记录上一次的状态status prestatus = status;// 更新当前状态status = updatestatus();if (prestatus != status && swipelayoutlistener != null) {if (status == status.close) {swipelayoutlistener.onclose(this);} else if (status == status.open) {swipelayoutlistener.onopen(this);} else if (status == status.draging) {if (prestatus == status.close) {swipelayoutlistener.onstartopen(this);} else if (prestatus == status.open) {swipelayoutlistener.onstartclose(this);}}}} |
updatestatus()方法:
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/*** 更新状态** @return*/private status updatestatus() {//得到前view的左边位置int left = mfrontview.getleft();if (left == 0) {//如果位置是0,就是关闭状态return status.close;} else if (left == -mrange) {//如果左侧边距是后view的宽度的负值,状态为开return status.open;}//其他状态就是拖拽return status.draging;} |

好了,事件基本上已经实现完毕了,这个侧拉删除的我会更新至我的项目中,同时希望android高仿qq6.0侧滑删除实例代码对大家有所帮助。

发表评论