View的基础知识

来源:互联网 发布:程序员五阶段书单搞笑 编辑:程序博客网 时间:2024/05/18 03:29

1.什么是View


        View是Android中所有控件的基类,不管是简单的Button和TextView还是复条的RelativeLayout和ListView,它们的共同基类都是View。所以说,View是一种界面层的控件的一种抽象,它代表了一个控件。除了 View,还有ViewGroup,从名字来看,它可以被翻译为控件组,言外之意是ViewGroup内部包含了许多个控件,即一组View。在Android的设计中,ViewGroup也继承了 View,这就意味着View本身就可以是单个控件也可以是由多个控件组成的一组控件,通过这种关系就形成了 View树的结构。根据这个概念,我们知道,Button显然是个View,而LinearLayout不但是一个View而且还是一个ViewGroup, 而ViewGroup内部是可以有子View的,这个子View同样还可以是ViewGroup,依此类推。


2.View的位置参数


        View的位置主要由它的四个顶点来决定,分别对应于View的四个属性:top、left、right、bottom,其中top是左上角纵坐标,left是左上角横坐标,right是右下角横坐标,bottom是右下角纵坐标。需要注意的是,这些坐标都是相对于View的父容器来说的,因此它是一种相对坐标,View的坐标和父容器的关系如图所示。


我们很容易得出View的宽高和坐标的关系:

    • width = right - left
    • height = bottom - top
    • Left = getLeft():
    • Right = getRight();
    • Top = getTop;
    • Bottom = getBottom();
        从 Android3.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
       需要注意的是,View在平移的过程中,top和left表示的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x、y、translationX和translationY这四个参数。

3.MotionEvent 和 TouchSlop


  MotionEvent


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

  • ACTION_DOWN——手指刚接触屏幕;
  • ACTION_MOVE——手指在屏幕上移动;
  • ACTIONJJP——手机从屏幕上松开的一瞬间。

      正常情况下,一次手指触摸屏幕的行为会触发一系列点击事件,考虑如下几种情况:

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

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


  TouchSlop


       TouchSlop是系统所能识别出的被认为是滑动的最小距离,换句话说,当手指在屏幕上滑动时,如果两次滑动之间的距离小于这个常最,那么系统就不认为你是在进行滑动操作。原因很简单:滑动的距离太短,系统不认为它是滑动。这是一个常量,和设备有关,在不同设备上这个值可能是不同的,通过如下方式即可获取这个常量:ViewConfigumtion.get(getContext()).getScaledTouchSlop()。这个常量有什么意义呢?当我们在处理滑动时,可以利用这个常量来做一些过滤,比如当两次滑动事件的滑动距离小于这个值,我们就可以认为未达到滑动距离的临界值,因此就可以认为它们不是滑动,这样做可以有更好的用户体验。其实如果细心的话,可以在源码中找到这个常量的定义,frameworks/base/core/res/res/values/config.xml 文件中,如下所示。这个 “config_viewConfigurationTouchSlop” 对应的就是这个常量的定义。
<!-- Base "touch slop" value used by ViewConfiguration as a movement thresholdwhere scrolling should begin.--><dimen name="config_viewConfigurationTouchSlop">8dp</dimen>


4. VelocityTracker、GestureDetector 和 Scroller


VelocityTracker

       速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。它的使用过程很简单,首先,在View的onTouchEvent方法中追踪当前单击事件的速度:

VelocityTracker VelocityTracker = VelocityTracker.obtain();velocityTracker.addMovement(event);
       接着,当我们先知道当前的滑动速度时,这个时候可以采用如下方式来获得当前的速度:
velocityTracker.computeCurrentVelocity(1000);int xVelocity = (int) velocityTracker.getXVelocity();int yVelocity = (int) velocityTracker.getYVelocityO;

       在这一步中有两点需要注意,第一点,获取速度之前必须先计算速度,即getXVelocity和getYVelocity这两个方法的前面必须要调用computeCurrentVelocity方法;第二点,这里的速度是指一段时间内手指所滑过的像素数,比如将时间间隔设为1000ms时,在Is内,手指在水平方向从左向右滑过100像素,那么水平速度就是100。注意速度可以为负数,当手指从右往左滑动时,水平方向速度即为负值,这个需要理解一下。速度的计算可以用如下公式来表示:

速度=(终点位置-起点位置)/时间段


        根据上面的公式再加上Android系统的坐标系,可以知道,手指逆着坐标系的正方向滑动,所产生的速度就为负值。另外,computeCurrentVelocity这个方法的参数表示的是一个时间单元或者说时间间隔,它的单位是毫秒(ms),计算速度时得到的速度就是在这个时间间隔内手指在水平或竖直方向上所滑动的像素数。针对上面的例子,如果我们通过velocityTracker.computeCurrentVelocity(100)来获取速度,那么得到的速度就是手指在100ms内所滑过的像素数,因此水平速度就成了 10像素/每100ms (这里假设滑动过程是匀速的),即水平速度为10,这点需要好好理解一下。
        最后,当不需要使用它的时候,需要调用clear方法來重置并回收内存:
velocityTracker.clear ();velocityTracker.recycle();

GestureDetector 

      手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。要使用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中的方法了,这两个接口中的方法介绍如表所示。


方法名描述所属接口 onDown 手指轻轻触摸屏幕的一瞬间,由1个ACTI0N_D0WN触发 OnGestureListcner onShowPress 手指轻轻触携屏幕,尚未松开或拖动,由1个 ACTION_DOWN触发
 *注意和 onDownO的区别,它强调的是没有松开或者拖动的状态  OnGestureListcner onSingleTapUp 手指(轻轻触摸屏幕后)松开,伴随着1个MotionEvent ACTION_UP而触发,这是单击行为 OnGestureListcner onScroll 手指按下屏幕并拖动,由1个ACTION_DOWN,多个ACTION_MOVE触发,这是拖动行为 OnGestureListcner onLongPress 用户长久地按着屏幕不放,即长按 OnGestureListener onFling 用户按下触摸屏、快速滑动后松开,由1个ACTION_DOWN、多个ACTION_MOVE和1个ACTION_UP触发,这是快速滑动行为 OnGestureListener onDoubleTap 双击,由2次连续的单击组成,它不可能和onSingleTapConfirmed共存 OnDoubleTapListener onSingleTapConfirmed 严格的单击行为
 *注意它和onSingleTapUp的区別,如果触发了onSingleTapConfirmed,那么后面不可能再紧跟着另一个单击为, 即这只可能是单击,而不可能是双击中的一次单击 OnDoubleTapListener onDoubleTapEvent 表示发生了双击行为,在双击的期间,ACTION_DOWN、ACTION_MOVE和ACTION_UP都会触发此回调 OnDoubleTapListener
        表里面的方法很多,但是并不是所有的方法都会被时常用到,在日常开发中,比较常用的有:onSingleTapUp (单击)、onFling (快速滑动)、onScroll(拖动)、onLongPress(长按)和onDoubleTap (双击)。另外这里要说明的是,实际开发中,可以不使用GestureDetector,完全可以自己在View的onTouchEvent方法中实现所需的监听,这个就看个人的喜好了。这里有一个建议供读者参考:如果只是监听滑动相关的,建议自己在onTouchEvent中实现,如果要监听双击这种行为的话,那么就使用GestureDetector。

Scroller

        弹性滑动对象,用于实现View的弹性滑动。我们知道,当使用View的scrollTo/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 ();}@Overridepublic void computeScroll() {    if (mScroller.computeScroXlOffset()) {        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());        postlnvalidate();    }}


原创粉丝点击