Android View 基础知识

来源:互联网 发布:汉密尔顿 知乎 喜剧 编辑:程序博客网 时间:2024/05/20 18:03

我们先来看一下 Android 官方是如何介绍 View 的:

        This class represents the basic building block for user interface components. A View occupies a rectangular area on the screen and is responsible for drawing and event handling. View is the base class for widgets, which are used to create interactive UI components (buttons, text fields, etc.). The ViewGroup subclass is the base class for layouts, which are invisible containers that hold other Views (or other ViewGroups) and define their layout properties.

      大概意思是这样:这个类表示用户界面组件的基本构建块。视图在屏幕上占据一个矩形区域,负责绘图和事件处理。视图是小部件的基类,用于创建交互式 UI 组件(按钮、文本字段等),ViewGroup 类布局的基础课,它是看不见的容器持有其它 View(或其他viewgroup)并确定其布局属性。


       View 是 Android 体系中一个非常重要的概念,虽然说 View 不属于四大组件,但是它的作用确比四大组件中的 Broadcast Receiver、Content Provider 的重要性都要大,在我们的实际开发中,Activity 承载着可视化的功能,同时 Android 系统提供了很多控件,有基本的 TextView、Button 等,但是往往很多时候系统提供的控件在实际开发中并不能很好地满足我们的需求,这样就需要我们去自定义能满足需求的组件,这就要求我们对 View 的基础知识必须掌握,并且慢慢达到深入的理解,接下来我们开始介绍 View 的基础知识


一、View 是什么


       在实际开发中我们每天都在使用 View,几乎每天提到 View,那么 View 到底是什么,通过上面的官方文档我们便可见一般,View 是 Android 中所有空间的基类,不管是简单的 TextView 和 Button 还是复杂的几大常用布局 LinearLayout、RelativeLayout 或 ListView、RecyclerView,他们的基类都是 View,所以说 View 是一种界面层的控件的一种抽象,它代表了一个控件,除了 View 还有 ViewGroup,就是控件的组合,也就是说 ViewGroup 内部包含了很多个控件,即一组 View, ViewGroup 也继承于 View,这就是说 View本身就可以是单个控件,也可以是由多个控件组成的一个控件组,根据这些概念,我们现在显然能知道我们平时在开发中的 TextView、Button 是个 View, 而 LinearLayout、RelativeLayout 不但是个 View, 同样也是一个 ViewGroup 等等,以此类推,理解 View 的这种层级关系有助于我们理解 View 的工作机制


二、View 的位置参数


       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();
从 Android 3.0 开始,View 增加了额外的几个参数:x、y、translationX 和 translationY,其中 x、y 是 View 左上角的坐标,而 translationX 和 translationY 是 View 左上角相对于父容器的偏移量,这几个参数也是相对于父容器的坐标,并且 translationX 和 translationY 的默认值是 0,和 View 的四个基本的位置参数一样,View 也为它们提供了 get/set 方法,这几个参数的换算关系如下所示:
  • x = left + translationX
  • y = top + translationY

三、MotionEvent 和 TouchSlop


MotionEvent


在手指接触屏幕后所产生的一系列事件中,典型的事件类型有如下几种:

  • ACTION_DOWN------手指刚接触屏幕
  • ACTION_MOVE------手指在屏幕上移动
  • ACTION_UP------手指从屏幕上松开的一瞬间
正常情况下,一次手指触摸屏膜的行为会触发一系列的点击事件,需要考虑如下几中情况:
  • 点击屏膜后离开松手,事件序列为 DOWN -> UP
  • 点击屏膜滑动一会儿再松开,事件序列为DOWN -> MOVE -> ...... MOVE -> UP
       上述两种情况是典型的事件序列,同时通过 MotionEvent 对象我们可以得到点击事件发生的 x 和 y 坐标,为此,系统提供了两组方法:getX/getY  和  getRawX/getRawY。它们的区别其实很简单,getX/getY 返回的是相对于当前的 View 左上角的 x 和 y 坐标,而 getRawX/getRawY 返回的是相对手机屏幕左上角的 x 和 y 坐标

