Android高仿QQ6.0侧滑删除实例代码

时间:2021-12-07 07:05:48

推荐阅读:

先给大家分享一下,侧滑删除,布局也就是前面一个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/*nlei
*/
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);
//第一步 初始化viewdraghelper
mdraghelper = viewdraghelper.create(this, mcallback);
}
viewdraghelper.callback mcallback = new viewdraghelper.callback() {
@override
public 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
*/
@override
public boolean onintercepttouchevent(motionevent ev) {
//交给viewdraghelper判断是否去拦截事件
return mdraghelper.shouldintercepttouchevent(ev);
}
@override
public boolean ontouchevent(motionevent event) {
try {
mdraghelper.processtouchevent(event);
} catch (exception e) {
e.printstacktrace();
}
//返回true,这里表示去拦截事件
return true;
}

然后我们去重写一下viewdraghelper里面的clampviewpositionhorizontal方法:

?
1
2
3
4
@override
public int clampviewpositionhorizontal(view child, int left, int dx) {
return left;
}

好了这个时候,就已经可以实现滑动了,我们先来看下结果:

Android高仿QQ6.0侧滑删除实例代码

这里我们可以看到,已经可以滑动了,好了接下来的就是要处理滑动事件,去放置到正确的地方(call me 和删除刚开始不能见,还有只能左滑显示,右滑隐藏)。
好了,我们先获取两个view吧:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
/**
* 当xml填充完毕的时候
*/
@override
protected 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
*/
@override
protected 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
*/
@override
protected 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) {
//摆放前view
rect frontrect = computefrontviewrect(isopen);
mfrontview.layout(frontrect.left, frontrect.top, frontrect.right, frontrect.bottom);
//摆放后view
rect backrect = computebackviewrect(frontrect);
mbackview.layout(backrect.left,backrect.top,backrect.right,backrect.bottom);
//前置前view
bringchildtofront(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
*/
@override
public 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();
}

好了这个时候我们来看下效果:

Android高仿QQ6.0侧滑删除实例代码

是不是发现了问题,就是我的前view想要的结果是不能右滑的(只允许左滑和返回),那么接下来就实现这个想要的结果吧。以下的代码是在clampviewpositionhorizontal()方法里面:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//在这里处理放置的逻辑拖拽的前view
if (child == mfrontview) {
if (left > 0) {
return 0;
} else if (left < -mrange) {
return -mrange;
}
}//拖拽的后view
else if (child == mbackview) {
if (left > mwidth) {
return mwidth;
} else if (left < mwidth - mrange) {
return mwidth - mrange;
}
}

看下效果图:

Android高仿QQ6.0侧滑删除实例代码

好了,这个时候已经基本实现了,接下来实现以下滑动的距离和速度【判断是否打开和关闭:

?
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
*/
@override
public 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);
}
}
/**
* 持续动画
*/
@override
public void computescroll() {
super.computescroll();
//这个是固定的
if (mdraghelper.continuesettling(true)) {
viewcompat.postinvalidateonanimation(this);
}
}

我们看下最终的效果吧:

Android高仿QQ6.0侧滑删除实例代码

好了,在这里我们加上一些回调,以方便外部使用的时候可以回调:

?
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侧滑删除实例代码

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