Android坐标系与View的位置参数
学习View的滑动前,我们先看看一些基础知识。
View的位置主要由它的四个顶点来决定,分别对应与View的四个属性:top、left、right、bottom
,这些坐标都是相对于View的父容器来说的,因此它是一种相对坐标,View的坐标和父容器的关系如下图所示。在Android中,X轴和Y轴的正方向分别为右和下,这点不难理解,不仅仅是Android,大部分显示系统都是按照这个标准来定义坐标系的。
View的四个属性都可以使用get
方法获取。
那么我们可以知道:
• getWidth = getRight() - getLeft()
• getHeight = getTop() - getBottom()
从Android 3.0开始, View增加了额外的几个参数:
-
translationX
、translationY
:View左上角相对于父容器的偏移量 x
、y
:View在父容器中左上角的坐标加上偏移量,关系如下:
• x = left + translationX
• y = top + translationY
[ ! ] 需要注意的是,View在平移过程中,top和left表示的是原始左上角的位置信息,其值并不会发生改变,此时发生改变的是x、y、translationX 和 translationY这四个参数。
MotionEvent
无论是View还是ViewGroup,最终的点击事件都会由onTouchEvent(MotionEvent event)
方法来处理。MotionEvent
在用户交互中作用重大,其内部提供了很多事件常量和获取触摸焦点坐标的各种方法。在手指接触屏幕后所产生的一系列事件中,典型的事件类型有如下几种:
ACTION_DOWN—— 手指刚刚接触屏幕
ACTION_MOVE—— 手指在屏幕上移动
ACTION_UP—— 手指从屏幕上抬起时
假设下图中蓝色圆点为用户触摸的位置,图片清晰明了的表示MotionEvent
的各个方法和屏幕之间的距离关系,其中getX()
、getY()
是获取点击事件距离当前控件的左边和上边的距离(这是MotionEvent的方法,注意只是和上面View的方法同名),而getRawX()
、getRawY()
是获取点击事件距离整个屏幕的绝对坐标。
在了解了这些后,我们就可以开始学习View滑动的几种方法了!
1、使用 scrollBy()
scrollBy()
方法是一种让 View 内画布滑动的方法。
scrollBy()
方法说是滑动,其实没有动画效果,是瞬间完成的,View 中的布局和内容都不会变。
//待移动的 View
View view = findViewById(R.id.view);
//待移动的ViewGroup,假设是上面 View 的父容器
View viewGroup = (View) view.getParent();
findViewById(R.id.scroll_by)
.setOnClickListener(v -> viewGroup.scrollBy(-100, 0));
上面代码给一个按钮设置点击了事件监听,里面调用了变量viewGroup
的scrollBy()
方法,这个方法表示:viewGroup 视图内画布的 x 轴整体右移动100像素,y 轴不变。
Android View视图是没有边界的,Canvas是没有边界的。
此方法是让画布相对当前位置进行滑动的,还有另一个方法scrollTo()
会滑动到绝对坐标。事实上scrollBy()
方法内部也调用了scrollTo()
。
2、使用属性动画
//ObjectAnimator
findViewById(R.id.object_animator).setOnClickListener(v ->
ObjectAnimator.ofFloat(view, "translationX", view.getTranslationX()+100)
.setDuration(500)
.start()
);
属性动画使用起来非常方便,只需指定移动的视图、改变哪个属性、改变的额值和动画速度即可。这里使用了属性动画而不使用View动画,因为View动画是Android 3.0以前的动画,View动画并不能真正改变View的位置,只是视觉效果移动而已。
3、改变 LayoutParams
//LayoutParams
findViewById(R.id.layout_params).setOnClickListener(v -> {
ViewGroup.MarginLayoutParams params = (ViewGroup.MarginLayoutParams) view.getLayoutParams();
params.leftMargin += mMoveDistance;
view.setLayoutParams(params);
});
获取 View 的LayoutParams
,接着转型为MarginLayoutParams
,因为MarginLayoutParams
类型才有leftMargin
等各个方向的属性,然后更改值,最后调用view.setLayoutParams(params)
方法改变其LayoutParams
属性或者使用view.requestLayout()
方法重新布局。
栗子
参考
Android开发艺术探索 - 任玉刚
Android进阶之光 - 刘望舒