自定义ViewGroup+ViewDragHelper —— 侧滑菜单
2016-02-18 19:07
791 查看
上划版面 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 是触摸区域的宽度。
Return true; —— 拦截事件
Return false; —— 不拦截事件
● 当触摸事件的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 更简单。。没啥好说的,稍微注意下的地方就是,用户拖动的时候有四种情况:
1.拖动到触发 展开动画scrollToMax() 的区域
2.拖动到触发 关闭动画scrollToClose() 的区域
3.直接拖动到完全展开
4.直接拖动到完全关闭
考虑完全就没啥了 =。=
相关文章推荐
- 使用C++实现JNI接口需要注意的事项
- Android IPC进程间通讯机制
- Android Manifest 用法
- [转载]Activity中ConfigChanges属性的用法
- Android之获取手机上的图片和视频缩略图thumbnails
- Android之使用Http协议实现文件上传功能
- Android学习笔记(二九):嵌入浏览器
- android string.xml文件中的整型和string型代替
- i-jetty环境搭配与编译
- android之定时器AlarmManager
- android wifi 无线调试
- Android Native 绘图方法
- Android java 与 javascript互访(相互调用)的方法例子
- android 代码实现控件之间的间距
- android FragmentPagerAdapter的“标准”配置
- Android"解决"onTouch和onClick的冲突问题
- android:installLocation简析
- android searchView的关闭事件
- SourceProvider.getJniDirectories