ViewDragHelper——打造你的专属ViewGroup
2016-05-18 22:06
330 查看
ViewDragHelper介绍
转载请注明出处,有问题的话欢迎在下面留言,我会一一回复.在自定义控件中,很多效果都需要重写onInterceptTouchEvent和onTouchEvent这两个类,但要考虑到各种情况,写出很好的手势处理控件是比较麻烦的。比如多点触控,速度监测等。ViewDragHelper是谷歌io大会上隆重推出的手势处理的类。在android.support.v4中。像Google官方侧滑菜单,DrawerLayout就是用这个类实现的。本节先介绍它的基本用法,以后会介绍如何用ViewDragHelper自定义侧滑菜单。
基本实现
创建实例
mViewDragHelper = ViewDragHelper.create(this,1.0f,callback);
需要传入三个参数,第一个参数传入当前的ViewGroup;第二个参数是灵敏度,数值越大,灵敏度越低;第三个参数传入ViewDragHelper.Callback,后面详细介绍。
触摸相关的方法
@Override public boolean onInterceptTouchEvent(MotionEvent ev) { // 让ViewDragHelper帮我们判断是否应该拦截 boolean result = viewDragHelper.shouldInterceptTouchEvent(ev); return result; } @Override public boolean onTouchEvent(MotionEvent event) { // 将触摸事件交给ViewDragHelper来解析处理 viewDragHelper.processTouchEvent(event); return true; }
ViewDragHelper.Callback的相关方法
callback的方法,大家参考注释。private ViewDragHelper.Callback callback = new ViewDragHelper.Callback() { /** * 用于判断是否捕获当前child的触摸事件 child: 当前触摸的子View return: true:就捕获并解析 false:不处理 */ @Override public boolean tryCaptureView(View child, int pointerId) { return child == blueView || child == redView; } /** * 当view被开始捕获和解析的回调 capturedChild:当前被捕获的子view */ @Override public void onViewCaptured(View capturedChild, int activePointerId) { super.onViewCaptured(capturedChild, activePointerId); // Log.e("tag", "onViewCaptured"); } /** * 获取view水平方向的拖拽范围,但是目前不能限制边界,返回的值目前用在手指抬起的时候view缓慢移动的动画世界的计算上面; 最好不要返回0 */ @Override public int getViewHorizontalDragRange(View child) { return getMeasuredWidth() - child.getMeasuredWidth(); } /** * 获取view垂直方向的拖拽范围,最好不要返回0 */ public int getViewVerticalDragRange(View child) { return getMeasuredHeight() - child.getMeasuredHeight(); } /** * 控制child在水平方向的移动 left: * 表示ViewDragHelper认为你想让当前child的left改变的值,left=chile.getLeft()+dx dx: * 本次child水平方向移动的距离 return: 表示你真正想让child的left变成的值 */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { if (left < 0) { // 限制左边界 left = 0; } else if (left > (getMeasuredWidth() - child.getMeasuredWidth())) { // 限制右边界 left = getMeasuredWidth() - child.getMeasuredWidth(); } return left; } /** * 控制child在垂直方向的移动 top: * 表示ViewDragHelper认为你想让当前child的top改变的值,top=chile.getTop()+dy dy: * 本次child垂直方向移动的距离 return: 表示你真正想让child的top变成的值 */ public int clampViewPositionVertical(View child, int top, int dy) { if (top < 0) { top = 0; } else if (top > getMeasuredHeight() - child.getMeasuredHeight()) { top = getMeasuredHeight() - child.getMeasuredHeight(); } return top; }; /** * 当child的位置改变的时候执行,一般用来做其他子View的伴随移动 changedView:位置改变的child * left:child当前最新的left top: child当前最新的top dx: 本次水平移动的距离 dy: 本次垂直移动的距离 */ @Override public void onViewPositionChanged(View changedView, int left, int top, int dx, int dy) { super.onViewPositionChanged(changedView, left, top, dx, dy); if (changedView == blueView) { // blueView移动的时候需要让redView跟随移动 redView.layout(redView.getLeft() + dx, redView.getTop() + dy, redView.getRight() + dx, redView.getBottom() + dy); } else if (changedView == redView) { // redView移动的时候需要让blueView跟随移动 blueView.layout(blueView.getLeft() + dx, blueView.getTop() + dy, blueView.getRight() + dx, blueView.getBottom() + dy); } //1.计算view移动的百分比 float fraction = changedView.getLeft()*1f/(getMeasuredWidth()-changedView.getMeasuredWidth()); Log.e("tag", "fraction:"+fraction); //2.执行一系列的伴随动画 executeAnim(fraction); } /** * 手指抬起的执行该方法, releasedChild:当前抬起的view xvel: x方向的移动的速度 正:向右移动, 负:向左移动 * yvel: y方向移动的速度 */ @Override public void onViewReleased(View releasedChild, float xvel, float yvel) { super.onViewReleased(releasedChild, xvel, yvel); int centerLeft = getMeasuredWidth() / 2 - releasedChild.getMeasuredWidth() / 2; if (releasedChild.getLeft() < centerLeft) { // 在左半边,应该向左缓慢移动 viewDragHelper.smoothSlideViewTo(releasedChild, 0, releasedChild.getTop()); ViewCompat.postInvalidateOnAnimation(DragLayout.this); } else { // 在右半边,应该向右缓慢移动 viewDragHelper.smoothSlideViewTo(releasedChild, getMeasuredWidth() - releasedChild.getMeasuredWidth(), releasedChild.getTop()); ViewCompat.postInvalidateOnAnimation(DragLayout.this); } } }; /** * 执行伴随动画 * @param fraction */ private void executeAnim(float fraction){ //fraction: 0 - 1 //缩放 // ViewHelper.setScaleX(redView, 1+0.5f*fraction); // ViewHelper.setScaleY(redView, 1+0.5f*fraction); //旋转 // ViewHelper.setRotation(redView,360*fraction);//围绕z轴转 ViewHelper.setRotationX(redView,360*fraction);//围绕x轴转 // ViewHelper.setRotationY(redView,360*fraction);//围绕y轴转 ViewHelper.setRotationX(blueView,360*fraction);//围绕z轴转 //平移 // ViewHelper.setTranslationX(redView,80*fraction); //透明 // ViewHelper.setAlpha(redView, 1-fraction); //设置过度颜色的渐变 redView.setBackgroundColor((Integer) ColorUtil.evaluateColor(fraction,Color.RED,Color.GREEN)); // setBackgroundColor((Integer) ColorUtil.evaluateColor(fraction,Color.RED,Color.GREEN)); } public void computeScroll() { if (viewDragHelper.continueSettling(true)) { ViewCompat.postInvalidateOnAnimation(DragLayout.this); } }
其他代码
/** * 当DragLayout的xml布局的结束标签被读取完成会执行该方法,此时会知道自己有几个子View了 一般用来初始化子View的引用 */ @Override protected void onFinishInflate() { super.onFinishInflate(); redView = getChildAt(0); blueView = getChildAt(1); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { super.onMeasure(widthMeasureSpec, heightMeasureSpec); //要测量我自己的子View // int size = getResources().getDimension(R.dimen.width);//100dp // int measureSpec = MeasureSpec.makeMeasureSpec(redView.getLayoutParams().width,MeasureSpec.EXACTLY); // redView.measure(measureSpec,measureSpec); // blueView.measure(measureSpec, measureSpec); //如果说没有特殊的对子View的测量需求,可以用如下方法 measureChild(redView, widthMeasureSpec, heightMeasureSpec); measureChild(blueView, widthMeasureSpec, heightMeasureSpec); } @Override protected void onLayout(boolean changed, int l, int t, int r, int b) { int left = getPaddingLeft(); int top = getPaddingTop(); redView.layout(left, top, left + redView.getMeasuredWidth(), top + redView.getMeasuredHeight()); blueView.layout(left, redView.getBottom(), left + blueView.getMeasuredWidth(), redView.getBottom() + blueView.getMeasuredHeight()); }
布局文件
<xyz.ibat.circleview.test.DragLayout android:layout_width="match_parent" android:layout_height="match_parent" > <TextView android:layout_width="@dimen/width" android:layout_height="@dimen/width" android:background="#ff0000" /> <TextView android:layout_width="@dimen/width" android:layout_height="@dimen/width" android:background="#0000ff" /> </xyz.ibat.circleview.test.DragLayout>
OK~~源码里注释写的很详细,就不过多描述了。开始打造属于你的ViewGroup吧!
相关文章推荐
- 前端构建工具gulp入门教程
- Uva 129 Krypton Factor(困难的串)
- 程序员如何保证我们的代码质量
- 动态路由协议之ISIS
- LNMP博客以及数据库分离搭建实战
- java反射机制的基本用法
- 网络黑客攻防学习平台之基础关第一题
- mysql 对于百万 千万级数据的分表实现方法
- PPT课件中的多媒体资源怎么快速下载提取出来?
- 第7课:Spark Streaming源码解读之JobScheduler内幕实现和深度思考
- 搭建多点触控模拟环境
- 习题8-1 UVA - 1149 Bin Packing 装箱 (滑动窗口)
- 浅谈Spring
- MediaWiki安装插件 ——以CategoryTree为例
- python3 下ascii与 str的转换
- 《JavaScript程序设计》课堂交流区问题汇总(进阶篇)
- 题目1
- 最大流-HDU-3338-Kakuro Extension
- HDU 1796How many integers can you find(容斥原理)
- varchar2_to_blob,应用向数据库更新LOB字段时的超时问题