美文网首页
View 的事件体系

View 的事件体系

作者: Yue_Q | 来源:发表于2018-10-12 15:46 被阅读0次

一 什么是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 的父容器来说是相对坐标

  1. 从 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

  1. MotionEvent:在手指接触屏幕后所产生一系列事件中,典型事件类型有如下几种:
       1. ACTION_DOWN:手指刚接触屏幕
       2. ACTION_MOVE:手指在屏幕上滑动
       3. ACTION_UP:手指从屏幕松开的一瞬间
    通过 MotionEvent 对象可以得到点击事件的 x,y 坐标。
       1. getX() / getY():当前 View 左上角的 x,y坐标。
       2. getRawX() / getRawY():相对于手机屏幕左上角的 x,y坐标。
  2. TouchSlop: 是系统所能识别出被认为滑动的最小距离,如果滑动距离小于常量:ViewConfiguration.get(getContext()).getScaledTouchSlop() 系统不认为是滑动。(frameworks/base/core/res/res/values/config.xml 中查看)
    MotionEvent 点击事件图解.png

(2) VelocityTracker,GestureDetector和 Scroller

  1. 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);
   }
  1. GesureDetector:手势检测,用于辅助检测用户的点击,滑动,长按,双击等行为。
    使用方法:首先,需要创建一个 GestureDetector 对象并实现 OnGestureListener 接口,根据需要我们还可以实现 OnDoubleTapListener 从而能够监听双击行为,接着,接管目标 View 的 onTouchEvent 方法,在待监听 View 的 onTouchEvent 方法中如下实现:
    boolean consum = mGestureDetector.onTouchEvent(event);
    (mGestureDetector.setIsLongpressEnabled(false); //解决长按屏幕后无法拖动的现象)
    以上接口方法介绍https://blog.csdn.net/b1480521874/article/details/53244801
  2. 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 的 translationXtranslationY 属性,可以采用传统 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

五 弹性滑动

    以上滑动比较生硬,用户体验差,因此可以使用弹性滑动,它的思想是:将一次大的滑动分成若干次小的滑动并在一个时间段内完成,可以通过 ScrollerHandler#postDelayed,以及 Thread#sleep 等。

  • (1). 使用 Scroller:原理如上 。
  • (2). 使用延迟策略:通过法送一系列延迟消息从而达到一种渐进式效果,可以使用 Handler 或 View 的 postDelayed 方法,也可以用 sheep.
  • (3). 使用属性动画:注意 3.0 一下版本兼容问题。

相关文章

网友评论

      本文标题:View 的事件体系

      本文链接:https://www.haomeiwen.com/subject/rflgaftx.html