最近做的项目里用到一个开源的第三方库SlidingUpPanel,其作用是将一个视图从底部往上拖拽到另一个视图之上,代码在github上可以下载到https://github.com/umano/AndroidSlidingUpPanel,其效果如下图所示:
具体的用法在github上也有,在此就不另做赘述,本文主要讨论其具体是如何实现的。下载源文件可以看到里面只有两个文件SlidingUpPanelLayout.java和 ViewDragHelper.java。
一、ViewDragHelper.java
首先来说说ViewDragHelper.java,可能有些看官已经对其有所了解,那么请忽略,本文讲的不好的地方也可以帮忙指出,一定虚心接受。
在2013年谷歌i/o大会上介绍了两个新的layout: SlidingPaneLayout和DrawerLayout,研究过其源码的应该知道这两个类都使用了ViewDragHelper.java处理拖动。SlidingPaneLayout与本文所讲的SlidingUpPanelLayout.java很像(有没有~~~),甚至其内部处理拖动的方式也都采用ViewDragHelper.java处理。
ViewDragHelper.java在support v4中,官方的介绍如下:
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.
用于自定义ViewGroup的一个工具类,为用户在父ViewGroup中拖动并且重新定位视图,提供了很多有用的操作以及状态跟踪方法。要获取到ViewDragHelper.java类的实例,可以调用该类的create()方法,该方法有两个,一个是两个参数的,一个是三个参数的。三个参数分别为:forParent第一个是指定监听的父视图;第二个参数sensitivity表示灵敏度,值越大代表越灵敏,通常为1.0 ;第三个参数是个回调接口cb,是ViewDragHelper与ViewGroup之间通信的桥梁,也是使用ViewDragHepler的关键。
create方法调用ViewDragHelper的私有构造方法实例化该类,构造方法中进行成员变量的赋值等操作,其中有个mScroller(是不是看着眼熟,没错,ViewDragHelper的拖动其实是通过Scroller滚动类实现的,如果对Scroller不熟的看官可以找找这方面的资料)。
上面讲到使用ViewDragHelper关键是回调接口Callback,实际上ViewDragHelper并不直接作用于要被拖动的View,而是使其控制的视图容器中的子View可以被拖动,如果要指定某个子view的行为,需要在Callback中实现:
上面列出了Callback中定义的所有方法,tryCaptureView方法用于指定视图容器中的哪个view可以进行拖动;clampViewPositionHorizontal和clampViewPositionVertical两个方法用于具体实现拖动,是必须实现的;其他的方法根据需要进行实现。public static abstract class Callback {
public void onViewDragStateChanged(int state) {} //拖动状态改变时触发该方法
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {} //视图位置改变触发该方法
public void onViewCaptured(View capturedChild, int activePointerId) {} //当子视图被捕获进行拖动时触发该方法
public void onViewReleased(View releasedChild, float xvel, float yvel) {} // 当子视图失去被捕获时触发该方法
public void onEdgeTouched(int edgeFlags, int pointerId) {}
public boolean onEdgeLock(int edgeFlags) {
return false;
}
public void onEdgeDragStarted(int edgeFlags, int pointerId) {}
public int getOrderedChildIndex(int index) {
return index;
}
public int getViewHorizontalDragRange(View child) {
return 0;
}
public int getViewVerticalDragRange(View child) {
return 0;
}
public abstract boolean tryCaptureView(View child, int pointerId);
public int clampViewPositionHorizontal(View child, int left, int dx) {
return 0;
}
public int clampViewPositionVertical(View child, int top, int dy) {
return 0;
}
}
另外使用ViewDragHelper处理拖动,必须将拖动事件传递给ViewDragHelper,ViewDragHelper中定义了shouldInterceptTouchEvent和processTouchEvent方法对事件进行处理。
ViewDragHelper就介绍到这里,讲的不好,逻辑性也不强,下面总结下使用ViewDragHelper的关键点:
1、通过create方法获取到ViewDragHelper实例;
2、根据需要实现Callback相关方法;
3、将事件传递给ViewDragHelper(一般是在onInterceptTouchEvent和onTouchEvent中调用ViewDragHelper的shouldInterceptTouchEvent和processTouchEvent方法);
还有其他诸如计算可以拖动的范围、完成拖动后的惯性操作这里就不做介绍了,感兴趣的可以研究下。
二、SlidingUpPanelLayout
终于进入到本文的主题了SlidingUpPanelLayout,其基本原理如下:
1、继续于ViewGroup,并且在ViewGroup中添加两个子view,一个定义为mMainView,另一个定义为mSlideableView;
2、重写ViewGroup的onMeasure、onLayout方法将两个子view在界面进行布局显示;
3、通过ViewDragHelper实现将mSlideableView从底部往上拖动,并覆盖mMainView。
(待续~~)
本文探讨了Android第三方库SlidingUpPanel的实现原理,重点解析了ViewDragHelper在拖动处理中的作用,以及如何创建实例并实现回调接口。SlidingUpPanelLayout作为 ViewGroup 的扩展,通过添加两个子View并重写测量和布局方法,利用ViewDragHelper实现在屏幕底部向上滑动的功能。
1433

被折叠的 条评论
为什么被折叠?



