转载请标明出处: http://blog.csdn.net/airsaid/article/details/53057091
本文出自:周游的博客
前言
自定义 View 可以说是 Android 路上的一道坎,会的人觉得简单,不会的觉得很难。最近正好在看《Android开发艺术探索》讲的自定义 View 这里,于是打算从头理一理自定义 View,写写笔记,方便日后自己查阅也希望能帮助到你。
什么是View
View作为用户界面组件的基本构建块,在屏幕上占据一个矩形区域,负责绘图和事件的处理。View是Android中所有控件的基类,像TextView、Button、LinearLayout都是间接或直接继承自View。除了View之外,还有一个比较重要的控件:ViewGroup。ViewGroup也是继承自View,和View不同的是,View主要用于创建交互式UI组件,而ViewGroup则表示一个控件组,布局Layout都继承自该类,其内部可以包含多个控件。
View位置参数
View最重要的莫过于View的位置参数了,View的位置,主要用4个点组成,分别对应View的四个属性:left、rigth、top、buttom。其中left是左上角横坐标,top是左上角纵坐标,right是右上角横坐标,buttom是右下角纵坐标。如下图:
注意事项
这些坐标都是根据当前View的父容器来决定的,而并不是根据当前屏幕。
从Android3.0开始,View增加了几个额外的属性:x、y、translationX、translationY。其中x、y是View左上角的坐标,而translationX、和translationY则是View左上角相对于父容器的偏移量。这几个参数也都是相当于父容器的,并且translationX、translationY的默认值为0。其换算公式如下:
x = left + translationX
y = top + translationY
MotionEvent
通过MotinoEvent对象我们可以获取的用户触摸到手机屏幕产生的事件,通常的触摸事件有如下几种:
- ACTION_DOWM:手指刚接触屏幕。
- ACTION_MOVE:手指在屏幕上移动。
- ACTION_UP:手指在屏幕上松开的一瞬间。
同时我们还可以同时获取到,用户触摸时的x、y坐标。我们可以通过getX()、getY()、getRawX()、getRawY()来获取。其中getX()、getY()是获取的相对于当前View左上角的x、y坐标。而getRawX()、getRawY()则获取的是相对于手机屏幕左上角的x、y坐标。
TouchSlop
TouchSlop是一个常量,保存的是系统所能识别出的最小滑动距离。这个值在不同的设备上有可能是不同的,我们通常使用它来进行一些滑动过滤,比如说判断当前滑动的距离如果少于这个值,那么就可以判断不是滑动,不进行滑动后的处理,增强用户体验。
我们可以通过:
ViewConfiguration.get(this).getScaledTouchSlop();
来获取TouchSlop这个值。
VelocityTracker
VelocityTracker,速度追踪,通过这个类我们可以获取手指在滑动时的速度,其中包括水平和垂直方向的速度。
获取第一步,在View的onTouch()方法中添加追踪:
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
第二步,获取当前滑动速度:
velocityTracker.computeCurrentVelocity(1000);
float xVelocity = velocityTracker.getXVelocity();
float yVelocity = velocityTracker.getYVelocity();
需要注意的是,在获取之前,必须先要调用computeCurrentVelocity(int units)方法,其中units参数代表的是毫秒时间段。比如说上方写的1000就代表1秒内手指滑动的像素数,如果1秒内滑动了100像素数,那么值就为100,当然这个值也有可能是负数,如果是在水平方向从右往左滑动,值则会负数,垂直时,从下往上滑动,也为负数。总结下来可以用一个公式来表示:
速度 = (终点位置 - 起点位置) / 时间段
当我们不需要使用VelocityTracker的时候,可以通过如下方法重置并回收内存:
velocityTracker.clear();
velocityTracker.recycle();
GestureDetector
GestureDetector是一个手势检测类,用于辅助我们检测用户的手势动作,比如说:单击、双击、长按、滑动等行为。
GestureDetector的使用也很简单,主要分如下几步:
- 第一步(创建对象):
GestureDetector gestureDetector = new GestureDetector(new GestureDetector.OnGestureListener() {
@Override
public boolean onDown(MotionEvent e) {
return false;
}
@Override
public void onShowPress(MotionEvent e) {
}
@Override
public boolean onSingleTapUp(MotionEvent e) {
return false;
}
@Override
public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
return false;
}
@Override
public void onLongPress(MotionEvent e) {
}
@Override
public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
return false;
}
});
其中,构建对象的参数为一个监听接口。如果只需要单独监听某个事件,可以实现如下监听:
GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
// 实现需要实现的方法
});
- 第二步(重写onTouchEvent()方法,接管触摸事件):
@Override
public boolean onTouchEvent(MotionEvent event) {
boolean consume = mGestureDetector.onTouchEvent(event);
return consume;
}
至此,我们我们就可以获取到用户触摸时的状态了,当用户触摸时分别会调用对应回调方法。具体的方法描述如下:
方法名 | 描述 |
---|---|
onDown | 手指轻轻触摸屏幕的一瞬间触发 |
onShowPress | 手指轻轻触摸屏幕,尚未松开或拖动时触发 |
onSingleTapUp | 手指轻轻触摸屏幕后松开时触发 |
onScroll | 手指按下屏幕后拖动时触发 |
onLongPress | 长按屏幕时触发 |
onFling | 按下屏幕,快速滑动后松开时触发 |
我们不仅可以获取到用户的如上触摸状态,还可以通过GestureDetector的setOnDoubleTapListener(listener)方法获取用户的双击等事件:
mGestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
@Override
public boolean onSingleTapConfirmed(MotionEvent e) {
return false;
}
@Override
public boolean onDoubleTap(MotionEvent e) {
return false;
}
@Override
public boolean onDoubleTapEvent(MotionEvent e) {
return false;
}
});
其中各回调方法说明如下:
方法名 | 描述 |
---|---|
onSingleTapConfirmed | 严格的单击行为(只允许出现一次单击行为,如果触发了该事件,那么后面不可能再有单击事件。即只可能是单击,而不是双击中的一次。) |
onDoubleTap | 双击时触发(该方法不可与onSingleTapConfirmed()方法共存) |
onDoubleTapEvent | 表示发生了双击行为,在双击的期间,ACTION_DOWN、ACTION_MOVE和ACTION_UP都会触发该回调 |
参考
《Android开发艺术探索》