android ViewDragHelper实现侧滑删除

先上效果图:

首先看一下关于ViewDragHelper的简介:

ViewDragHelper is a utility class for writing custom ViewGroups. It offers a number of useful operations and state tracking for allowing a user to drag and reposition views within their parent ViewGroup.

简单说,ViewDragHelper是一个用于实现自定义ViewGroup的工具类。它提供了很多各种用户拖动视图的状态操作供用户使用。

首先创建SlideView继承ViewGroup,此处为节省操作,子view设置为一个LinearLayout和一个TextView。在onFinishInflate做初始化:

@Override
protected void onFinishInflate() {
super.onFinishInflate();
ll_content = (LinearLayout) getChildAt(0);
tv_delete = (TextView) getChildAt(1);
mCallBack = ViewDragHelper.create(this, new MyDragViewCallBack());
}
然后重写onMeasure进行子view的测量操作:
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
//先测量子view
for (int i = 0; i < getChildCount(); i++) {
measureChild(getChildAt(i), widthMeasureSpec, heightMeasureSpec);
}
//测量容器
int widthSpec = measureWidth(widthMeasureSpec);
int heightSpec = measureHeight(heightMeasureSpec);
setMeasuredDimension(widthSpec, heightSpec);
}
private int measureWidth(int measureSpec) {
int spec = 0;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.EXACTLY:
spec = size;
break;
case MeasureSpec.AT_MOST:
//获取长度
for (int i = 0; i < getChildCount(); i++) {
spec += getChildAt(i).getMeasuredWidth();
}
break;
case MeasureSpec.UNSPECIFIED:
break;
default:
break;
}
return spec;
}

private int measureHeight(int measureSpec) {
int spec = 0;
int mode = MeasureSpec.getMode(measureSpec);
int size = MeasureSpec.getSize(measureSpec);
switch (mode) {
case MeasureSpec.EXACTLY:
spec = size;
break;
case MeasureSpec.AT_MOST:
//取子view高度最大值
for (int i = 0; i < getChildCount(); i++) {
spec = Math.max(spec, getChildAt(i).getMeasuredHeight());
}
spec = Math.min(spec, size);
break;
case MeasureSpec.UNSPECIFIED:
break;
default:
break;
}
return spec;
}
然后重写onLayout来摆放布局:@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
mContentWidth = ll_content.getMeasuredWidth();
mContentHeight = ll_content.getMeasuredHeight();
ll_content.layout(0, 0, mContentWidth, mContentHeight);
mDeleteWidth = tv_delete.getMeasuredWidth();
mDeleteHeight = tv_delete.getMeasuredHeight();
tv_delete.layout(mContentWidth, 0, mContentWidth + mDeleteWidth, mDeleteHeight);
}
以上的操作都相对简单,接下来,便是最主要的工具类ViewDragHelper了,我们首先创建类MyDragViewCallBack继承ViewDragHelper.Callback方法,
并重写当前view的touch方法:
@Override
public boolean onTouchEvent(MotionEvent event) {
mCallBack.processTouchEvent(event);
return true;
}
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
mCallBack.shouldInterceptTouchEvent(ev);
return true;
}

然后重写
MyDragViewCallBack的一个方法,tryCaptureView(View child,int pointerId),这个方法需要我们将我们想要“动”的子view传过去,这里我们要让2个子view都能做拖拽操作,即return child == ll_content || child == tv_delete;接着再实现clampViewPositionHorizontal*(View child,int left,int dx)方法,该方法会在我们touch做移动操作的时候被调用。child即我们移动的子view,left为父容器左变与子view的距离,dx为增量值。
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
if (child == ll_content) {
if (left > 0) {//右拖越界
return 0;
} else if (left < -mDeleteWidth) {//左拖越界
return -mDeleteWidth;
}
}
if (child == tv_delete) { // 解决删除部分左右拖动的越界问题
if (left < mContentWidth - mDeleteWidth) {
return mContentWidth - mDeleteWidth;
} else if (left > mContentWidth) {
return mContentWidth;
}
}
return left;
}
到这里,我们的子view都可以拖拽了,接下来,我们要做的是,在拖动其中一个子view的时候,让另一个子view的位置跟着移动,这里用到的是onViewPositionChanged(View changedView, int left, int top, int dx, int dy),参数分别
表示改变了位置的view、view的left、view的top、x方向的增量和y方向的增量:
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
if (changedView == ll_content) { // 如果移动的是mContent
int tempDeleteLeft = mContentWidth + left;
int tempDeleteRight = mContentWidth + left + mDeleteWidth;
tv_delete.layout(tempDeleteLeft, 0, tempDeleteRight, mDeleteHeight);
} else { // touch的是mDelete
int tempContentLeft = left - mContentWidth;
ll_content.layout(tempContentLeft, 0, left, mContentHeight);
}
invalidate();
}
到这一步,我们的子view就能正常的拖动了,但是,当我们手抬起时,我们还需要根据当前拖动的距离来决定是否显示deleteView,这里用到
public void onViewReleased(View releasedChild, float xvel, float yvel);
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
Log.e(TAG,"------->onViewReleased");
//该方法在touch的up中调用
int left = ll_content.getLeft();
if (-left > mDeleteWidth / 2) {//左拖动时,拖动距离超过删除块的一半
mCallBack.smoothSlideViewTo(ll_content, -mDeleteWidth, 0);
mCallBack.smoothSlideViewTo(tv_delete, mContentWidth - mDeleteWidth, 0);
} else {
mCallBack.smoothSlideViewTo(ll_content, 0, 0);
mCallBack.smoothSlideViewTo(tv_delete, mContentWidth, 0);
}
invalidate();
super.onViewReleased(releasedChild, xvel, yvel);
}
到这一步就完成了

 

 




posted @ 2017-10-24 14:46  Epilogue  阅读(1071)  评论(0编辑  收藏  举报