はじめに
MotionLayoutは手軽にアニメーションを管理出来てとても便利なんですが、デフォルトの動作だと元のvisibilityを無視してアニメーションを実行するとViewが表示されてしまいます。こんな感じ↓
ですが、利用する際はINVISIBLEやGONEの場合はその非表示の状態を維持したままアニメーションさせたい場合がほとんどだと思いますので、今回はそのやり方を説明します。
やり方
修正前のコード
まず前述の修正前のアニメーションはこのようなコードで実装されています。
app/build.gradle
// NOTE: MotionLayoutを利用するにはconstraintlayout:2.0.0以上を利用します
implementation 'androidx.constraintlayout:constraintlayout:2.0.0'
MainActivity.kt
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
// NOTE: アニメーションを開始
hello1.setOnClickListener {
if (motion.currentState == R.id.start) {
motion.transitionToEnd()
}else {
motion.transitionToStart()
}
}
// NOTE: 非表示にする
hello2.setOnClickListener {
it.visibility = View.INVISIBLE
}
}
}
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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<androidx.constraintlayout.motion.widget.MotionLayout
android:id="@+id/motion"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layoutDescription="@xml/hello_motion_scene">
<TextView
android:id="@+id/hello1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World! 1"
/>
<TextView
android:id="@+id/hello2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Hello World! 2"
/>
</androidx.constraintlayout.motion.widget.MotionLayout>
</androidx.constraintlayout.widget.ConstraintLayout>
xml/hello_motion_scene.xml
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/hello1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hello2"
/>
<Constraint
android:id="@+id/hello2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hello1"
app:layout_constraintEnd_toEndOf="parent"
/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/hello1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/hello2"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginBottom="50dp"
/>
<Constraint
android:id="@+id/hello2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hello1"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginBottom="50dp"
/>
</ConstraintSet>
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@+id/start"
app:duration="600"
/>
</MotionScene>
修正後のコード
visibilityを保持したコードにする場合は app:visibilityMode="ignore"
を追加してあげるだけ。
xml/hello_motion_scene.xml
<?xml version="1.0" encoding="utf-8"?>
<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto">
<ConstraintSet android:id="@+id/start">
<Constraint
android:id="@+id/hello1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toStartOf="@id/hello2"
app:visibilityMode="ignore"
/>
<Constraint
android:id="@+id/hello2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="50dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toEndOf="@id/hello1"
app:layout_constraintEnd_toEndOf="parent"
app:visibilityMode="ignore"
/>
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:id="@+id/hello1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@id/hello2"
app:layout_constraintStart_toStartOf="parent"
android:layout_marginBottom="50dp"
app:visibilityMode="ignore"
/>
<Constraint
android:id="@+id/hello2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/hello1"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginBottom="50dp"
app:visibilityMode="ignore"
/>
</ConstraintSet>
<Transition
app:constraintSetEnd="@id/end"
app:constraintSetStart="@+id/start"
app:duration="600"
/>
</MotionScene>
これでアニメーション実行後に勝手に表示されることなく、visibilityを制御できるようになりました!