我喜欢看动态的东西,总想着能够做出炫酷啊的东西,先要学习一些基本的让Anroid视图动起来的方式。Android 为了达到移动的目的,有多种移动的方式。这几张方式的限制和使用 早期让我觉得有些懵。现在做一个总结,综述下这些移动方式,讲述他们的差异和用途。

  1. 改变布局参数。通过设LayoutParamsmargin来改变布局,达到移动的目的
  2. 改变scrollX scrollY 属性。 通过scrollTo() scrollBy()函数来改变视图
  3. 改变translate。设置translate的值来产生动画
  4. offsetTopAndBottom 调用

改变布局参数

这种思路自然不用说,是一种最容易想到的布局的方式

RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams)
mTvLayoutParam.getLayoutParams();
layoutParams.topMargin = layoutParams.topMargin + 50;
mTvLayoutParam.requestLayout();

效果上面,是需要重新布局和计算的,会影响到同一个布局中的兄弟节点的的绘制,因为是布局参数的根本上改变。这样是需要重写走遍历的流程的,是代价最大的一种方式.

改变scroll属性

对于TextView移动的是内容。改变的只是内容的滑动,并不改变背景,并且,还会有对应的scrollBar产生对应 效果。它滑动的方向是scrollBar的方向,scrollBar向下的时候,内容向上,scrollBar向上的内容向下,为了滑动View中的内容scrollBy传递的值与想要的内容滑动的方向是相反的, 内容向上滑动是正值,向下滑动是赋值。

mTvScroll.scrollBy(0,10);

简单的想看看scroll里面最后是怎么实现的,瞅瞅了是把View的画布进行了平移

//硬件加速的渲染方式找到了,根据scroll的值,整个的画布进行了平移
updateDisplayListIfDirty() {
.....
 canvas.translate(-mScrollX, -mScrollY);
........
}

顺便提一嘴,想要实现丝绸般润滑的 scroll行为,是需要借助Scroller这个工具类 的,来一小步一小步的进行滑动处理的。

translate布局

也是在绘制阶段进行 变化,不过会整体的进行移动,而不是只是移动背景

mTvTranslate.setTranslationY(10);

offsetTopAndBottom等的调用

offsetTopAndBottom offsetLeftAndRight本质是改变了布局的参数,只是直接在布局参数上面进行了加减,但是不会影响到兄弟View的位置变化。需要的只是重新绘制,但是本质上又直接修改了布局参数

mTvTranslate.offsetTopAndBottom(50);

瞅瞅源码里面做了啥

public void offsetTopAndBottom(int offset) {
............ //省略一部分,看到下面这句就够了,把布局的参数直接进行了修改

            mTop += offset;
            mBottom += offset;
............
        }
    }

总结

特别需要注意的。scroll tranlate 布局的参数都是单独的属性,可以各自起到作用

方式

影响

效果

作用场景

改变布局参数layoutParams

需要重新走视图 测量 布局 绘制 三部曲,代价大

会影响到兄弟节点一起变化,效果差

大部分只用在有少数布局调整的操作

scroll方式

只需要走重新绘制即可,代价小

只能滑动内容,不能把背景跟着一起滑动,不影响布局参数

常常配合ontouch一起处理内容的滑动 , 可能受到requestlayout影响则会复位

translate方式

只需要走重新绘制即可,代价小

真正的平移滑动,可以移动整个视图, 不影响布局参数

常常作用于动画,不受requestlayout的影响

offsetTopAndBottom

只需要走重新绘制即可,代价小

影响布局参数,受到requestlayout影响则会复位

有一些自定义控件中用到了

以上的所有的描述都是基于一些默认的行为,控件都是可以自行处理的,比如RecycleView中就会记录scroll值,在layout中做一系列的处理


附件(布局文件和主类文件)

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="horizontal"
    >

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent"
        android:clipChildren="false">

        <TextView
            android:id="@+id/tv_shadow1"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_marginTop="50dp"
            android:layout_centerHorizontal="true"
            android:gravity="center"
            android:text="多层layer方式1"
            android:background="@drawable/bg_shadow"/>

        <TextView
            android:id="@+id/tv_shadow2"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_below="@id/tv_shadow1"
            android:layout_marginTop="50dp"
            android:layout_centerHorizontal="true"
            android:text="多层layer方式2"
            android:gravity="center"
            android:background="@drawable/bg_shadow_2"/>

    </RelativeLayout>

    <RelativeLayout
        android:layout_width="0dp"
        android:layout_weight="1"
        android:layout_height="match_parent">

        <TextView
            android:id="@+id/tv_shadow3"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_marginTop="50dp"
            android:layout_centerHorizontal="true"
            android:text="elevation"
            android:gravity="center"
            android:background="#fff"
            android:elevation="10dp"/>

        <android.support.v7.widget.CardView
            android:id="@+id/tv_shadow4"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_below="@id/tv_shadow3"
            android:layout_marginTop="50dp"
            android:layout_centerHorizontal="true"
            app:cardCornerRadius="4dp"
            app:cardElevation="4dp"
            >
            <TextView
                android:layout_width="match_parent"
                android:layout_height="match_parent"
                android:text="CardView"
                android:gravity="center"
                android:background="#fff"
                />
        </android.support.v7.widget.CardView>

    </RelativeLayout>
</LinearLayout>

public class MainActivity extends Activity implements View.OnClickListener {

    private static final String TAG = "MainActivity";
    private TextView mTvLayoutParam;
    private TextView mTvScroll;
    private TextView mTvTranslate;
    private android.support.v7.widget.CardView mTvOffset;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_shadow);
        mTvLayoutParam = findViewById(R.id.tv_shadow1);
        mTvScroll = findViewById(R.id.tv_shadow2);
        mTvTranslate = findViewById(R.id.tv_shadow3);
        mTvOffset = findViewById(R.id.tv_shadow4);
        mTvLayoutParam.setOnClickListener(this);
        mTvScroll.setOnClickListener(this);
        mTvTranslate.setOnClickListener(this);
        mTvOffset.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.tv_shadow1:
                RelativeLayout.LayoutParams layoutParams = (RelativeLayout.LayoutParams) mTvLayoutParam.getLayoutParams();
                layoutParams.topMargin = layoutParams.topMargin + 50;
                mTvLayoutParam.requestLayout();
                break;
            case R.id.tv_shadow2:
                mTvScroll.scrollBy(0,10);
                break;
            case R.id.tv_shadow3:
                mTvTranslate.setTranslationY(10);
                break;
            case R.id.tv_shadow4:
                mTvTranslate.offsetTopAndBottom(50);
                break;
        }
    }
}