Android 从 0 开始自定义控件之 View 基础知识与概念(一)

3,408 阅读6分钟

转载请标明出处: blog.csdn.net/airsaid/art…
本文出自:周游的博客

前言

自定义View可以说是Android路上的一道坎,会的人觉得简单,不会的觉得很难。最近正好在看《Android开发艺术探索》讲的自定义View这里,于是打算从头理一理自定义View,写写笔记,方便日后自己查阅也希望能帮助到你。

什么是View

View作为用户界面组件的基本构建块,在屏幕上占据一个矩形区域,负责绘图和事件的处理。View是Android中所有控件的基类,像TextView、Button、LinearLayout都是间接或直接继承自View。除了View之外,还有一个比较重要的控件:ViewGroup。ViewGroup也是继承自View,和View不同的是,View主要用于创建交互式UI组件,而ViewGroup则表示一个控件组,布局Layout都继承自该类,其内部可以包含多个控件。

View位置参数

View最重要的莫过于View的位置参数了,View的位置,主要用4个点组成,分别对应View的四个属性:left、rigth、top、buttom。其中left是左上角横坐标,top是左上角纵坐标,top是右上角横坐标,buttom是右下角纵坐标。如下图:
这里写图片描述

注意事项
这些坐标都是根据当前View的父容器来决定的,而并不是根据当前屏幕。

从Android3.0开始,View增加了几个额外的属性:x、y、translationX、translationY。其中x、y是View左上角的坐标,而translationX、和translationY则是View左上角相对于父容器的偏移量。这几个参数也都是相当于父容器的,并且translationX、translationY的默认值为0。其换算公式如下:

x = left + translationX
y = top + translationY

MotionEvent

通过MotinoEvent对象我们可以获取的用户触摸到手机屏幕产生的事件,通常的触摸事件有如下几种:

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

同时我们还可以同时获取到,用户触摸时的x、y坐标。我们可以通过getX()、getY()、getRawX()、getRawY()来获取。其中getX()、getY()是获取的相对于当前View左上角的x、y坐标。而getRawX()、getRawY()则获取的是相对于手机屏幕左上角的x、y坐标。

TouchSlop

TouchSlop是一个常量,保存的是系统所能识别出的最小滑动距离。这个值在不同的设备上有可能是不同的,我们通常使用它来进行一些滑动过滤,比如说判断当前滑动的距离如果少于这个值,那么就可以判断不是滑动,不进行滑动后的处理,增强用户体验。

我们可以通过:

ViewConfiguration.get(this).getScaledTouchSlop();

来获取TouchSlop这个值。

VelocityTracker

VelocityTracker,速度追踪,通过这个类我们可以获取手指在滑动时的速度,其中包括水平和垂直方向的速度。
获取第一步,在View的onTouch()方法中添加追踪:

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

第二步,获取当前滑动速度:

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

需要注意的是,在获取之前,必须先要调用computeCurrentVelocity(int units)方法,其中units参数代表的是毫秒时间段。比如说上方写的1000就代表1秒内手指滑动的像素数,如果1秒内滑动了100像素数,那么值就为100,当然这个值也有可能是负数,如果是在水平方向从右往左滑动,值则会负数,垂直时,从下往上滑动,也为负数。总结下来可以用一个公式来表示:

速度 = (终点位置 - 起点位置) / 时间段
当我们不需要使用VelocityTracker的时候,可以通过如下方法重置并回收内存:

velocityTracker.clear();
velocityTracker.recycle();

GestureDetector

GestureDetector是一个手势检测类,用于辅助我们检测用户的手势动作,比如说:单击、双击、长按、滑动等行为。
GestureDetector的使用也很简单,主要分如下几步:

  • 第一步(创建对象):
GestureDetector gestureDetector = new GestureDetector(new GestureDetector.OnGestureListener() {
    @Override
    public boolean onDown(MotionEvent e) {
        return false;
    }

    @Override
    public void onShowPress(MotionEvent e) {

    }

    @Override
    public boolean onSingleTapUp(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onScroll(MotionEvent e1, MotionEvent e2, float distanceX, float distanceY) {
        return false;
    }

    @Override
    public void onLongPress(MotionEvent e) {

    }

    @Override
    public boolean onFling(MotionEvent e1, MotionEvent e2, float velocityX, float velocityY) {
        return false;
    }
});

其中,构建对象的参数为一个监听接口。如果只需要单独监听某个事件,可以实现如下监听:

GestureDetector gestureDetector = new GestureDetector(new GestureDetector.SimpleOnGestureListener(){
    // 实现需要实现的方法
});
  • 第二步(重写onTouchEvent()方法,接管触摸事件):
@Override
public boolean onTouchEvent(MotionEvent event) {
    boolean consume = mGestureDetector.onTouchEvent(event);
    return consume;
}

至此,我们我们就可以获取到用户触摸时的状态了,当用户触摸时分别会调用对应回调方法。具体的方法描述如下:

方法名 描述
onDown 手指轻轻触摸屏幕的一瞬间触发
onShowPress 手指轻轻触摸屏幕,尚未松开或拖动时触发
onSingleTapUp 手指轻轻触摸屏幕后松开时触发
onScroll 手指按下屏幕后拖动时触发
onLongPress 长按屏幕时触发
onFling 按下屏幕,快速滑动后松开时触发

我们不仅可以获取到用户的如上触摸状态,还可以通过GestureDetector的setOnDoubleTapListener(listener)方法获取用户的双击等事件:

mGestureDetector.setOnDoubleTapListener(new GestureDetector.OnDoubleTapListener() {
    @Override
    public boolean onSingleTapConfirmed(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onDoubleTap(MotionEvent e) {
        return false;
    }

    @Override
    public boolean onDoubleTapEvent(MotionEvent e) {
        return false;
    }
});

其中各回调方法说明如下:

方法名 描述
onSingleTapConfirmed 严格的单击行为(只允许出现一次单击行为,如果触发了该事件,那么后面不可能再有单击事件。即只可能是单击,而不是双击中的一次。)
onDoubleTap 双击时触发(该方法不可与onSingleTapConfirmed()方法共存)
onDoubleTapEvent 表示发生了双击行为,在双击的期间,ACTION_DOWN、ACTION_MOVE和ACTION_UP都会触发该回调

Scroller

Scroller是一个弹性滑动类,用于实现View的弹性滑动。Scroller的好处就在于滑动时可以让View平滑的滑动,而不是像scrollTo/scrollBy一样生硬的一下子滑动完成。
使用Scroller分为如下几部:

  • 1,创建Scroller对象。
Scroller mScroller = new Scroller(context);
  • 2,调用startScroll()方法滑动到指定位置。
 mScroller.startScroll(int startX, int startY, int dx, int dy, int duration)
  • 3,重写computeScroll()方法,并在其内部完成平滑移动逻辑。
@Override
public void computeScroll() {
    if(mScroller.computeScrollOffset()){
        scrollTo(mScroller.getCurrX(), mScroller.getCurrY());
        postInvalidate();
    }
}

参考

《Android开发艺术探索》

下篇:Android 从0开始自定义控件之View的滑动(二)