Android开发进阶—Android中的View

1.什么是View?

       View是Android中所有控件的基类,不论是简单的Button还是较为复杂的ListView或者LinearLayout,它们的共同基类都是View。所以说Android中的View是一种界面层的控件的一种抽象。除了View以外还有ViewGroup,从字面意义上来看它是控件组的意思,也就是说它的内部可以包含许多的控件,其实ViewGroup也是继承自View,这就意味这View本身可以是单个控件,也可以是由多个控件组成的控件组。通过这样一系列的关系就形成了View树的结构,如下图所示。

       

       根据上面View树的图示可以知道,ViewGroup内部是可以有子View也可以有ViewGroup,而View内部没有子View。明白了以上的View的这种层级关系有利于让我们理解View的工作机制和View的事件分发机制。

2.View的位置参数

       View的位置参数主要由它的四个顶点来决定,分别对应于它的四个属性(top、bottom、left、right),其中top表示当前View的上边界距父容器的距离也就是View的左上角的纵坐标,bottom表示当前View的下边界距父容器的距离也就是View的右下角的纵坐标,left表示当前View的左边界距父容器的距离也就是View的左上角的横坐标,right表示当前View的右边界距父容器的距离也就是View的右下角的横坐标,入下图所示。

       

       由上图可以看到,在Android中X轴和Y轴的正方向分别是向右和向下,并且我们可以根据View的这四个属性很容易的得到它的高和宽

width = right - left
height = bottom - top

       可以通过下面的四个方法,分别获取View的这四个属性

top = getTop();
bottom = getBottom();
left = getLeft();
right = getRight();

      了解Android动画的同学应该知道,在Android3.0之前是不能用属性动画的,只能用补间动画,而补间动画所做的动画效果只是将View的显示转为图片,然后再针对这个图片做透明度、平移、旋转、缩放等效果。这带来的问题是,View所在的区域并没有发生变化,变化的只是个“幻影”而已。也就是说,在Android 3.0之前,要想将View区域发生变化,就得改变top、left、right、bottom。如果我们想让View的动画是实际的位置发生变化,并且要兼容3.0之前的软件,该怎么办呢?为了解决这个问题,从3.0开始,加了几个新的参数:x、y、translationX、translationY。

       x和y分别表示View的左上角坐标,translationX和translationY是View左上角相对于父容器的偏移量,这四个参数都是相对于父容器的偏移量,并且translationX和translationY的默认值为0,其中x、y、translationX、translationY的关系如下。

x = left + translationX
y = right + translationY

       需要注意的是,在View平移的过程中,top和left表示的是原始左上角的位置信息,其值并不会改变,此时会改变的是x、y、translationX、translationY这四个参数。

3.MotionEvent和TouchSlop

(1)MotionEvent

       MotionEvent即为移动事件,我们都知道,每个触摸事件或者滑动事件都代表用户在屏幕上的一个动作,而每个动作必定有其发生的位置,在MotionEvent中就有手指接触屏幕后所产生的一系列事件。

ACTION_DOWN — 手指刚接触屏幕

ACTION_MOVE — 手指在屏幕上移动

ACTION_UP — 手指离开屏幕

       在正常情况下,一次手指与屏幕的交互会生成一系列的事件,主要考虑一下两种情况:

点击屏幕后松开 — 事件包括一个ACTION_DOWN和一个ACTION_UP

点击屏幕滑动一段距离再松开 — 事件包括一个ACTION_DOWN、多个ACTION_MOVE和一个ACTION_UP

       同时在通过MotionEvent对象我们可以得到点击事件发生的x、y的值,为此系统为我们提供了两组方法来得到x和y的值,包括getX/getY和getRawX/getRawY,它们之间的区别很简单,getX/getY的返回值是相对于当前View左上角的x和y坐标,而getRawX/getRawY的返回值是相对于手机屏幕左上角的x和y坐标,入下图所示。

       

