在前面转场动画的文章有提到TransitionManager.beginDelayedTransition()
方法,这个方法的作用是:当View状态变化时,产生动画效果。
比如下图两个按钮,当点击底部按钮时,使顶部按钮的长度或者文字发生变化。
默认情况的效果如下:
但是如果加入代码:
TransitionManager.beginDelayedTransition(rootView);
之后,会有动画效果,动画效果如下:
看到以上的效果对比就知道TransitionManager.beginDelayedTransition()
方法的强大之处了,由此,引出本篇文章:在约束布局中实现约束动画。
ConstraintLayout,即约束布局,是当前Google最为推荐的一个布局方式,当存在多个View并且多个View存在约束关系时,当其中某个View某位置、偏移量状态发生变化时,其他View的状态也随之变化。
下面开始举例说明
【举例1】
当两个按钮具有约束时,改变其中一个View的margin
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button button_3;
private ConstraintLayout constraintLayout;
private ConstraintSet constraintSet = new ConstraintSet();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
constraintLayout = findViewById(R.id.rootView);
button_3 = findViewById(R.id.button_3);
button_3.setOnClickListener(this);
constraintSet.clone(constraintLayout);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button_3:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
TransitionManager.beginDelayedTransition(constraintLayout);
}
constraintSet.setMargin(R.id.button_1,ConstraintSet.START,100);
constraintSet.applyTo(constraintLayout);
break;
}
}
}
activity_main.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"/>
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World!"
android:textSize="20sp"
app:layout_constraintLeft_toRightOf="@id/button_1"
app:layout_constraintTop_toBottomOf="@id/button_1"/>
<Button
android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="点击改变按钮状态"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
android:layout_marginBottom="30dp"/>
</androidx.constraintlayout.widget.ConstraintLayout>
效果如下:
【举例2】
将按钮水平居中
关键代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
TransitionManager.beginDelayedTransition(constraintLayout);
}
constraintSet.centerHorizontally(R.id.button_1, R.id.rootView);
constraintSet.centerHorizontally(R.id.button_2, R.id.rootView);
constraintSet.applyTo(constraintLayout);
效果如下:
【举例3】
改变View的宽度和高度
核心代码:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
TransitionManager.beginDelayedTransition(constraintLayout);
}
((Button)findViewById(R.id.button_1)).setTextSize(8);
constraintSet.constrainWidth(R.id.button_1, 100);
constraintSet.constrainWidth(R.id.button_2, 200);
constraintSet.constrainHeight(R.id.button_1, 100);
constraintSet.constrainHeight(R.id.button_2, 200);
constraintSet.applyTo(constraintLayout);
效果如下:
【举例4】
将两个随机位置的View重新摆放为水平居中
核心代码如下:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
TransitionManager.beginDelayedTransition(constraintLayout);
}
//清除button1的约束
constraintSet.clear(R.id.button_1);
//清除button2的约束
constraintSet.clear(R.id.button_2);
//设置button1和button1之间的约束
constraintSet.connect(R.id.button_2, ConstraintSet.LEFT, R.id.button_1, ConstraintSet.RIGHT, 0);
constraintSet.connect(R.id.button_1, ConstraintSet.RIGHT, R.id.button_2, ConstraintSet.LEFT, 0);
//由于两个按钮的约束重置了,所以需要重新设置宽高
constraintSet.constrainWidth(R.id.button_1,ConstraintSet.WRAP_CONTENT);
constraintSet.constrainWidth(R.id.button_2,ConstraintSet.WRAP_CONTENT);
constraintSet.constrainHeight(R.id.button_1,ConstraintSet.WRAP_CONTENT);
constraintSet.constrainHeight(R.id.button_2,ConstraintSet.WRAP_CONTENT);
//建立水平链式关系
constraintSet.addToHorizontalChain(R.id.guideline, R.id.button_1, R.id.button_2);
//垂直居中
constraintSet.centerVertically(R.id.button_1, R.id.rootView);
constraintSet.centerVertically(R.id.button_2, R.id.rootView);
constraintSet.applyTo(constraintLayout);
效果如下:
【举例5】
这里重点说明一下约束动画的另一种写法
首先,声明两个布局activity_main1.xml
和activity_main2.xml
activity_main1.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:textSize="20sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World!"
android:textSize="20sp"
app:layout_constraintLeft_toRightOf="@id/button_1"
app:layout_constraintTop_toBottomOf="@id/button_1" />
<Button
android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="点击改变按钮状态"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
activity_main2.xml
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:id="@+id/rootView"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<Button
android:id="@+id/button_1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello"
android:textSize="20sp"
app:layout_constraintRight_toLeftOf="@+id/guideline"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent" />
<Button
android:id="@+id/button_2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="World!"
android:textSize="20sp"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/guideline"/>
<Button
android:id="@+id/button_3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="30dp"
android:text="点击改变按钮状态"
android:textSize="20sp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />
<androidx.constraintlayout.widget.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
</androidx.constraintlayout.widget.ConstraintLayout>
两个布局的View ID是一样的,就是布局位置不一样,其中第一个布局为默认加载布局。
代码如下:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
private Button button_3;
private ConstraintLayout constraintLayout;
private ConstraintSet constraintSet1 = new ConstraintSet();
private ConstraintSet constraintSet2 = new ConstraintSet();
private boolean isFirst = true;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main1);
button_3 = findViewById(R.id.button_3);
button_3.setOnClickListener(this);
constraintLayout = findViewById(R.id.rootView);
constraintSet1.clone(constraintLayout);
constraintSet2.clone(this, R.layout.activity_main2);
}
@Override
public void onClick(View view) {
switch (view.getId()){
case R.id.button_3:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
TransitionManager.beginDelayedTransition(constraintLayout);
}
if(isFirst){
constraintSet2.applyTo(constraintLayout);
}else{
constraintSet1.applyTo(constraintLayout);
}
isFirst = isFirst ? false : true;
break;
}
}
}
效果如下:
这个效果类似于转场动画的场景动画
,两个布局相当于两个场景
,两布局之间相同的View ID类似于共享元素
。
[本章完...]