Android坐标系与View的位置参数

学习View的滑动前,我们先看看一些基础知识。

View的位置主要由它的四个顶点来决定,分别对应与View的四个属性:top、left、right、bottom这些坐标都是相对于View的父容器来说的,因此它是一种相对坐标,View的坐标和父容器的关系如下图所示。在Android中,X轴和Y轴的正方向分别为右和下,这点不难理解,不仅仅是Android,大部分显示系统都是按照这个标准来定义坐标系的。

android 把view设置到图层最顶层 android view的移动_Android


View的四个属性都可以使用get方法获取。

那么我们可以知道:

• getWidth = getRight() - getLeft()
• getHeight = getTop() - getBottom()

从Android 3.0开始, View增加了额外的几个参数:

  • translationXtranslationY:View左上角相对于父容器的偏移量
  • xy: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()是获取点击事件距离整个屏幕的绝对坐标。

android 把view设置到图层最顶层 android view的移动_View_02

在了解了这些后,我们就可以开始学习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));

上面代码给一个按钮设置点击了事件监听,里面调用了变量viewGroupscrollBy()方法,这个方法表示: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 把view设置到图层最顶层 android view的移动_MotionEvent_03

参考
Android开发艺术探索 - 任玉刚
Android进阶之光 - 刘望舒