一 什么是View
View是 Android 中所有控件的基类,除了 View 还有 ViewGroup ,ViewGroup 内部包含了许多控件,ViewGroup 也继承 View, 所以 View 是单个控件或者一组控件,通过这种关系形成树形结构。例如 LinearLayout 不但是一个 View 同时也是 ViewGroup 。
二 View 的位置参数
1.View 有四个属性:top,left,right,bottom。
1. top:左上角纵坐标, Top = getTop()
2. left:左上角横坐标, Left = getLeft()
3. right:右下角横坐标, Right = getRight()
4. bottom:右下角纵坐标, Bottom = getBottom()
注意:这些坐标都是相对于 View 的父容器来说是相对坐标。
- 从 Android 3.0 开始,View 增加了额外的几个参数:x,y,translationX,translationY。
1. (x , y): View 左上角的坐标。
2. (translationX , translationY) : View 左上角相对于父容器的偏移量。
注意: View在平移的过程中,top 和 left 原始左上角的位置信息不会改变, 改变的是x,y,translationX,translationY。
View 的位置坐标与父容器的关系.png
三 (1) MotionEvent 和 TouchSlop
- MotionEvent:在手指接触屏幕后所产生一系列事件中,典型事件类型有如下几种:
1. ACTION_DOWN:手指刚接触屏幕
2. ACTION_MOVE:手指在屏幕上滑动
3. ACTION_UP:手指从屏幕松开的一瞬间
通过 MotionEvent 对象可以得到点击事件的 x,y 坐标。
1. getX() / getY():当前 View 左上角的 x,y坐标。
2. getRawX() / getRawY():相对于手机屏幕左上角的 x,y坐标。- TouchSlop: 是系统所能识别出被认为滑动的最小距离,如果滑动距离小于常量:
ViewConfiguration.get(getContext()).getScaledTouchSlop()
系统不认为是滑动。(frameworks/base/core/res/res/values/config.xml 中查看)
MotionEvent 点击事件图解.png
(2) VelocityTracker,GestureDetector和 Scroller
- VelocityTracker: 用于追踪手指滑动中的速度,包括水平速度与垂直速度。首先,在View 的 onTouchEvent 方法中追踪当前单击事件速度。
使用方法如下:@Override public boolean onTouchEvent(MotionEvent ev) { //追踪 ev 点击事件 VelocityTracker velocityTracker = VelocityTracker.obtain();//创建对象 velocityTracker.addMovement(ev); //得到当前滑动速度 // 速度 = (终点位置 - 起点位置)/ 时间段 velocityTracker.computeCurrentVelocity(1000); //时间间隔(ms) 1000ms = 1 秒 int xVelocity = (int) velocityTracker.getXVelocity(); //获得水平速度 int yVelocity = (int) velocityTracker.getXVelocity(); //获得垂直速度 velocityTracker.clear(); //重置 velocityTracker.recycle(); //回收内存 return super.onTouchEvent(ev); }
- GesureDetector:手势检测,用于辅助检测用户的点击,滑动,长按,双击等行为。
使用方法:首先,需要创建一个 GestureDetector 对象并实现 OnGestureListener 接口,根据需要我们还可以实现 OnDoubleTapListener 从而能够监听双击行为,接着,接管目标 View 的 onTouchEvent 方法,在待监听 View 的 onTouchEvent 方法中如下实现:
boolean consum = mGestureDetector.onTouchEvent(event);
(mGestureDetector.setIsLongpressEnabled(false); //解决长按屏幕后无法拖动的现象)
以上接口方法介绍:https://blog.csdn.net/b1480521874/article/details/53244801- Scroller:弹性滑动对象,实现 View 的弹性滑动,当使用 View 的 scrollTo/scrollBy 方法滑动,过程是瞬间完成,使用 Scroller 实现有过度效果的滑动。
invalidate()
:用于 UI 线程更新 View 界面。
postInvalidate()
:用于 非UI 线程更新 View 界面,底层利用 Handler + invalidate() 。
使用方法如下:private void smoothScrollTo(int x, int y){ int scrollX = getScrollX(); int delta = x - scrollX; // 1000ms 内滑向 destX, 效果慢慢滑动; mScroller.startScroll(scrollX, 0, delta, 1000); //保存传递参数 invalidate();//这里必须调用invalidate()才能保证computeScroll()会被调用,否则不一定会刷新界面,看不到滚动效果 } @Override public void computeScroll() { if (mScroller.computeScrollOffset()){ scrollTo(mScroller.getCurrX(), mScroller.getCurrY()); postInvalidate(); } }
原理:
mScroller.startScroll(scrollX, 0, delta, 1000);
它只是保存了我们传递的参数,invalidate();
方法会导致 View 重绘,在 View 的 draw 方法中会调用computeScroll()
,computeScroll()在 View 中是空实现,因此我们重写了它,computeScrollOffset()
根据时间流逝计算出 scrollX 和 scrollY 的值,computeScroll() 会向 Scroller 获取当前的 scrollX 和 scrollY,通过 scrollTo() 方法实现滑动,接着会调用postInvalidate()
; 再次重绘 View ,还会调用 computeScroll(),如此反复,知道整个滑动结束。
四 View 的滑动
实现 View 滑动的三种方法:
1. View 本身提供的 scrollTo/scrollBy 方法。
2. 通过动画给 View 施加平移效果来实现滑动。
3. 通过改变 View 的 LayoutParams 使得 View 重新布局从而实现滑动。
(1)使用 scrollTo/scrollBy:
scrollTo:实现的绝对滑动,通过改变 mScrollX 与 mScrollY 这两个属性。如下图解
scrollBy:实现基于所传的参数相对滑动,从源码角度,scrollBy 实际上还是调用了 scrollTo
mScrollX和mScrollY 的变化规律示意.png
(2)使用动画:使用动画滑动 View ,主要操作 View 的 translationX 和 translationY 属性,可以采用传统 View 的动画,也可以采用属性动画,如果用属性动画为了能够兼容 3.0 以下的版本,需要采用开源动画库mineoldandroid
(http://nineoldandroids.com/) 。
注意:使用这两个方法只是对 View 的影像位置的改变,并没有真正改变 View 的位置参数(例如:在移动影像上不能触发onClick
事件)。可以通过设置fillAfter
属性,为 false 时动画完成后会消失。
- View 动画:使用 XML 文件的 tanslate 标签设置相关属性。
- 属性动画:在代码中设置,改变了动画的属性,在 Android 3.0 以下本质仍是 View 动画。
例如: ObjectAnimator.ofFloat(targetView, "translationX", 0, 100).setDuration(100).start() 。(3)改变布局参数:
改变 LayoutParams 的marginLeft,width 等参数。MarginLayoutParams params = (MarginLayoutParams )mButton.getLayoutParms(); params.width += 100; params.leftMargin +=100; mButton.requestLayout(); //或者 mButton.setLayoutParams(params)
(4)总结:
- scrollTo/scrollBy:操作简单,适合对 View 内容的滑动;
- 动画:操作简单,主要适用于没有交互 View 和实现复杂效果;
- 改变布局参数:操作稍负责,适用于有交互的 View
五 弹性滑动
以上滑动比较生硬,用户体验差,因此可以使用弹性滑动,它的思想是:将一次大的滑动分成若干次小的滑动并在一个时间段内完成,可以通过
Scroller
,Handler#postDelayed
,以及Thread#sleep
等。
- (1). 使用 Scroller:原理如上 。
- (2). 使用延迟策略:通过法送一系列延迟消息从而达到一种渐进式效果,可以使用 Handler 或 View 的 postDelayed 方法,也可以用 sheep.
- (3). 使用属性动画:注意 3.0 一下版本兼容问题。
网友评论