Android

View基础知识(一)

2019-03-29  本文已影响2人  12313凯皇

一、什么是View

ViewAndroid中所有控件的基类,不管是简单的ButtonTextView还是复杂的RelativeLayoutListView,它们共同的基类都是View

View是一种界面层的控件的一种抽象,它代表了一个控件。除了View,还有ViewGroup,即控件组。在Android的设计中,ViewGroup也继承了View,这就意味着View本身可以是单个控件也可以是由多个控件组成的一组控件,通过这种关系就形成了View树的结构,和Web前端中的DOM树的概念是相似的。

二、View的位置参数

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

View的位置坐标和父容器的关系
根据上图,我们很容易得出View的宽高和左边的关系:

width = right - left
htight = bottom - top

Android 3.0开始,View增加了额外的几个参数:xytranslationXtranslationY,其中xyView左上角的坐标,而translationXtranslationYView左上角相对于父容器的偏移量。这几个参数也是相对于父容器的坐标,并且translationXtranslationY的默认值为0,和View的四个基本的位置参数一样,View也为它们提供了get/set方法,这几个参数的换算关系如下所示:

x = left + translationX
y = top + translationY

需要注意的是,View在平移的过程中,topleft表示的是原始左上角的位置信息,其值并不会改变,此时发生改变的xytranslationXtranslationY这四个参数。

三、MotionEvent和TouchSlop

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

    • ACTION_DOWN --- 手指刚接触屏幕。
    • ACTION_MOVE --- 手指在屏幕上移动。
    • ACTION_UP --- 手指从屏幕上松开的一瞬间。

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

    • 点击屏幕后离开,事件序列为DOWN -> UP
    • 点击屏幕滑动一会再松开,事件序列为DOWN -> MOVE -> ...> MOVE -> UP
      上述三种情况是典型的事件序列,同时通过MotionEvent对象我们可以得到点击事件发生的xy坐标。为此,系统提供了两组方法:getX/getYgetRawX/getRawYgetX/getY返回的是相对于当前View左上角的xy坐标,而getRawX/getRawY返回的是相对于手机屏幕左上角的xy坐标。
  2. TouchSlop
    TouchSlop是系统所能识别出的被认为是滑动的最小距离,换句话说,当手指在屏幕上滑动时,如果两次滑动之间的距离小于这个常量,那么系统就不认为你是在进行滑动操作。TouchSlop是一个常量,和设备有关,在不同设备上的之可能是不同的,通过ViewConfiguration.get(getContext()).getScaledTouchSlop()即可获取这个常量。

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

    Android源码的res/values/config.xml中,可以找到这个常量的定义:

    <!-- 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
    速度追踪,用于追踪手指在滑动过程中的速度,包括水平和竖直方向的速度。它的使用过程很简单,首先,在ViewonTouchEvent方法中追踪当前单击速度的速度:

    VelocityTracker velocityTracker = VelocityTracker.obtain();
    velocityTracker.addMovement(event);
    

    接着,当我们想知道当前的滑动速度时,这个时候可以采用如下方式来获得当前的速度:

    velocityTracker.computeCurrentVelocity(1000);
    int xVelocity = (int) velocityTracker.getXVelocity();
    int yVelocity = (int) velocityTracker.getYVelocity();
    

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

    • 第一点,获取速度之前必须先计算速度,即getXVelocitygetYVelocity这两个方法的前面必须调用computeCurrentVelocity方法。
    • 第二点,这里的速度是指一段时间内手指所滑动的像素数,比如将时间间隔设为1000ms时,在1s内,手指在水平方向从左向右滑动100像素,那么水平速度就是100。

    注意速度可以为负数,当手指从右往左滑动时,水平方向速度即为负值。速度的计算可以用如下公式来表示:

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

    根据上面的公式再加上Android系统的坐标系,可以知道,手指逆着坐标系的正方向滑动,所产生的的速度就为负值。另外computeCurrentVelocity这个方法的参数表示的是一个时间单元或者说时间间隔,它的单位是毫秒(ms),计算速度时得到的速度就是在这个时间间隔内手指在水平或垂直方向上所滑动的像素块。

    最后,当不需要使用它的时候,需要调用clear方法来重置并回收内存:

    velocityTracker.clear();
    velocityTracker.recycle();
    
  2. GestureDetector
    手势检测,用于辅助检测用户的单击、滑动、长按、双击等行为。下面简单的讲解一下如何使用GestureDetector

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

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

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

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

    做完了上面这步,我们就可以有选择性地实现onGestureListeneronDoubleTapListener中的方法了,这两个接口中的方法介绍如下表所示:

    方法名 描述 所属接口
    onDown 手指轻轻触摸屏幕的一瞬间,由1个ACTION_DOWN触发 onGestureListener
    onShowPress 手指轻轻触摸屏幕,尚未松开或拖动,由1个ACTION_DOWN触发 * 注意与onDown()的区别,它强调的是没有松开或者拖动的状态 onGestureListener
    onSingleTapUp 手指(轻轻触摸屏幕后)松开,伴随着1个MotionEvent ACTION_UP而触发,这是点击行为 onGestureListener
    onScroll 手指按下屏幕并拖动,由1个ACTION_DOWN,多个ACTION_MOVE触发,这是拖动行为 onGestureListener
    onLongPress 用户长久的按着屏幕不放,即长按 onGestureListener
    onFling 用户按下触摸屏,快速滑动后松开,有1个ACTION_DOWN、多个ACTION_MOVE和1个ACTION_UP触发,这是快递滑动行为 onGestureListener
    onDoubleTap 双击,由2次连续的单击组成,它不可能和onSingleTapConfirmed共存 onDoubleTapListener
    onSingleTapConfirmed 严格的单击行为 *主要它和onSingleTapUp的区别,如果触发了onSingleTapConfirmed,那么后面不可能再紧跟着另一个单击行为,即这只可能是单击,而不可能是双击中的一次单击 onDoubleTapListener
    onDoubleTapEvent 表示发生了双击行为,在双击的期间,ACTION_DOWNACTION_MOVEACTION_UP都会触发此回调 onDoubleTapListener

    表中方法很多,但并不是所有的方法都时常被用到,在日常开发中,比较常用的有:onSingleTapUp(单击)、onFling(快速滑动)、onScroll(拖动)、onLongPress(长按)和onDoubleTap(双击)。

    另外,在实际开发中,可以不使用GestureDetector,完全可以自己在ViewonTouchEvent方法中实现所需的监听。如果只是监听滑动相关的建议就在onTouchEvent中实现,如果要监听双击这种行为的话,那么就使用GestureDetector

  3. Scroller
    弹性滑动对象,用于实现View的弹性滑动。我们知道,当使用ViewscrollTo/scrollBy方法来进行滑动时,其过程是瞬间完成的,这个没有过渡效果的滑动用户体验不好。这是就可以使用Scroller啦实现有过渡效果的滑动,其过程不是瞬间完成的,而是在一定的时间间隔内完成的。

    Scroller本身无法让View弹性滑动,它需要和ViewcomputeScroll方法配合使用才能共同完成这个功能,下面是实现的典型代码:

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

猜你喜欢

热点阅读