ConstraintSet动画失效排查及Activity中实现疑问
解决Activity中ConstraintLayout文本上下移动动画的问题
嘿,我来帮你搞定这个动画实现的问题!先说说你之前Controller代码里的核心问题:你每次点击按钮都新建了一个ConstraintLayout实例(通过getLayoutInflater().inflate()),但动画根本没作用在当前显示在屏幕上的布局上,所以自然看不到效果。
下面是在Activity中实现点击按钮让文本在顶部/底部之间切换动画的正确方案:
步骤1:简化布局文件(只需要一个)
不用再维护两个重复的布局文件,我们可以直接在代码中修改约束。用你原来的布局基础调整即可(建议改用AndroidX库的命名空间,现在是官方推荐):
<?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" android:id="@+id/root_layout" android:layout_width="match_parent" android:layout_height="match_parent" android:background="@color/white"> <androidx.appcompat.widget.AppCompatTextView android:id="@+id/textview" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_marginStart="8dp" android:layout_marginTop="60dp" android:layout_marginEnd="8dp" android:text="Hello" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.appcompat.widget.AppCompatButton android:id="@+id/plop_button" android:layout_width="40dp" android:layout_height="40dp" android:layout_margin="8dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
步骤2:Activity中的完整实现代码
import androidx.appcompat.app.AppCompatActivity; import androidx.constraintlayout.widget.ConstraintLayout; import androidx.constraintlayout.widget.ConstraintSet; import android.os.Bundle; import android.transition.ChangeBounds; import android.transition.TransitionManager; import android.view.View; import androidx.appcompat.widget.AppCompatButton; import androidx.appcompat.widget.AppCompatTextView; public class MainActivity extends AppCompatActivity { private ConstraintLayout rootLayout; private AppCompatButton plopButton; private boolean isTextAtTop = true; // 标记文本当前位置状态 private ConstraintSet topConstraintSet = new ConstraintSet(); private ConstraintSet bottomConstraintSet = new ConstraintSet(); @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.plop); // 绑定界面上的真实视图 rootLayout = findViewById(R.id.root_layout); plopButton = findViewById(R.id.plop_button); // 克隆初始的顶部约束状态 topConstraintSet.clone(rootLayout); // 构建底部状态的约束集:复制初始约束后,修改文本的对齐规则 bottomConstraintSet.clone(rootLayout); bottomConstraintSet.clear(R.id.textview, ConstraintSet.TOP); // 清除顶部约束 bottomConstraintSet.connect(R.id.textview, ConstraintSet.BOTTOM, ConstraintSet.PARENT_ID, ConstraintSet.BOTTOM, 60); // 设置底部对齐和margin // 设置按钮点击逻辑 plopButton.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { // 创建并配置动画 ChangeBounds transition = new ChangeBounds(); transition.setDuration(1000); // 动画时长1秒 // 告诉系统准备捕捉布局变化并执行动画 TransitionManager.beginDelayedTransition(rootLayout, transition); // 根据当前状态切换约束 if (isTextAtTop) { bottomConstraintSet.applyTo(rootLayout); } else { topConstraintSet.applyTo(rootLayout); } // 切换状态标记,实现反向动画 isTextAtTop = !isTextAtTop; } }); } }
关键要点解释
- 操作真实可见的布局:一定要用
findViewById获取当前界面上的rootLayout,绝对不能用inflate新建布局实例,否则动画不会作用在用户能看到的视图上。 - 用ConstraintSet管理约束:通过
clone()复制初始约束,再修改特定视图的约束规则,比维护两个几乎一样的布局文件更简洁、易维护。 - 状态标记变量:
isTextAtTop用来记录文本当前位置,实现点击一次切换一次方向的逻辑。 - TransitionManager的正确用法:
beginDelayedTransition必须传入当前的根ConstraintLayout,系统会自动识别约束变化并生成过渡动画。
内容的提问来源于stack exchange,提问作者TomJouin
相关产品推荐
相关产品推荐

