我喜欢看动态的东西,总想着能够做出炫酷啊的东西,先要学习一些基本的让Anroid视图动起来的方式。Android 为了达到移动的目的,有多种移动的方式。这几张方式的限制和使用 早期让我觉得有些懵。现在做一个总结,综述下这些移动方式,讲述他们的差异和用途。
- 改变布局参数。通过设
LayoutParams
的margin
来改变布局,达到移动的目的 - 改变scrollX scrollY 属性。 通过
scrollTo()
scrollBy()
函数来改变视图 - 改变translate。设置translate的值来产生动画
- 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;
}
}
}