推荐阅读:
先给大家分享一下,侧滑删除,布局也就是前面一个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;
}
|
好了这个时候,就已经可以实现滑动了,我们先来看下结果:
这里我们可以看到,已经可以滑动了,好了接下来的就是要处理滑动事件,去放置到正确的地方(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();
}
|
好了这个时候我们来看下效果:
是不是发现了问题,就是我的前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;
}
}
|
看下效果图:
好了,这个时候已经基本实现了,接下来实现以下滑动的距离和速度【判断是否打开和关闭:
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 );
}
}
|
我们看下最终的效果吧:
好了,在这里我们加上一些回调,以方便外部使用的时候可以回调:
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侧滑删除实例代码对大家有所帮助。