【读书笔记】【Android 开发艺术探索】第3章 View 的事件体系
一、 View 的基础知识
View 是 Android 中所有空间的基类。
1、 View 的位置参数
View 的位置主要有四个顶点决定的, top、left、right、bottom. 这些顶点的坐标是相对于 View 的父容器来说。
从 Android 3.0 增加的参数: x、 y、 translationX 和 translationY. translationX 和 translationY 是 View 左上角相对于父容器的偏移量。
x = left + translationX, y = top + translationY;
在 View 平移的过程中, top 和 left 表示的是原始左上角的位置信息, 其值并不会发生变化, 改变的是 x, y, traslationX 和 translation Y.
3、 MotionEvent 和 TouchSlop
MotionEvent分为 ACTION_DOWN, ACTION_MOVE, ACTION_UP
获取点击事件的坐标
getX/getY 获取当前 View 左上角的的 x, y 坐标;
getRawX/getRawY 返回的是相对于手机屏幕左上角的 x 和 y 的坐标(即手指在屏幕中的坐标);
ToushSlop
系统所能识别出的被认为是滑动的最小距离。 常量, 和设备有关,不同的设备上可以有所不同。
通过 get(getContext()).getScaledTouchSlop() 获取。
4、VelocityTracker, GestureDetector 和 Scroller
VelocityTracker
速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。在 Support Library 中是VelocityTrackerCompat.
官网的连接 , 使用如下:
// 1、在 View 的 onTouchEvent 方法中追踪当前点击事件的速度
VelocityTracker velocityTracker = VelocityTracker.obtain();
velocityTracker.addMovement(event);
// 2、获取当前的速度, 单位以 1000 ms 为例
velocityTracker.computeCurrentVelocity(1000);
int xVelocity = (int) velocityTracker.getXVelocity();
int yVelocity = (int) velocityTracker.getYVelocity();
// 3、最后进行回收
velocityTracker.recycle();
GestureDetector
手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。
Gathering data about touch events;
Interpreting the data to see if it meets the criteria for any of gestures your app supports.
// 1、创建一个 GestureDetector 对象,并实现 OnGestureListener 接口。 GestureDetector gestureDetector = new GestureDetector(AnimationActivity.this, this); // 2、接管目标 View 的 onTouchEvent 方法, 在待监听 View 的 onTouchEvent 方法中添加实现 boolean consume = gestureDetector.onTouchEvent(event); return; consume;
OnGestureListener 接口的方法
onDrown : 手指轻轻触摸屏幕的瞬间,由一个 ACTION_DOWN 触发;
onShowPress : 手指轻触屏幕,尚未松开或者拖动, 由一个 ACTION_DOWN 触发;
onSingTapUp : 手指松开,由 ACTION_DOWN 触发, 这是单击行为;
onScroll: 手指按下屏幕并拖动,由一个 ACTION_DOWN , 多个 ACTION_MOVE 触发, 这是拖动行为;
onLongPress: 用户长久地按着屏幕不放,即长按;
onFling: 用户按下触摸屏,快速移动后松开,由一个 ACTION_DWON、多个 ACTION_MOVE 和一个 ACTION_UP 触发,快速滑动行为;
OnDoubleTapListener 接口中的方法
onDoubleTap: 双击,由两次连续的单击组成,不能和 onSingleTapConfirmed 共存;
onSingleTapConfirmed: 单击行为;
onDoubleEvent: 表示双击行为,在双击的期间, ACTION_DOWN、ACTION_MOVE、ACTION_UP 都不会触发此回调。
如果只是监听滑动相关的,可以在 onTouchEvent 方法中实现,如果要监听类似双击这样的行为,使用 GestureDetector.
Where or not you use GestureDetector.OnGesturelistener, it's best practive to implement onDraw() method that reture true. This is beacause all getstures begin with an OnDraw() message, if you reture false for onDraw(), the system assumes methods of GestureDetector.OnGestureListener never get called.
5.Scroller
用于实现 View 的弹性滑动
二、 View 的滑动
通过 View 本身提供的 srollTo/srollBy 方法来实现滑动;
通过动画给 View 施加平移效果来实现滑动;
通过改变 View 的 LayoutParams 使得 View 重新布局从而实现滑动。
1、使用 ScrollTo/ScrollBy
滑动过程是通过改变 View 的 mScrollX 和 mScrollY 的值,实现滑动。在滑动过程中, mScrollX 的值总是等于 View 左边缘和 View 内容左边缘在水平的距离。
ScrollTo/ScrollBy 只能改变 View 内容的位置,而不能改变 View 在布局中的位置。
2、使用动画
使用动画来移动 View, 主要是操作 View 的translationX 和 translationY 属性。
如果使用 View 动画滑动时, View 动画是对 View 的影响操作,它 并不能改变 View 的位置参数,包括宽高,如果希望动画后的状态得以保留,设置 fillAfter 为 true, 否则动画完成后其动画结果就会消失。
使用属性动画则无问题。
3、改变布局参数
即通过改变 LayoutParams.
例子:
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) mButton.getLayoutParams(); params.width +=100; params.leftMargin += 100; mButton.requestLayout(); // 或者 mButton.setLayoutParams(params);
三种滑动方式的比较
.scrollTo/scrollBy : 操作简单, 适合对 View 内容的滑动;
.动画:操作简单, 主要适用于没有交互的 View 和实现复杂的动画效果;
.改变布局参数:操作稍微复杂,适用于有交互的 View.
三、弹性滑动
实现弹性滑动的共同点,即将一次大的滑动分成若干次小的滑动,并在一个时间段内完成。
1、使用 Scroller
Scroller mScroller = new Scroller(mContext); // 缓慢滚动到指定的位置 private void smoothScrollTo(int destX, int destY){ int scrollX = getScrollX(); int deltaX = destX - scrollX; // 以 1000ms 内滑向 destX, 效果是慢慢滑动 mScroller.startScroll(scrollX, destY, deltaX , 0, 1000); // View 的重绘 invalidate(); } @Override public void computeScroll() { // 重写 computeScroll 方法,并在内部完成平滑滚动的逻辑 if (mScroller.computeScrollOffset()){ scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); // 再次进行重绘 postInvalidate(); } }
使用 Scroller 内部的整个流程
Scroller 的工作原理:
Scroller 本身不能实现 View 的滑动,它需要配合 View 的 computeScroll 方法才能完成弹性滑动的效果。通过不断地让 View 重绘,而每一次重绘距离滑动其实起始时间会有一个时间间隔,通过这个时间间隔 Scroller 得出 View 当前的滑动位置,知道了滑动位置就可以通过 scrollTo 方法完成 View 的滑动。 View 的每一次重绘都会导致 View 的小幅度滑动,而多次的小幅度滑动组成了弹性滑动,这就是 Scroller 滑动的工作机制。
Scroller 的使用步骤:
1、创建 Scroller 实例;
2、调用 startScroll(...) 方法来初始化滑动数据并刷新界面;
3、重写 computeScroll() 方法, 并在其内部完成滑动的逻辑。
可参考郭霖的博客http://blog.csdn.net/guolin_blog/article/details/48719871;
2、通过动画
通过属性动画
ObjectAnimatior.ofFloat(targetView, "translationX", 0, 100).setDuration(100).start();
通过 ValueAnimator,这里只是改变 Button 的内容
private void scroller(){ final int startX = 0; final int deltax = 1000; final ValueAnimator animator = ValueAnimator.ofInt(0, 1).setDuration(3000); animator.addUpdateListener(new ValueAnimator.AnimatorUpdateListener() { @Override public void onAnimationUpdate(ValueAnimator animation) { float fraction = animator.getAnimatedFraction(); mButton.scrollTo(startX +(int)(deltax * fraction), 0); } }); animator.start(); }3、使用延时策略
通过发送一系列的消息从而达到一种渐进式的效果,具体来说就是使用 Handler 或 View 的 postDelayed 方法,也可以使用线程的 sleep 方法。
四、 View 的事件分发机制
所谓点击事件的分发,其实就是对 MotionEvent 事件分发的过程,即当一个 MotionEvent 产
您可能想查找下面的文章:
- 在viewPager中双指缩放图片,双击缩放图片,单指拖拽图片,
- Android--实现ViewPager边界回弹效果(转),android--viewpager
- View控件中android:drawablePadding不起作用的原因探究,
- 对View的onMeasure()方法的进一步研究,viewonmeasure
- 订单流程view,订单view
- [Android] 使用ViewPager 实现导航,androidviewpager
- View的layout机制,Viewlayout机制
- android 同时setTag两次,保存多种值,androidsettag
- 深入理解 Android 之 View 的绘制流程,androidview
- Android View的绘制流程,androidview绘制