这段时间学习了ViewDragHelper
的使用,觉得挺牛逼的,使用起来也特别的方便。它可以方便的让我们处理触摸事件,是否分发,是否处理,一句话,使用它你可以忽略touch过程中的一些细节了!!
先看看ViewDragHelper
的创建吧!
ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() {}
通过一个create
的静态方法就可以获取到ViewDragHelper的一个实体。
这里需要传入一个Callback
;
接下来重点说说这个Callback
;它里面有很多的方法。。
搂一眼之后还是先来看看ViewDragHelper
的几个重要的方法。
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
return mViewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
mViewDragHelper.processTouchEvent(event);
return true;
//这里一定要记得返回true;
}
通过这两个方法的设定,那么我们的触摸事件就移交给ViewDragHelper
了,让它帮我处理是否要中断传播和处理触摸相关的事件。
获取到填充的布局:
@Override
protected void onFinishInflate() {
super.onFinishInflate();
//该布局中应该只有一个子布局,所有的其他布局填充到这个子布局中。
mContentView = getChildAt(0);
}
在onLayout()
的方法中得到view的宽度!!
@Override
protected void onLayout(boolean changed, int left, int top, int right, int bottom) {
super.onLayout(changed, left, top, right, bottom);
mContentWidth = mContentView.getWidth();
}
接下来看看Callback
的相关代码:
@Override
public boolean tryCaptureView(View child, int pointerId) {
return child == mContentView;//只有mContentView可以移动
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
mMoveLeft = left;
if (mCallBack != null) {
mCallBack.onPositionChanged(left, top, dx, dy);
}
if (isClose && (left == mContentWidth)) {
if (mCallBack != null) {
mCallBack.onFinish();
}
activity.finish();
}
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if (mMoveLeft >= (mContentWidth / 2)) {
//滑动超过屏幕的一半,那么就可以判断为true了!
isClose = true;
mViewDragHelper.settleCapturedViewAt(mContentWidth, releasedChild.getTop());
} else {
mViewDragHelper.settleCapturedViewAt(0, releasedChild.getTop());
}
invalidate();
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
return left;
}
@Override
public int getViewHorizontalDragRange(View child) {
//一定要重写这个方法,返回>0的值,不然当子View可以消耗触摸事件时就会无法移动。
return mContentWidth;
}
tryCaptureView()
的方法就是返回是否可以操作。
onViewPositionChanged()
就是位置发生变化时的相关回调。
onViewReleased()
这个就是当我们抬起手,释放的操作时。我们的相关判断其实就是在这个方法中完成的。如果移动的距离大于等于屏幕宽度的一半,那么在释放的时候我们就finish当前的Activity
clampViewPositionHorizontal()
返回建议的left就好!
getViewHorizontalDragRange()
如果我们滑动的控件可以消费触摸事件,那么为了可以成功的移动它,我们必须得重写这个方法,返回值>0就好!
最后复写一下
@Override
public void computeScroll() {
super.computeScroll();
if (mViewDragHelper.continueSettling(true)) {
invalidate();
}
}
到这里就完了哇??哈哈,还没有呢!因为你会发现这样你弄的的确可以滑动了,但是看不到下面的Activity啊!!这是什么鬼??最后还得给Activity设置为透明的背景。
配置这两个属性,基本上就大功告成了!!
nono..是不是Activity划出去之后还有屏幕一闪一闪的情况?那可能是因为Activity默认的动画效果。
所以在上面finish()
是应该再设置一下(这两句话的位置不能反了!):
this.finish();
this.overridePendingTransition(0, 0);//取消Activity的动画。//取消Activity的动画。
最后的最后,如果你想让Activity的开启动画变成是从左到右的,那么也设置一下就好:
对应的就是:
activity_in
activity_out
之前的代码使用的话,会出现Activity左右都能滑动。
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
//这样的话,页面就只能向右滑动了!
return Math.min(mContentWidth, Math.max(left, 0));
}
如果需要实现边界触摸才有效果的话:需要做如下修改:
1.实现边界滑动的回调,在里面处理对应的view!
@Override
public void onEdgeDragStarted(int edgeFlags, int pointerId) {
super.onEdgeDragStarted(edgeFlags, pointerId);
//在里面处理我们需要实现边界滑动有效的view
mViewDragHelper.captureChildView(mContentView, pointerId);
}
2.设置边界滑动可用:
mViewDragHelper.setEdgeTrackingEnabled(ViewDragHelper.EDGE_LEFT);
这里当然是左边有效啦!
3.最后需要将之前的tryCaptureView()
的方法中的mContentView
的相关逻辑注释掉!
Demo下载
as直接导入module!
GitHub