欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  移动技术

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

程序员文章站 2024-02-22 15:25:55
推荐阅读: 先给大家分享一下,侧滑删除,布局也就是前面一个item,然后有两个隐藏的按钮(textview也可以),然后我们可以向左侧滑动,然后显示出来,然后对delet...

推荐阅读:

先给大家分享一下,侧滑删除,布局也就是前面一个item,然后有两个隐藏的按钮(textview也可以),然后我们可以向左侧滑动,然后显示出来,然后对delete(删除键)实现监听,就可以了哈。好了那就来看看代码怎么实现的吧。

首先和之前一样

自定义view,初始化viewdraghelper:

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方法,默认是不拦截的:

/**
* 传递触摸事件
*
* @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方法:

@override
public int clampviewpositionhorizontal(view child, int left, int dx) {
return left;
}

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

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

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

/**
* 当xml填充完毕的时候
*/
@override
protected void onfinishinflate() {
super.onfinishinflate();
/**
* 后view
*/
mbackview = getchildat(0);
/**
* 前view
*/
mfrontview = getchildat(1);
}

获取想要的宽和高:

/**
* 在这里获取宽和高
*
* @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的位置:

/**
* 摆放位置
* @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里面的方法):

/**
* 当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()方法里面:

//在这里处理放置的逻辑拖拽的前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侧滑删除实例代码 

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

/**
* 拖拽的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);
}

好了,接下来实现以下平滑的关闭和打开:

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

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

/**
* 默认状态是关闭
*/
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()方法中调用)

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()方法:

/**
* 更新状态
*
* @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侧滑删除实例代码对大家有所帮助。