TouchSlop

       TouchSlop 是系统所能识别出的被认为是滑动的最小距离,换句话说,当手指在屏幕上移动时如果滑动的距离小于这个常量,那么系统就认为你不是在进行滑动操作,原因很简单,滑动的距离太短,体统认为它不是在滑动,这是一个常量,和设备有关,在不同的设备上这个值可能是不同的,通过如下方式获取这个常量:
ViewConfiguration.get(getContext().getScaledTouchSlop())。那么这个常量有什么意义呢?当我们在处理滑动时,可以利用这个常量来做一些过滤,比如当两次滑动事件的滑动距离小于这个值,我们就可以认为没有达到滑动距离的要求,因此就可以认为它没有滑动,这样做有更好的用户体验


四、VelocityTracker、GestureDetector

VelocityTracker

速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度,它的使用过程比较简单,首先在 View 的 onTouchEvent 方法中追踪当前单击事件的速度:
VelocityTracker velocityTracker = VelocityTracker.obtain();velocityTracker.addMovement(event);
接着,当我们想知道当前的滑动速度时,这个时候可以采用如下方法来获得当前的速度:
velocityTracker.computeCurrentVelocity(1000);int xVelocity = (int) velocityTracker.getXVelocity();int yVelocity = (int) velocityTracker.getYVelocity();

在这一步中有两点需要注意:

第一点:获取速度之前必须先计算速度,即 getXVelocity 和 getYVelocity 这两个方法的前面必须要调用 computeCurrentVelocity() 方法
 
第二点:这里的速度是指一段时间内手指所划过的像素数,比如将时间间隔设为 1000ms 时,在 1s 内,手指在水平方向从左向右滑过100 像素,那么水平速度就是 100,注意速度可以为负数,当手指从右往左滑动时,水平方向速度即为负值,这个需要理解一下,速度的计算可以用如下公式来表示:
  • 速度 =(终点位置 - 起点位置)/ 时间段
       根据上面的公式再加上 Android 系统的坐标,可以知道,手指逆着坐标系的正方向滑动,所产生的速度就为负值,另外,computeCurrentVelocity() 这个方法的参数表示的是一个单元时间或者说时间间隔,它的单位是毫秒(ms),计算速度时得到的速度就是在这个时间间隔内手指在水平或竖直方向上所滑动的像素数,针对上面的例子,如果我们通过
velocityTracker.computeCurrentVelocity(100) 来获取速度,那么得到的速度就是手指在 100ms 内所滑过的像素数,因此水平速度就成了 10 像素/每 100ms,即水平速度为 10

最后,当不需要使用它的时候,需要调用 clear() 方法来重置并回收内存:
velocityTracker.clear();velocityTracker.recycle();
上面就是如何使用 VelocityTrackr 对象的全过程

GestureDetector

手势测试,用于辅助用户的单击、滑动、长按、双击等行为,参考过程如下:
首先,需要创建一个 GestureDetector 对象并实现 OnGestureListener 接口,根据需要我们还可以实现 OnDoubleTapListener 从而能够监听双击行为:

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

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

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

       做完上面两步,我们就可以有选择的实现 OnGestureListener 和 OnDoubleTapListener 中的方法了,OnGestureListener 和 OnDoubleTapListener 这两个接口的方法中比较常用的有:
  • onSingleTapUp() ---- 单击
  • onFling() ---- 快速滑动
  • onScroll() ---- 拖动
  • onLongPress() ---- 长按
  • onDoubleTop() ---- 双击
       另外需要说明的是在实际开发中可以不使用 GestureDetector,完全可以自己在 View 的 onTouchEvent 方法中实现所需要的监听,这里建议:如果只是监听滑动相关的,建议自己在 onTouchEvent 方法中实现,如果要监听双击这种行为的话,那么就使用 GestureDetector



1 0
原创粉丝点击