View 体系详解:坐标系、滑动、手势和事件分发机制

本文深入探讨了Android中View的坐标系、滑动实现方式,包括layout()、offsetLeftAndRight()等方法,以及手势处理,如GestureDetector和VelocityTracker。同时详细解析了事件分发机制,涵盖决定是否拦截事件、事件传递的过程和源码分析。
摘要由CSDN通过智能技术生成

1、位置

1.1 坐标系

下面是 Android 中的 View 坐标系的基本图。要获得一个 View 的位置,我们可以借助两个对象,一个是 View ,一个是 MotionEvent。以下是它们的一些方法的位置的含义:

Android View 坐标系

在 View 中共有 mLeft, mRight, mTopmBottom 四个变量包含 View 的坐标信息,你可以在源码中获取它们的含义:

  1. mLeft:指定控件的左边缘距离其父控件左边缘的位置,单位:像素;
  2. mRight:指定控件的右边缘距离其父控件左边缘的位置,单位:像素;
  3. mTop:指定控件的上边缘距离其父控件上边缘的位置,单位:像素;
  4. mBottom:指定控件的下边缘距离其父控件上边缘的位置,单位:像素。

此外,View 中还有几个方法用来获取控件的位置等信息,实际上就是上面四个变量的 getter 方法:

  1. getLeft():即 mLeft
  2. getRight():即 mRight
  3. getTop():即 mTop
  4. getBottom():即 mBottom

所以,我们可以得到两个获取 View 高度和宽度信息的方法:

  1. getHeight():即 mBottom - mTop
  2. getWidth():即 mRight - mLeft

另外,就是 View 中的 getX()getY() 两个方法,你需要注意将其与 MotionEvent 中的同名方法进行区分。在没有对控件进行平移的时候,getX()getLeft() 返回结果相同,只是前者会在后者的基础上加上平移的距离:

  1. getX():即 mLeft + getTranslationX(),即控件的左边缘加上 X 方向平移的距离;
  2. getY():即 mTop + getTranslationY(),即控件的上边缘加上 Y 方向平移的距离;

以上是我们对 View 中获取控件位置的方法的梳理,你可以到源码中查看它们更加相详尽的定义,那更有助于自己的理解。

1.2 MotionEvent

通常当你对控件进行触摸监听的时候会用到 MotionEvent ,它封住了触摸的位置等信息。下面我们对 MotionEvent 中的获取点击事件的位置的方法进行梳理,它主要涉及下面四个方法:

  1. MotionEvent.getX():获取点击事件距离控件左边缘的距离,单位:像素;
  2. MotionEvent.getY():获取点击事件距离控件上边缘的距离,单位:像素;
  3. MotionEvent.getRawX():获取点击事件距离屏幕左边缘的距离,单位:像素;
  4. MotionEvent.getRawY():获取点击事件距离屏幕上边缘的距离,单位:像素。

另外是触摸事件中的三种典型的行为,按下、移动和抬起。接下来的代码示例中我们会用到它们来判断手指的行为,并对其做响应的处理:

  1. MotionEvent.ACTION_DOWN:按下的行为;
  2. MotionEvent.ACTION_MOVE:手指在屏幕上移动的行为;
  3. MotionEvent.ACTION_UP:手指抬起的行为。

2、滑动

我们有几种方式实现 View 的滑动:

2.1 layout() 方法

调用控件的 layout() 方法进行滑动,下面是该方法的定义:

public void layout(int l, int t, int r, int b) { /*...*/ }

其中的四个参数 l, t, r, b分别表示控件相对于父控件的左、上、右、下的距离,分别对应于上面的 mLeft, mTop, mRightmBottom。所以,调用该方法同时可以改变控件的高度和宽度,但有时候我们不需要改变控件的高度和宽度,只要移动其位置即可。所以,我们又有方法 offsetLeftAndRight()offsetTopAndBottom() 可以使用,后者只会对控件的位置进行平移。因此,我们可以进行如下的代码测试:

private int lastX, lastY;

private void layoutMove(MotionEvent event) {
    int x = (int) event.getX(), y = (int) event.getY();
    switch (event.getAction()) {
        case MotionEvent.ACTION_DOWN:
            lastX = x;
            lastY = y;
            break;
        case MotionEvent.ACTION_MOVE:
            int offsetX = x - lastX, offsetY = y - lastY;
            getBinding().v.layout(getBinding().v.getLeft() + offsetX,
                    getBinding().v.getTop() + offsetY,
                    getBinding().v.getRight() + offsetX,
                    getBinding().v.getBottom() + offsetY);
            break;
        case MotionEvent.ACTION_UP:
            break;
    }
}

上面的代码的效果是指定的控件会随着手指的移动而移动。这里我们先记录下按下的位置,然后手指移动的时候记录下平移的位置,最后调用 layout() 即可。

2.2 offsetLeftAndRight() 和 offsetTopAndBottom()

上面已经提到过这两个方法,它们只改变控件的位置,无法改变大小。我们只需要对上述代码做少量修改就可以实现同样的效果:

getBinding().v.offsetLeftAndR
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值