MotionLayout简单场景使用笔记

119 阅读1分钟
Screen_recording_20241031_150755 00_00_00-00_00_30.gif

Activity布局定义activity_motion.xml

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.motion.widget.MotionLayout 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/motionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:background="#888888"
    app:layoutDescription="@xml/scene_01"
    tools:showPaths="true">

    <View
        android:id="@+id/button"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/bg"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent" />

    <View
        android:id="@+id/bottom"
        android:layout_width="0dp"
        android:layout_height="0dp"
        android:background="@drawable/shape_top_corner"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/button" />

    <com.google.android.material.floatingactionbutton.FloatingActionButton
        android:id="@+id/floating"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="16dp"
        android:src="@drawable/baseline_upload_24"
        app:fabSize="normal"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
  • 主要控制View(button)动画带动底部变化
  • app:layoutDescription="@xml/scene_01"绑定 scene_01.xml
  • MotionLayout继承ConstraintLayout

定义 res/xml/scene_01.xml

<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:motion="http://schemas.android.com/apk/res-auto">

    <Transition
        motion:constraintSetEnd="@+id/end"
        motion:constraintSetStart="@+id/start">
        <OnSwipe
            motion:dragDirection="dragDown"
            motion:touchAnchorId="@+id/button"
            motion:touchAnchorSide="bottom"
            />
    </Transition>

    <ConstraintSet android:id="@+id/start">
        <Constraint
            android:id="@+id/button"
            android:layout_width="0dp"
            android:layout_height="0dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/end">
        <Constraint
            android:id="@+id/button"
            android:layout_width="108dp"
            android:layout_height="192dp"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>

</MotionScene>
  • Transition捆绑开始结束动作ConstraintSet
  • ConstraintSet定义起始结束布局容器
  • Constraint定义布局样式位置大小属性参照ConstraintLayout
  • OnSwipe指定要捆绑的布局锚点、配置拖拽方向

Activity代码中点击控制

enableEdgeToEdge()
setContentView(R.layout.activity_motion)
val motionLayout = findViewById<MotionLayout>(R.id.motionLayout)
ViewCompat.setOnApplyWindowInsetsListener(motionLayout) { v, insets ->
    val systemBars = insets.getInsets(WindowInsetsCompat.Type.systemBars())
    v.setPadding(systemBars.left, systemBars.top, systemBars.right, systemBars.bottom)
    insets
}
motionLayout.setTransitionDuration(1000)
val floating = findViewById<FloatingActionButton>(R.id.floating)
floating.setOnClickListener { v ->
    println("-------${motionLayout.progress}-------")
    if (motionLayout.progress == 0.0f) {
        motionLayout.transitionToEnd {
            if (motionLayout.progress == 0f) {
                floating.setImageDrawable(
                    ContextCompat.getDrawable(
                        v.context,
                        R.drawable.baseline_upload_24
                    )
                )
            } else {
                floating.setImageDrawable(
                    ContextCompat.getDrawable(
                        v.context,
                        R.drawable.baseline_download_24
                    )
                )
            }
            println("transitionToEnd-------${motionLayout.progress}-------")
        }
    } else {
        motionLayout.transitionToStart()
    }
}