美文网首页Android开发Android开发经验谈Android技术知识
Android开发艺术笔记 | View的事件体系

Android开发艺术笔记 | View的事件体系

作者: 凌川江雪 | 来源:发表于2020-03-22 15:06 被阅读0次

    View的概述

    • View是Android中所有控件的基类,
      不管是简单的Button和TextView还是复杂的RelativeLayout和ListView,
      它们的共同基类都是View
    • View是一种界面层的控件的一种抽象,它代表了一个控件。
    • ViewGroup内部可以包含许多个控件,即一组View。
      ViewGroup也继承了View,
      即View本身就可以是单个控件也可以是由多个控件组成的一组控件,
      通过这种关系就形成了View树的结构,
      这和Web前端中的DOM树的概念是相似的。

      上层的控件要负责测量与绘制下层的控件,并传递交互事件
      在每棵View树的顶部都存在着一个ViewParent对象,
      它是整棵View树的核心所在,
      所有的交互管理事件都由它来统一调度和分配
      从而对整个视图进行整体控制
    • Button显然是个View,
      而LinearLayout不但是一个View而且还是一个ViewGroup,
      而ViewGroup内部是可以有子View的,这个子View同样还可以是ViewGroup,依此类推。

    • 明白View的这种层级关系有助于理解View的工作机制。

    View的位置参数

    • Android坐标系:以屏幕的左上角为坐标原点,向右为x轴增大方向,向下为y轴增大方向。
    • View的位置主要由它的四个顶点来决定,
      分别对应于View的四个属性top、left、right、bottom
    • 其中top是左上角纵坐标,left是左上角横坐标,
      right是右下角横坐标,bottom是右下角纵坐标。
    • 注意这些坐标都是相对于View的父容器来说的,因此它是一种相对坐标
      View的坐标和父容器的关系如下图:

    根据上图,
    可以得出View的宽高坐标关系

        width = right - left
        height = bottom - top
    

    关于如何得到View的这四个参数
    View的源码中它们对应于mLeft、mRight、mTop和mBottom这四个成员变量,获取方式:

    Left=getLeft();
    Right=getRight();
    Top=getTop;
    Bottom=getBottom();
    ---
    width=getWidth();
    height=getHeight();
    
    • 从Android3.0开始,
      View增加了额外的几个参数:x、y、translationXtranslationY
      xyView左上角的坐标
      translationXtranslationYView左上角相对于父容器偏移量

    • 这几个参数也是相对于父容器的坐标!!!!
      并且translationXtranslationY默认值是0

      View也为它们提供了get/set方法,下面是这几个参数的关系

    x=left+translationX
    y=top+translationY
    
    • 注意,
      View平移的过程中,
      topleft表示的是原始左上角位置信息,其并不会发生改变!!!
      此时发生改变的是x、y、translationXtranslationY这四个参数!!!

    MotionEvent和TouchSlop

    1. MotionEvent

    • 手指接触屏幕后产生一系列事件中,
      典型的事件类型有如下几种:
      ACTION_DOWN——手指刚接触屏幕;
      ACTION_MOVE——手指在屏幕上移动;
      ACTION_UP——手机从屏幕上松开的一瞬间。

    • 正常情况下,
      一次手指触摸屏幕的行为会触发一系列点击事件;

    • 点击屏幕后离开松开,事件序列为DOWN -> UP
      点击屏幕滑动一会再松开,事件序列为DOWN -> MOVE -> … > MOVE -> UP

    • 上述是典型的事件序列,同时,
      通过MotionEvent对象,可以得到点击事件发生的x和y坐标
      为此,
      系统提供了两组方法:getX/getYgetRawX/getRawY
      区别:
      getX/getY返回的是相对于当前View左上角的x和y坐标,
      getRawX/getRawY返回的是相对于手机屏幕左上角的x和y坐标。

    2. TouchSlop

    • 概念:系统所能识别出被认为滑动最小距离
      即当手指在屏幕上滑动时,如果两次滑动之间的距离小于这个常量
      那么系统就不认为你是在进行滑动操作
      原因:滑动的距离太短,系统不认为它是滑动。

    • 这是一个常量,和设备有关,在不同设备上这个值可能是不同的,
      通过ViewConfiguration. get(getContext()).getScaledTouchSlop()可获取这个常量。

    • TouchSlop意义
      处理滑动时,可以利用这个常量来做一些过滤
      比如当两次滑动事件的滑动距离小于这个值
      我们就可以认为未达到滑动距离的临界值
      因此就可以认为它们不是滑动
      这样做可以有更好的用户体验!!!

    • 源码中有这个常量的定义,
      frameworks/base/core/res/res/values/config.xml文件中,如下所示。这个“config_viewConfigurationTouchSlop”对应的就是这个常量的定义。

     <!--Base "touch slop" value used by ViewConfiguration as a movement 
    threshold where scrolling should begin. -->
        <dimen name="config_viewConfigurationTouchSlop">8dp</dimen>
    

    VelocityTracker、GestureDetector和Scroller

    1. VelocityTracker

    概念:
    速度追踪,用于追踪手指滑动过程中速度
    包括水平和竖直方向的速度。

    使用过程:
    首先,在View的onTouchEvent方法中追踪当前单击事件速度

    VelocityTracker velocityTracker = VelocityTracker.obtain();//实例化一个VelocityTracker 对象
    velocityTracker.addMovement(event);//添加追踪事件
    
    • 接着在对ACTION_UP事件的处理中 获取当前的速度
      注意这里计算的是1000ms时间(即1s)间隔移动的像素值,
      假设像素是100,即速度是每秒100像素。
      在1s内,手指在水平方向从左向右滑过100像素,那么水平速度就是100。
      另外,如在水平方向上,
      手指逆着坐标系的正方向(从右往左滑动)滑动,所产生的速度为负值,
      顺着正反向(从左往右滑动)滑动,所产生的速度为正值。
    velocityTracker .computeCurrentVelocity(1000);//获取速度前先计算速度,这里计算的是在1000ms内
    float xVelocity = velocityTracker .getXVelocity();//得到的是1000ms内手指在水平方向从左向右滑过的像素数,即水平速度
    float yVelocity = velocityTracker .getYVelocity();//得到的是1000ms内手指在垂直方向从上向下滑过的像素数,即垂直速度
    
    • 注意,
      获取速度之前必须先计算速度,
      getXVelocitygetYVelocity这两个方法的前面
      必须要调用computeCurrentVelocity方法;!!

    • 速度的计算可以用如下公式来表示:
      速度=(终点位置-起点位置)/时间段

    • computeCurrentVelocity()的方法参数表示的是
      一个时间单元或者说时间间隔单位是毫秒(ms)
      计算速度时得到的速度
      就是在这个时间间隔内
      手指在水平或竖直方向上所滑动的像素数。

    针对上面的例子,
    如果我们通过velocityTracker.computeCurrentVelocity(100)来获取速度,
    那么得到的速度就是手指在100ms内所滑过的像素数,
    假设返回的是10,
    则水平速度就成了10像素/每100ms(这里假设滑动过程是匀速的),
    即水平速度为10。

    • 最后不需要使用它时,需调用clear方法来重置,并回收内存:
        velocityTracker.clear();
        velocityTracker.recycle();
    

    GestureDetector

    概念:手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。

    使用过程:
    首先,
    需要创建一个GestureDetector对象
    并实现OnGestureListener接口
    根据需要还可以实现OnDoubleTapListener从而能够监听双击行为:!!!

        GestureDetector  mGestureDetector = new GestureDetector(this);
        //解决长按屏幕后无法拖动的现象
        mGestureDetector.setIsLongpressEnabled(false);
    

    接着,
    接管目标View的onTouchEvent方法,
    在待监听View的onTouchEvent方法中添加如下实现:

        boolean consume = mGestureDetector.onTouchEvent(event);
        return consume;
    

    做完以上两步后,
    即可有选择地实现OnGestureListenerOnDoubleTapListener中的方法了,
    这两个接口中的方法介绍如下表:

    • 实际开发中,
      可以不使用GestureDetector,
      可以自己在View的onTouchEvent方法中实现所需的监听,看个人的喜好。
      建议,
      如果只是监听滑动相关的,建议自己在onTouchEvent中实现,
      如果要监听双击这种行为的话,那么就使用GestureDetector。

    Scroller

    概念:弹性滑动对象,用于实现View的弹性滑动。

    • 当使用ViewscrollTo/scrollBy方法来进行滑动时,
      过程瞬间完成的,
      这个没有过渡效果滑动 用户体验不好。

      此时可使用Scroller来实现有过渡效果的滑动
      其过程不是瞬间完成的,
      而是在一定的时间间隔内完成的。

    • Scroller本身无法让View弹性滑动
      它需要和View的computeScroll方法配合使用才能完成这个功能。

    使用Scroller,其典型代码是固定的:

        Scroller scroller = new Scroller(mContext);
        // 缓慢滚动到指定位置
        private void smoothScrollTo(int destX,int destY) {
            int scrollX = getScrollX();
            int delta = destX -scrollX;
            // 1000ms内滑向destX,效果就是慢慢滑动
            mScroller.startScroll(scrollX,0,delta,0,1000);
            invalidate();
        }
        @Override
        public void computeScroll() {
            if (mScroller.computeScrollOffset()) {
                    scrollTo(mScroller.getCurrX(),mScroller.getCurrY());
                    postInvalidate();
            }
        }
    








    参考:

    相关文章

      网友评论

        本文标题:Android开发艺术笔记 | View的事件体系

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