上划版面 SlidingUpPanel 的教程网址
(http://blog.csdn.net/ocwvar/article/details/50682213 )
首先是布局文件:
<com.ocwvar.surfacetest.QQSwipePanel.OCHorizontalSlidingPanel
xmlns:android="http://schemas.android.com/apk/res/android"
android:id="@+id/sli"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#000">
<ListView
android:id="@+id/sli_menu_listview"
android:layout_width="200dp"
android:layout_height="match_parent"
android:divider="@null"
android:background="#003470"/>
<FrameLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<ListView
android:id="@+id/listview2"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:divider="@null"
android:background="#58b7e7"/>
<com.ocwvar.surfacetest.SlidingPanelTest.OCSlidingUpPanel
android:id="@+id/tgp"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
</com.ocwvar.surfacetest.QQSwipePanel.OCHorizontalSlidingPanel>
这个侧滑菜单唯一的难点就是如何解决可滑动View中带有可滑动控件的问题 就像动态图中带有ListView的View既可以左右滑动展开侧滑菜单,也可以上下滑动ListView。
我当初也是想了很久,后来想到了Google Play商店的侧滑菜单,也就是自带组件 NavigationView与DrawerLayout的组合 。我们不需要照顾整个可拖动View的触摸事件,怎么处理,看下面的图片
当触摸事件产生在 红色区域 的时候:
我们就认为当前用户的意图是要展开菜单,从而阻断到ListView的触摸事件。
当触摸事件产生在 剩余区域 的时候:
我们就认为当前用户是想要操作ListView,让触摸事件传递到ListView。
处理这些事件我们重写方法:
public boolean onInterceptTouchEvent(MotionEvent ev)
@Override
public boolean onInterceptTouchEvent(MotionEvent ev) {
final float pointX = ev.getRawX();
if (MotionEventCompat.getActionMasked(ev) == MotionEvent.ACTION_UP){
openingMenu = false;
return false;
}
if (status == 0){
// On panel is closed
if (pointX > 0 && pointX < dragSize){
openingMenu = true;
}
}else if (status == 1){
//On panel is opened
if (pointX > getPaddingLeft()+menuView.getMeasuredWidth()){
openingMenu = true;
}
}
return openingMenu;
}
代码详解:
变量 dragSize 是触摸区域的宽度。
● 当触摸事件的X坐标处于 0~dragSize 之间的时候我们就将当前行为确定是 正在滑动主版面
● 当 当前状态是菜单已打开 同时 触摸事件的X坐标位于ViewGroup的左Padding+菜单View宽度的距离(也就是在半边处于屏幕外边的主界面)的时候,我们就将当前行为确定是 正在滑动主版面
● 当用户手指抬起来的时候,就会触发ViewDragHelper.CallBack.onViewReleased() 事件,到时候会根据已滑动距离来判断菜单是否已经打开,或者需不需要执行滑动动画来完成打开动作。这我们下面会说到。
我们在布局文件里面就要放好 主版面mainView 和菜单版面menuView ,放在第一个的View是mainView,第二个的就是menuView,但是在代码中mainView的位置是第二个,menuView的位置是第一个。 看了代码大家就懂了。
重写 protected void onFinishInflate()
@Override
protected void onFinishInflate() {
super.onFinishInflate();
if (dragHelper == null){
dragHelper = ViewDragHelper.create(this,1.0f,new DragHelperCallBack());
}
mainView = getChildAt(1);
menuView = getChildAt(0);
}
重写 protected void onLayout(boolean changed, int l, int t, int r, int b)
@Override
protected void onLayout(boolean changed, int l, int t, int r, int b) {
if (mainView != null){
mainView.layout(l, t, l + mainView.getMeasuredWidth(), b);
}
if (menuView != null){
menuView.layout( l , t , l + menuView.getMeasuredWidth() , b);
}
}
我们先绘制最上层的mainView,再绘制底层的menuView
剩下的就是重写computeScroll()和onTouchEvent()了,和之前的一样,这里就不重新写了。
接下来是创建继承了ViewDragHelper.Callback的类
class DragHelperCallBack
private class DragHelperCallBack extends ViewDragHelper.Callback {
@Override
public boolean tryCaptureView(View child, int pointerId) {
//Only main panel can be drag
return mainView != null && child == mainView;
}
@Override
public int clampViewPositionHorizontal(View child, int left, int dx) {
final int leftEdge = getPaddingLeft();
final int rightEdge = getPaddingLeft() + menuView.getMeasuredWidth();
return Math.min(Math.max(left, leftEdge), rightEdge);
}
@Override
public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) {
offset = left;
}
@Override
public void onViewReleased(View releasedChild, float xvel, float yvel) {
final int width = Math.abs(menuView.getMeasuredWidth() - getPaddingLeft());
System.out.println("Width:"+width+" Offset:"+offset);
if (offset == width && status == 0){
openingMenu = false;
status = 1;
}else if (offset == 0 && status == 1){
openingMenu = false;
status = 0;
}else if (offset >= width/2){
scrollToMax();
}else if (offset < width/2){
scrollToClose();
}
}
感觉这里比之前的 SlidingUpPanel 更简单。。没啥好说的,稍微注意下的地方就是,用户拖动的时候有四种情况:
考虑完全就没啥了 =。=