专栏首页李蔚蓬的专栏Android开发艺术笔记 | View的事件体系

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

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();
        }
    }

参考:

本文参与腾讯云自媒体分享计划,欢迎正在阅读的你也加入,一起分享。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • Android开发艺术笔记 | View的滑动(三种普遍实现方式及其对比、实战)

    View提供了专门的方法来实现滑动, 即scrollTo()和scrollBy(),这两个方法的实现如下:

    凌川江雪
  • 自定义控件基础 之 3.4 ViewGroup的测量 & 3.5 ViewGroup的绘制

    之前分析中说了,ViewGroup会去管理其子View,其中一个管理项目就是负责子View的显示大小。当ViewGroup的大小为wrap_content时,V...

    凌川江雪
  • 设计模式 | MVC、MVP、MVVM详析

    凌川江雪
  • 教你步步为营掌握自定义 View

    国内自定义View的文章汗牛充栋,但是,即使你全部看完它们也未必能掌握这一知识点(实际上,我就几乎看完了所有的国内文章)。为什么?一言以蔽之,你是得其术不明其道...

    非著名程序员
  • View绘制系列(2)-View生命周期

    了解C++的小伙伴们肯定都听过构造函数和析构函数这两个名词,通过构造函数我们可以生成一个类对象,通过析构函数我们可以完成一个对象的销毁,那么对于同样面对对象的J...

    小海编码日记
  • View详解(1)

    好久好久没更新了,不知道大家还有没有在看以前的一些博文,这段时间换了个坑位还是有点小忙呢!鉴于最近工作接触自定义View,Canvas比较多,所以打算开个系列,...

    小海编码日记
  • 自定义View基础 - 最易懂的自定义View原理系列(1)

    对于多View的视图,结构是树形结构:最顶层是ViewGroup,ViewGroup下可能有多个ViewGroup或View,如下图:

    Carson.Ho
  • SAP CDS view里,什么时候用left join,什么时候用association

    版权声明:本文为博主汪子熙原创文章,未经博主允许不得转载。 https://jerry.bl...

    Jerry Wang
  • SAP CDS view里association和join的区别

    Association它指明了两个View之间的关系,如果一个View A中定义了Association到另外一个View B时,View A可以把这个Asso...

    Jerry Wang
  • Android:你要了解的自定义View基础概念都在这里了!

    自定义View原理是Android开发者必须了解的基础,在了解自定义View之前,你需要有一定的知识储备。

    Android技术干货分享

扫码关注云+社区

领取腾讯云代金券