(2)TouchSlop

       TouchSlop指的是系统能够被识别出的最小滑动距离,也就是说只有手指在屏幕上滑动的距离大于TouchSlop这个常量系统才认为进行了滑动操作,否则系统就不认为你是在进行滑动操作。TouchSlop的值是一个常量,和设备有关,在不同的设备中这个值有可能是不一样的,可以通过如下方式获取这个常量:ViewConfiguration.get(context).getScaledTouchSlop(),同时也可以通过源码获取这个常量的值,如下所示。

    /**
     * Distance a touch can wander before we think the user is scrolling in dips.
     * Note that this value defined here is only used as a fallback by legacy/misbehaving
     * applications that do not provide a Context for determining density/configuration-dependent
     * values.
     *
     * To alter this value, see the configuration resource config_viewConfigurationTouchSlop
     * in frameworks/base/core/res/res/values/config.xml or the appropriate device resource overlay.
     * It may be appropriate to tweak this on a device-specific basis in an overlay based on
     * the characteristics of the touch panel and firmware.
     */
    private static final int TOUCH_SLOP = 8;

       TOUCH_SLOP就是TouchSlop的值。

4.VelocityTracker

       我们知道,很多ViewGroup中,假设手指滑动的距离相同,但是滑动速度不同,那么滑动速度越快,ViewGroup中内容滚动的距离越远。那么如何识别用户滑动的速度呢?当然了,你可以在onTouchEvent中不断的监听计算,但是那样的代码太臃肿了,而且容易算错,好在Android系统内置了速度追踪类VelocityTracker,有了它我们就不用担心如何计算速度追踪了。

       首先需要在View的onTouchEvent方法中追踪当前单击事件的速度

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

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

vt.computeCurrentVelocity(1000);
int xv = (int) vt.getXVelocity();
int yv = (int) vt.getYVelocity();
       这里设置的时间间隔为1000ms,很显然,速度的计算为(终端位置-起始位置) / 间隔时间,最后,当不需要使用它的时候,需要调用clear方法来重置并且回收内存

vt.clear();
vt.recycle();

5.GestureDetector

       手势检测用于辅助检测用户的单击、滑动、长按、双击等行为,首先需要创建一个GestureDetector的对象并且实现OnGestureListener接口

GestureDetector.OnGestureListener listener = new GestureDetector.OnGestureListener() 
{
    public boolean onDown(MotionEvent e) 
    {
        //手指出品按下的瞬间
        return false;
    }

    public void onShowPress(MotionEvent e) 
    {
        //手指触摸屏幕,并且尚未松开或拖动。与onDown的区别是,onShowPress强调没用松开和没有拖动
    }

    public boolean onSingleTapUp(MotionEvent e) 
    {
        //手指离开屏幕(单击)
        return false;
    }

    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) 
    {
        //手指按下并拖动,当前正在拖动
        return false;
    }

    public void onLongPress(MotionEvent e) 
    {
        //手指长按事件
    }

    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) 
    {
        //手指快速滑动
        return false;
    }
};
GestureDetector mGestureDetector = new GestureDetector(this,listener);
//防止长按后无法拖动的问题
mGestureDetector.setIsLongpressEnabled(false);

       接着,还需要接管目标的onTouchEvent方法,在待监听View的onTouchEvent方法中加入

return mGestureDetector.onTouchEvent(event);

       在手势检测中除了OnGestureListener()之外还有OnDoubleTapListener(),它主要处理双击相关的事件,可以通过setOnDoubleTapListener将该监听器设置到GestureDetector中。

6.Scroller

       Scroller是一个专门用于处理滚动效果的工具类,可能在大多数情况下,我们直接使用Scroller的场景并不多,但是很多大家所熟知的控件在内部都是使用Scroller来实现的,如ViewPager、ListView等。而如果能够把Scroller的用法熟练掌握的话,我们自己也可以轻松实现出类似于ViewPager这样的功能。其实Scroller本身是无法让View弹性滑动的,它需要和View的computeScroll方法配合使用才能共同完成这个功能,关于View的滑动具体的内容可以去参考View的滑动








评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值