1、位置
1.1 坐标系
下面是 Android 中的 View 坐标系的基本图。要获得一个 View 的位置,我们可以借助两个对象,一个是 View ,一个是 MotionEvent。以下是它们的一些方法的位置的含义:
在 View 中共有 mLeft
, mRight
, mTop
和 mBottom
四个变量包含 View 的坐标信息,你可以在源码中获取它们的含义:
mLeft
:指定控件的左边缘距离其父控件左边缘的位置,单位:像素;mRight
:指定控件的右边缘距离其父控件左边缘的位置,单位:像素;mTop
:指定控件的上边缘距离其父控件上边缘的位置,单位:像素;mBottom
:指定控件的下边缘距离其父控件上边缘的位置,单位:像素。
此外,View 中还有几个方法用来获取控件的位置等信息,实际上就是上面四个变量的 getter 方法:
getLeft()
:即mLeft
;getRight()
:即mRight
;getTop()
:即mTop
;getBottom()
:即mBottom
;
所以,我们可以得到两个获取 View 高度和宽度信息的方法:
getHeight()
:即mBottom - mTop
;getWidth()
:即mRight - mLeft
;
另外,就是 View 中的 getX()
和 getY()
两个方法,你需要注意将其与 MotionEvent 中的同名方法进行区分。在没有对控件进行平移的时候,getX()
与 getLeft()
返回结果相同,只是前者会在后者的基础上加上平移的距离:
getX()
:即mLeft + getTranslationX()
,即控件的左边缘加上 X 方向平移的距离;getY()
:即mTop + getTranslationY()
,即控件的上边缘加上 Y 方向平移的距离;
以上是我们对 View 中获取控件位置的方法的梳理,你可以到源码中查看它们更加相详尽的定义,那更有助于自己的理解。
1.2 MotionEvent
通常当你对控件进行触摸监听的时候会用到 MotionEvent ,它封住了触摸的位置等信息。下面我们对 MotionEvent 中的获取点击事件的位置的方法进行梳理,它主要涉及下面四个方法:
MotionEvent.getX()
:获取点击事件距离控件左边缘的距离,单位:像素;MotionEvent.getY()
:获取点击事件距离控件上边缘的距离,单位:像素;MotionEvent.getRawX()
:获取点击事件距离屏幕左边缘的距离,单位:像素;MotionEvent.getRawY()
:获取点击事件距离屏幕上边缘的距离,单位:像素。
另外是触摸事件中的三种典型的行为,按下、移动和抬起。接下来的代码示例中我们会用到它们来判断手指的行为,并对其做响应的处理:
MotionEvent.ACTION_DOWN
:按下的行为;MotionEvent.ACTION_MOVE
:手指在屏幕上移动的行为;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
, mRight
和 mBottom
。所以,调用该方法同时可以改变控件的高度和宽度,但有时候我们不需要改变控件的高度和宽度,只要移动其位置即可。所以,我们又有方法 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