自定义View之常用工具类汇总
来源:互联网 发布:js 调用按钮点击事件 编辑:程序博客网 时间:2024/05/22 12:23
在自定义View的过程中,我们经常用到各种工具类来简化我们的工作。这篇文章就对sdk提供的一些常用的工具类进行一下总结。
ViewConfiguration
这个类是在自定义View的过程中使用频率非常高的。比如自定义View需要和用户进行Touch交互的时候,常常需要获得TouchSlop,就是通过这个类来获得。
获取ViewConfiguration实例:
ViewConfiguration vc = ViewConfiguration.get(context);
这个类提供了一些常用的对象方法用于获取基本常量值:
//认定是Scroll操作的最短距离,以像素为单位int touchSlop = vc.getScaledTouchSlop();//是否含有物理实体按键boolean isHavePermanentMenuKey = vc.hasPermanentMenuKey();//获取fling速度的最大值和最小值int maxFlingVelocity = vc.getScaledMaximumFlingVelocity();int minFlingVelocity = vc.getScaledMinimumFlingVelocity();
还有一些常用的静态方法:
//双击的时间间隔,否则认定是单击int doubleTapTimeout = ViewConfiguration.getDoubleTapTimeout();//长按状态的时间长度int longPressTimeout = ViewConfiguration.getLongPressTimeout();
GestureDetector
在编写自定义View的时候,可能需要检测一些特定的手势。如果我们在onTouchEvent回调函数中自己处理必定非常麻烦。使用工具类GestureDetector可以简化我们的工作量。
Detects various gestures and events using the supplied MotionEvents. The GestureDetector.OnGestureListener callback will notify users when a particular motion event has occurred.
一般我们按照如下步骤使用GestureDetector
- 创建GestureDetector实例
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){ ...}
- 监听各种手势回调函数
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){ @Override public boolean onSingleTapUp(MotionEvent e) { Log.d("CustomView", "onSingleTapUp"); return true; } @Override public void onLongPress(MotionEvent e) { Log.d("CustomView", "onLongPress"); } @Override public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) { Log.d("CustomView", "onScroll, distanceX=" + distanceX + ", distanceY=" + distanceY); return true; } @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.d("CustomView", "onFling, velocityX=" + velocityX + ", velocityY=" + velocityY); return true; } @Override public boolean onDoubleTap(MotionEvent e) { Log.d("CustomView", "onDoubleTap"); return true; }});
- 将MotionEvent对象传递给GestureDetector
@Overridepublic boolean onTouchEvent(MotionEvent event){ mGestureDetector.onTouchEvent(event); return true;}
OK,下面贴一下Log.d的打印,方便理解各个回调函数何时调用
- 单击
06-19 22:01:25.240 14850-14850/com.czh.customviewtools D/CustomView: onSingleTapUp
- 双击
06-19 22:01:04.054 14850-14850/com.czh.customviewtools D/CustomView: onSingleTapUp06-19 22:01:04.139 14850-14850/com.czh.customviewtools D/CustomView: onDoubleTap
- Scroll,从左上到右下滑动
06-19 22:03:29.463 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-17.110687, distanceY=-15.12115506-19 22:03:29.478 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-9.851639, distanceY=-11.85520906-19 22:03:29.497 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-11.986954, distanceY=-11.99319506-19 22:03:29.512 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-11.984398, distanceY=-12.39547706-19 22:03:29.529 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-9.235718, distanceY=-12.8325506-19 22:03:29.547 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-2.74868, distanceY=-7.746185306-19 22:03:29.563 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-3.9947968, distanceY=-3.16326906-19 22:03:29.579 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-1.9973984, distanceY=-5.36285406-19 22:03:29.596 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-2.996109, distanceY=-2.4653015
- Fling,从左上到右下
06-19 22:06:57.446 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-24.924263, distanceY=-25.19662506-19 22:06:57.462 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-29.701729, distanceY=-34.45388806-19 22:06:57.479 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-50.0672, distanceY=-40.05697606-19 22:06:57.497 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-59.65364, distanceY=-41.4551706-19 22:06:57.513 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-46.238846, distanceY=-26.56616206-19 22:06:57.521 14850-14850/com.czh.customviewtools D/CustomView: onScroll, distanceX=-21.808838, distanceY=-11.82803306-19 22:06:57.521 14850-14850/com.czh.customviewtools D/CustomView: onFling, velocityX=985.20465, velocityY=402.38626
这里Fling手势速度的含义。velocityX:1秒钟在X方向上滑动的像素值;velocityY:1秒钟在Y方向上滑动的像素值。
ViewDragHelper
自定义ViewGroup的时候,子view和用户进行交互是常有的事,即用户拖动某个子view(eg:侧滑菜单)。针对具体需求重写onInterceptTouchEvent和onTouchEvent不是件容易的事。ViewDragHelper可以帮助我们完成很多工作。
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.
看一下ViewDragHelper最简单的使用
public class ViewDragHelperDemo extends LinearLayout{ private ViewDragHelper mDragger; public ViewDragHelperDemo(Context context, AttributeSet attrs) { super(context, attrs); //创建ViewDragHelper实例 mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback() { @Override public boolean tryCaptureView(View child, int pointerId) { return true; } /** * 在水平方向上指定被拖拽子view的位置 * 这里做了边界控制,限制了子view在ViewGroup的水平范围内移动 */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { int leftBound = getPaddingLeft(); int rightBound = getWidth() - getPaddingRight() - child.getWidth(); left = left < leftBound ? leftBound : left; left = left > rightBound ? rightBound : left; return left; } /** * 在垂直方向上指定被拖拽子view的位置 * 这里没有做边界控制 */ @Override public int clampViewPositionVertical(View child, int top, int dy) { return top; } }); } @Override public boolean onInterceptHoverEvent(MotionEvent event) { return mDragger.shouldInterceptTouchEvent(event); } @Override public boolean onTouchEvent(MotionEvent event) { mDragger.processTouchEvent(event); return true; }}
解释一下:
- 创建ViewDragHelper实例
mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback(){ ...});
第一个参数传入ViewGroup;第二参数是拖拽的精确度,通常传入1.0f;第三个参数是ViewDragHelper.Callback()实例,这个回调接口就用来控制拖拽的细节。
- 回调函数
mDragger = ViewDragHelper.create(this, 1.0f, new ViewDragHelper.Callback(){ /** * 返回true表示,可以对子view进行拖拽 */ @Override public boolean tryCaptureView(View child, int pointerId) { return true; } /** * 在水平方向上指定被拖拽子view的位置 * 这里做了边界控制,限制了子view在ViewGroup的水平范围内移动 */ @Override public int clampViewPositionHorizontal(View child, int left, int dx) { int leftBound = getPaddingLeft(); int rightBound = getWidth() - getPaddingRight() - child.getWidth(); left = left < leftBound ? leftBound : left; left = left > rightBound ? rightBound : left; return left; } /** * 在垂直方向上指定被拖拽子view的位置 * 这里没有做边界控制 */ @Override public int clampViewPositionVertical(View child, int top, int dy) { return top; }});
想要实现拖拽效果,至少重写这三个回调函数。每个函数的功能都有注释,就不赘述了。
- 最后需要把MotionEvent交给ViewDragHelper
@Overridepublic boolean onInterceptHoverEvent(MotionEvent event){ return mDragger.shouldInterceptTouchEvent(event);}@Overridepublic boolean onTouchEvent(MotionEvent event){ mDragger.processTouchEvent(event); return true;}
下面贴个效果图
OK,可以发现,代码在水平方向上做了边界控制,垂直方向上可以任意拖动。
回调接口中还有很多方法可以让我们实现更加复杂的功能,比如:释放某个子view之后就回到原位;仿QQ侧滑菜单功能等等。
/** * 释放某个子view的回调 * 释放子view之后,让子view回到原位,就可以在这里实现 */@Overridepublic void onViewReleased(View releasedChild, float xvel, float yvel){}/** * 触摸屏幕Edge是触发;可以用来实现侧滑菜单功能 */@Overridepublic void onEdgeDragStarted(int edgeFlags, int pointerId){}
VelocityTracker
触摸手势的速度追踪帮助类。简单说一下使用方法:
第一步:开始速度追踪
private void startVelocityTracker(MotionEvent event){ if(mVelocityTracker == null) { mVelocityTracker = VelocityTracker.obtain(); } mVelocityTracker.addMovement(event);}
第二步:获取追踪到的速度
/** * 获取scroll时X方向上的速度 * @return */private int getScrollVelocityX(){ //设置单位,1000表示返回的是一秒内移动的像素值 mVelocityTracker.computeCurrentVelocity(1000); int velocityX = (int) mVelocityTracker.getXVelocity(); return Math.abs(velocityX);}/** * 获取scroll时Y方向上的速度 * @return */private int getScrollVelocityY(){ //设置单位,1000表示返回的是一秒内移动的像素值 mVelocityTracker.computeCurrentVelocity(1000); int velocityY = (int) mVelocityTracker.getYVelocity(); return Math.abs(velocityY);}
最后:停止速度追踪
private void stopVelocityTracker(){ if(mVelocityTracker != null) { mVelocityTracker.recycle(); mVelocityTracker = null; }}
我在前面GestureDetector的demo中,加入了VelocityTracker的打印,看一下效果。
首先,开始速度追踪
@Overridepublic boolean onTouchEvent(MotionEvent event){ mGestureDetector.onTouchEvent(event); startVelocityTracker(event); return true;}
打印追踪到的速度
mGestureDetector = new GestureDetector(context, new GestureDetector.SimpleOnGestureListener(){ //这里省略了一些回调函数 @Override public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) { Log.d("CustomView", "onFling, velocityX=" + velocityX + ", velocityY=" + velocityY); Log.d("CustomView", "velocityTracker: velocityX=" + getScrollVelocityX()+ ", velocityY=" + getScrollVelocityY()); return true; }});
下面是程序打印内容:
06-20 21:06:55.342 4247-4247/com.czh.customviewtools D/CustomView: onScroll, distanceX=-37.950577, distanceY=-33.9734506-20 21:06:55.359 4247-4247/com.czh.customviewtools D/CustomView: onScroll, distanceX=-23.83014, distanceY=-19.84567306-20 21:06:55.376 4247-4247/com.czh.customviewtools D/CustomView: onScroll, distanceX=-9.126953, distanceY=-7.133239706-20 21:06:55.387 4247-4247/com.czh.customviewtools D/CustomView: onScroll, distanceX=-23.96878, distanceY=-15.98751806-20 21:06:55.387 4247-4247/com.czh.customviewtools D/CustomView: onFling, velocityX=678.5648, velocityY=314.0172706-20 21:06:55.387 4247-4247/com.czh.customviewtools D/CustomView: velocityTracker: velocityX=678, velocityY=314
从打印内容可以看出,GestureDetector中的onFling()回调函数传入的速度参数和使用VelocityTracker得到的速度值是一致的。
Scroller
之前写过一篇关于Scroller的文章Android Scroller使用详解。这里就不在赘述。下面就进行简单的说明:
- 首先View是支持scroll操作,api中提供了两个方法:scrollTo()和scrollBy()。
- 关于scrollTo()和scrollBy()。需要注意3点:第一、scrollBy()最终调用的是scrollTo()方法;第二、移动坐标的方向问题,比如:scrollBy(-30, -50),代表向右移动30像素,向下移动50像素;第三、移动的是View的内容,而不是View本身。如果你调用一个TextView的scrollBy()或者scrollTo()方法,将会移动TextView的文本内容,TextView本身并不会移动。
- 由于scrollTo()和scrollBy()移动效果是瞬间的,借助Scroller工具类可以完成平滑移动的效果。需要掌握的就是Scroller的固定用法以及使用步骤,可以参考之前的文章。
欧克,本篇文章先介绍这么多。自定义View过程中用到的工具类,sdk还提供了很多,后续会进行补充。
参考文章:自定义View系列教程01–常用工具介绍
- 自定义View之常用工具类汇总
- Android自定义View之常用工具源码分析
- Android自定义View之常用工具源码分析
- 【自定义View】01--常用工具介绍
- 自定义View系列教程01--常用工具介绍
- 自定义View系列教程01--常用工具介绍
- Android自定义View探索(二)—常用工具
- Android自定义View(二)——常用工具
- 自定义View系列教程01--常用工具介绍
- android 开发常用工具类汇总
- android 开发常用工具类汇总
- 自定义View-之Path类
- 常用工具汇总
- 常用工具汇总
- 常用工具汇总
- 常用工具汇总
- 常用工具汇总
- 常用工具汇总
- 主流开源数据库代码行数
- 超图Deskpro .NET 6R(2012) CAD图转化为GPS数据的操作步骤
- RPC框架
- iOS无法判断手机是否安装微信等(Scheme白名单问题)
- 无论如何
- 自定义View之常用工具类汇总
- selenium webdriver 杂记 - 自定义Table操作类(代码展示)
- hadoop1.x 和 hadoop 2.x 区别, 2.5 2.6 2.7之间的区别
- C++合成默认构造函数的真相
- DevExpress Grid中实现点击Detail获得Master rowHandle的方法
- Fragment中使用地图切换时会闪一下的处理方案
- 二叉树------由前序和中序求后序
- Rails 5 有什么新特性?
- 【QTP】如何改进QTP性能