[TOC]
声明:此系列的部分内容出自《Android开发艺术探索》一书,是我当初学习时候的一些笔记和总结,在这里留个记录。
View是android中所有控件的基类。
位置参数
在Android系统中,左上角为坐标原点,x和y轴正方向分别是往右和下。View的位置由它的4个顶点来决定,即top,left,right,bottom。需要注意的是这4个点是相对坐标,相对于view的父容器来说的。获取方法:
- top: getTop()
- left: getLeft()
- right: getRight()
- bottom: getBottom()
从Android3.0开始,View增加了4个额外的参数:x,y,translationX,translationY。其中x和y指view左上角的坐标,translationX和translationY指view左上角相对于父容器的偏移量。这4个参数也都是相对坐标,他们之间的相互关系如下:
- x = left + translationX;
- y = top + translationY;
即:在view发生平移的过程中,left和top始终是不变的,指view原始位置的左上角坐标,发生改变的只是x,y,translationX,translationY这4个参数。
触摸事件
MotionEvent
手指的触摸事件一般可以分为两种(姑且把单击和长按当成一种,滑动和多点触控当成一种吧,起码触发的事件是差不多的):
- 手指按下,不滑动,放开:DOWN--->UP。
- 手指按下,滑动一段距离,再松手:DOWN--->MOVE--->...--->MOVE--->UP。
通过MotionEvent对象我们可以得到点击位置的坐标:
- getX()和getY():得到的是相对当前view左上角的坐标。
- getRawX()和getRawY():得到的是相对手机屏幕左上角的坐标。
TouchSlop
即系统所能识别出的被认为是滑动的最小距离。常量,和硬件设备有关,可以通过ViewConfiguration.get(context).getScaledTouchSlop()得到,手指移动小于这个值得话则认为这次操作不是滑动。
VelocityTracker
用来测量某个触摸事件的速度。
@Override
public boolean onTouchEvent(MotionEvent event) {
/**
* 某个触摸时间的速度测量:
* 1.通过obtain()方法获得velocityTracker变量,并添加需要测量的事件
* 2.通过computeCurrentVelocity计算速度(参数单位为ms),再通过getter方法获取速度值(右下滑为正数,反之为负数)
* 3.释放velocityTracker对象。
*/
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
velocityTracker.computeCurrentVelocity(1000);//秒速
int v_x = (int) velocityTracker.getXVelocity();
int v_y = (int) velocityTracker.getYVelocity();
LogUtils.i(TAG,"\t\tX:" + v_x + "\t\tY:" + v_y);
velocityTracker.recycle();
return true;
}
02-17 11:26:55.483 27154-27154/lxf.androiddemos I/TestView: X:5656 Y:1203
02-17 11:26:55.500 27154-27154/lxf.androiddemos I/TestView: X:6255 Y:1202
02-17 11:26:55.509 27154-27154/lxf.androiddemos I/TestView: X:0 Y:0
02-17 11:26:55.510 27154-27154/lxf.androiddemos I/TestView: X:0 Y:0
02-17 11:27:01.207 27154-27154/lxf.androiddemos I/TestView: X:0 Y:0
02-17 11:27:01.248 27154-27154/lxf.androiddemos I/TestView: X:-421 Y:49
02-17 11:27:01.265 27154-27154/lxf.androiddemos I/TestView: X:-2978 Y:372
02-17 11:27:01.282 27154-27154/lxf.androiddemos I/TestView: X:-3426 Y:426
GestureDetector
手势检测,用来辅助检测用户的滑动、单击、双击、长按等行为。
//1.实现OnGestureListener接口
public class TestView extends View implements GestureDetector.OnGestureListener{
//2.获得GestureDetector对象,
gestureDetector = new GestureDetector(getContext(),this);
//如果要监听双击,可以实现DoubleTapListener接口
gestureDetector.setOnDoubleTapListener(mDoubleTapListener);
...
//3.接管onTouchEvent(event)方法。
@Override
public boolean onTouchEvent(MotionEvent event) {
return gestureDetector.onTouchEvent(event);
}
//4.在接口的相应回调方法中实现自己的逻辑。
...
}
View的滑动
scrollTo/scrollBy
scrollBy内部实际上就是调用的scrollTo方法,它实现了view基于当前位置的相对滑动,而scrollTo是相对于初始位置滚动某段距离,可以变向理解为绝对滑动。
public void scrollBy(int x, int y) {
scrollTo(mScrollX + x, mScrollY + y);
}
在滑动过程中,mScrollX的值总是等于view的左边缘(left)和view的内容的左边缘在水平方向上的距离,mScrollY同理。scrollTo/scrollBy只能改变view的内容位置而不能改变view在布局中的位置。
使用动画
使用动画使view平移的方式有两种:
- 补间动画:实际上是对view的影像进行操作,并不会改变view本身的位置、内容等参数。
TranslateAnimation animation = new TranslateAnimation(0,100,0,0);
setAnimation(animation);
animation.start();
- 属性动画:直接操作view的属性,可以改变view自身。
ObjectAnimator.ofInt(targetView,"translationX",0,100).setDuration(500).start();
改变LayoutParams
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) getLayoutParams();
params.leftMargin += 100;
setLayoutParams(params);
// 或requestLayout();
弹性滑动
使用Scroller
Scroller的典型用法:
scroller = new Scroller(getContext());
private void smoothScrollTo(int x, int y) {
int scrollX = getScrollX();
int delayX = x - scrollX;
scroller.startScroll(scrollX, 0, delayX, 0, 1000);//仅仅保存相应参数
invalidate();//draw方法中会调用computeScroll
}
@Override
public void computeScroll() {
if (scroller.computeScrollOffset()) {
scrollTo(scroller.getCurrX(), scroller.getCurrY());
postInvalidate();
}
}
Scroller本身并不能使View滑动,它需要配合View的computeScroll方法才能实现弹性滑动的效果。它不断让view重绘,每一次重绘距离view的起始滑动会有一个时间间隔,通过这个时间间隔Scroller可以得到view的当前滑动位置,通过scrollTo()完成滑动。
使用属性动画
值动画:其实属性动画的根本就是属性值的改变。
ValueAnimator animator = ValueAnimator.ofFloat(0,1).setDuration(1000);
animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() {
@Override
public void onAnimationUpdate(ValueAnimator animation) {
float flag = animation.getAnimatedFraction();
scrollTo(startX + (int)(delayX * flag),0);
}
});
animator.start();
其实所谓弹性滑动,就是将一次滑动分成了若干个短距离滑动。