最近想了解自定义view的知识,没想到在网上找到了一个仿QQ5.0的,就拿来学习学习。里面涉及到了一个类ViewDragHelper,所以就要好好研究一下它。这个类是在google2013 I/O大会上推出的2个组件中slidingPaneLayout和DrawerLayout就使用到了这个类,那么这个类是干嘛用的呢?从字面意思上面看就是一个View拖拽的帮助类,那我们就来学一下怎么使用它吧。
任何类的使用必须要有它的对象,ViewDragHelper类有一个工厂方法用来创建类的实例,
viewDragHelper = ViewDragHelper.create(this, callback);
viewDragHelper = ViewDragHelper.create(this, 1.0f,callback);
从上面看到,create方法是有2种的,第二种的第二个 参数的意思就是拖拽的灵敏度的高度,1.0f表示是默认的。第一个参数是当前要跟ViewDragHelper链接的ViewGroup,第三个参数就是一个回调方法,我们在对view进行拖拽的时候的操作就是在这个callback里面进行的.当我们实例化了这个类后,就该考虑在哪里将我们的View的touch事件交给ViewdragHelper来实现,我们知道所有viewGroup的touch事件都是从dispatchTouchEvent开始的,那么我们就应该在拦截方法onInterceptTouchEvent中将改事件拦截并在这里将touch事件交给ViewDragHelper同时在onTouchEvent让ViewDragHelper来处理这个事件,代码如下:
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final int action = MotionEventCompat.getActionMasked(ev);
if(action == MotionEvent.ACTION_CANCEL || action == MotionEvent.ACTION_UP){
viewDragHelper.cancel();
return false;
}
return viewDragHelper.shouldInterceptTouchEvent(ev);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
viewDragHelper.processTouchEvent(event);
return true;
}
至此我们完成了初始化工作,那么接下来我们来看一下上文提到过的callback接口中的方法
public int clampViewPositionHorizontal(View child, int left, int dx) {
if(mainView.getLeft()+dx < 0){
return 0;
}
return left;
}
这个方法的意思就是当你水平拖拽view的时候要回调的方法,返回的值就是你的view离屏幕左边的距离,那么我们可以想到垂直方向拖拽也是有其对应的方法,不过ViewDragHelper默认是水平拖拽,如果需要垂直拖拽的话,请提前设置拖拽方式。那么这个方法一般都会和一个方法一起出现
@Override
public int getViewHorizontalDragRange(View child) {
return width;
}
这个方法返回的值是水平滑动的范围,这个值一般在onMeasure中获取,将会在后面作为ViewGroup的位置更新的参数,假如有两个子View的时候我们需要在
@Override
public boolean tryCaptureView(View arg0, int arg1) {
return true;
}
这个方法总return true,此时你的2个View都是可以拖拽,如果return false ,那么都不能拖拽。如果你想让某一个可以拖拽,另一个不能拖拽的话,就请return arg0 == YourView。
这样下来,你的ViewGroup是可以拖拽的,但是如果你要动态的更新VIewGroup的位置或者什么的,必须实现另外的两个方法
@Override
public void onViewPositionChanged(View changedView, int left, int top,
int dx, int dy) {
int mainLeft = mainView.getLeft() + dx;
if(mainLeft<0){
mainLeft = 0;
}else if(mainLeft>width){
mainLeft = width;
}
if(changedView == leftView){
leftView.layout(0, 0, width, height);
mainView.layout(mainLeft, 0, mainLeft+width,height);
}
dispatchMove(mainLeft);
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
if(xvel>0){
open(true);
}else if(xvel < 0){
close(true);
}else if(releasedChild == leftView && mainView.getLeft() > width*2/3){
open(true);
}else if(releasedChild == mainView && mainView.getLeft() > width/3){
open(true);
}else{
close(true);
}
}
第一个方法表示ViewGroup的positionChanged的回调事件,该事件一直伴随这你的拖拽,你可以在这个方法中对ViewGroup的位置,大小什么进行更改,当你完成拖拽后,也就是释放时会调用第二个方法,这个方法一般会处理你手完成拖拽后的ViewGroup的处理。具体来说,onViewReleased是为了当完成拖拽时但是View不在应该在的位置的时候我们对View位置的一种改变,一般会在这个方法里面调用
smoothSlideViewTo(mainView,0, 0);
第一个参数是要移动的View,第二个参数是移动View到距离屏幕左侧的距离,第三个参数就是移动View到距离屏幕顶部的距离。这个方法的作用就是告诉ViewDragHelper,请将这个View移动到指定的位置,当调用这个方法后,ViewdragHelper会回调onViewPositionChanged方法来实现对View位置的自动更新。切记:在调用这个方法的时候记得调用
invalidate()方法,来实现重绘,有时候效果还是没有出来,是因为我们需要再另一个方法中做一些事情
<span style="white-space:pre"> </span>@Override
public void computeScroll() {
super.computeScroll();
if(viewDragHelper.continueSettling(true)){
ViewCompat.postInvalidateOnAnimation(this);
}
}
这个方法的写法貌似是固定的,含义我也不太理解,如果有大神理解的话请告诉我,不甚感激!
ViewDragHelper还是很厉害的,我也只知道一点,各位如果有兴趣,请点击下方链接
http://flavienlaurent.com/blog/2013/08/28/each-navigation-drawer-hides-a-viewdraghelper/