《 Android 开发艺术探索》 View 的位置参数与使用 scrollTo/scrollBy 进行滑动

版权声明:转载请标明出处「OneDeveloper」 https://blog.csdn.net/OneDeveloper/article/details/82624678

在《Android开发艺术探索》中有提到过,View 的位置主要由其四个顶点来决定,分别对应 View 的四个属性:top、left、right、bottom,且这四个点是相对于 View 的父容器来说的,是一种相对坐标。

另外,在 Android 3.0 以后,View 还增加了几个参数:x、y、translationX、translationYx、y是 View 左上角相对于父容器的坐标,而 translationX、translationY 是 View 左上角相对于父容器的偏移量。

x = left + translationX
y = top + translationY

View 在平移的过程中,top 和 left 表示的是原始左上角的位置信息,其值是不会改变的,此时发生改变的是 x、y、translationX、translationY。

这里需要突出的是平移,因为下面需要说到 View 使用 scrollTo/scrollBy进行滑动。


首先,需要强调的一点 ,scrollTo/scrollBy 只能滑动 View 的内容,而不能滑动 View 本身 (即滑动的是下面所说的绘图层,而不能滑动 layout 层)。同时,还需要先了解清楚接下来说明的一些概念,有些名词不一定准确,主要是为来辅助概念的讲解。

比如 TextView 的话滑动的就是里面的文本内容,ViewGroup 的话就是滑动内部的子 View。

View 的scrollTo 和scrollBy 一文中,有如下的图:
这里写图片描述
红色框框代表 TextView 的空间视图(即图中的 View 视图,也就是绘画层、绘画视图),该层是没有边界的,可以无限延伸(用红色框框只是为了凸显出来)。

但是在实际中,TextView 在使用的时候都会依附于一个父 View,此时就存在 TextView 的 layout 视图,即图中的黑色框框(框框的左上角坐标即 TextView 的 (left,top)),是具有具体的边界的(如下代码中 TextView 设置的 layout_XXX 属性,就是用来框定 TextView 的 layout 视图的,此视图即代表在父布局中实际的边界),在绘画层中的内容只有同时处于 layout 视图中才会被显示出来

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:layout_height="match_parent">
    <TextView
        android:layout_width="50dp"
        android:layout_height="100dp"
        android:text="X"/>

</LinearLayout>

对于 Layout 来说(如 LinearLayout),因为内部排放的是子 View,所以,子 View 是在 Layout 的绘图层进行绘画的,但是只有当绘画的子 View 处于 Layout 的 layout 视图范围内时,子 View 才会被显示出来(更进一步的说,此时显示的就是子 View 的 layout 视图处于父 Layout 的 layout 视图中)。

像下面这种情况:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:id="@+id/rootView"
    android:layout_width="800dp"
    android:orientation="horizontal"
    android:id="@+id/parent"
    android:layout_height="800dp">
    ......

</LinearLayout>

此时,因为 LinearLayout 设置的 android:layout_widthandroid:layout_height过大,并不能在手机屏幕上完全显示出来,这里需要注意,该布局文件对应的只是 ContentView(即通过 setContentView 设置的),在该 View 外层还有包裹一层系统的 Layout 的,而此时即使 rootView 设置了 800 * 800dp,但是因为有一部分是不在系统Layout 中的 layout 视图中的,所以才没有在手机屏幕上完全显示出来。

扫描二维码关注公众号,回复: 3319022 查看本文章

使用scrollTo 、scrollBy方法滑动时,涉及到 View 内部的两个属性 mScrollXmScrollY (两者的单位为像素,可通过 getScrollX() 和 getScrollY()获得)的改变。

当 View 没有经过 scroll 方法滑动内部内容时,处于原始状态时,此时,View 的绘画层与 layout 层左上角重叠的点为参考点(如图中着重标记的黑点),有 mScrollX = 0 && mScrollY = 0,当滑动之后,该参考点与 layout 层左上角点的距离即为 mScrollX、mScrollY 的值。(因为 layout 层是固定不动,滑动的只是绘图层)。

  • scrollTo 实现基于所传递参数的绝对滑动,即把上面所说的参考点滑动到指定的位置。
  • scrollBy 实际上也是调用 scrollTo,实现基于当前位置的相对滑动,即把上面所说的参考点根据原有位置滑动相应的距离。

如果绘图层向滑,mScrollX 为正,如果绘图层向滑,mScrollY 为正。如下图演示:
这里写图片描述


此外,还需要注意,当一个 Layout 在使用 scroll 滑动时,并不会改变其内部子 View 的 x、left、translationX等属性。

例如有如下布局:

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:background="#feb4b4"
    android:layout_width="match_parent"
    android:orientation="horizontal"
    android:id="@+id/parent"
    android:layout_height="wrap_content">
    <Button
        android:id="@+id/bt"
        android:onClick="test"
        android:layout_marginLeft="100dp"
        android:layout_width="50dp"
        android:layout_height="100dp"
        android:text="X"/>
</LinearLayout>

且为 Button 实现点击事件:

public class MainActivity extends AppCompatActivity {

    private LinearLayout layout;
    private Button testBt;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        layout = findViewById(R.id.parent);
        testBt = findViewById(R.id.bt);
    }

    public void test(View view) {
        Log.d("test", "getX() = "+testBt.getX());
        Log.d("test", "getLeft() = "+testBt.getLeft());
        Log.d("test", "getTranslationX() = "+testBt.getTranslationX());
        layout.scrollBy(50,50);
        Log.d("test", "getX() = "+testBt.getX());
        Log.d("test", "getLeft() = "+testBt.getLeft());
        Log.d("test", "getTranslationX() = "+testBt.getTranslationX());
    }
}

scrollBy() 前后,打印的值相等。
这里写图片描述
(需要注意第一次打印不能在 Activity 的 onCrate 方法中,因为此时可能控件还没有完全初始化,导致 getX()getLeft() 为 0)。

猜你喜欢

转载自blog.csdn.net/OneDeveloper/article/details/82624678
今日推荐