A. *_*rik 7 android android-animation android-motionlayout
Activityclass SwipeHandlerActivity : AppCompatActivity(R.layout.activity_swipe_handler){
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putBundle("Foo", findViewById<MotionLayout>(R.id.the_motion_layout).transitionState)
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedInstanceState?.getBundle("Foo")?.let(findViewById<MotionLayout>(R.id.the_motion_layout)::setTransitionState)
}
}
Run Code Online (Sandbox Code Playgroud)
Layout<?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"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layoutDescription="@xml/activity_swipe_handler_scene"
android:id="@+id/the_motion_layout"
app:motionDebug="SHOW_ALL">
<View
android:id="@+id/touchAnchorView"
android:background="#8309AC"
android:layout_width="64dp"
android:layout_height="64dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toTopOf="parent" />
</androidx.constraintlayout.motion.widget.MotionLayout>
Run Code Online (Sandbox Code Playgroud)
Scene<?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"
motion:duration="1000">
<OnSwipe
motion:touchAnchorId="@id/imageView"
motion:dragDirection="dragUp"
motion:touchAnchorSide="top" />
</Transition>
<ConstraintSet android:id="@+id/start">
</ConstraintSet>
<ConstraintSet android:id="@+id/end">
<Constraint
android:layout_height="250dp"
motion:layout_constraintStart_toStartOf="@+id/textView2"
motion:layout_constraintEnd_toEndOf="@+id/textView2"
android:layout_width="250dp"
android:id="@+id/imageView"
motion:layout_constraintBottom_toTopOf="@+id/textView2"
android:layout_marginBottom="68dp" />
</ConstraintSet>
</MotionScene>
Run Code Online (Sandbox Code Playgroud)
配置更改后,运动布局保持在其开始状态
我最终创建了这些扩展功能
fun MotionLayout.restoreState(savedInstanceState: Bundle?, key: String) {
viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
override fun onGlobalLayout() {
doRestore(savedInstanceState, key)
viewTreeObserver.removeOnGlobalLayoutListener(this)
}
})
}
private fun MotionLayout.doRestore(savedInstanceState: Bundle?, key: String) =
savedInstanceState?.let {
val motionBundle = savedInstanceState.getBundle(key) ?: error("$key state was not saved")
setTransition(
motionBundle.getInt("claptrap.motion.startState", -1)
.takeIf { it != -1 }
?: error("Could not retrieve start state for $key"),
motionBundle.getInt("claptrap.motion.endState", -1)
.takeIf { it != -1 }
?: error("Could not retrieve end state for $key")
)
progress = motionBundle.getFloat("claptrap.motion.progress", -1.0f)
.takeIf { it != -1.0f }
?: error("Could not retrieve progress for $key")
}
fun MotionLayout.saveState(outState: Bundle, key: String) {
outState.putBundle(
key,
bundleOf(
"claptrap.motion.startState" to startState,
"claptrap.motion.endState" to endState,
"claptrap.motion.progress" to progress
)
)
}
Run Code Online (Sandbox Code Playgroud)
然后我这样称呼他们:
onCreate, onCreateView if (savedInstanceState != null) {
binding.transactionsMotionLayout.restoreState(savedInstanceState, MOTION_LAYOUT_STATE_KEY)
}
Run Code Online (Sandbox Code Playgroud)
onSaveInstanceState binding.transactionsMotionLayout.saveState(outState, MOTION_LAYOUT_STATE_KEY)
Run Code Online (Sandbox Code Playgroud)
这导致两种预期的行为MotionLayouts在ActivityS和MotionLayouts里面Fragment秒。但是我对所需的代码量不满意,所以如果有人能提出更简洁的解决方案,我会很高兴听到:)
我不明白为什么你没有这样做,但你需要扩展MotionLayout以正确保存视图状态。
您当前的解决方案(除了需要在活动和片段层中进行额外处理外)在可分离片段的情况下将失败,因为它们在内部处理视图保存状态而没有实际填充savedInstanceState(我知道这很令人困惑)。
open class SavingMotionLayout @JvmOverloads constructor(
context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
) : MotionLayout(context, attrs, defStyleAttr) {
override fun onSaveInstanceState(): Parcelable {
return SaveState(super.onSaveInstanceState(), startState, endState, targetPosition)
}
override fun onRestoreInstanceState(state: Parcelable?) {
(state as? SaveState)?.let {
super.onRestoreInstanceState(it.superParcel)
setTransition(it.startState, it.endState)
progress = it.progress
}
}
@kotlinx.android.parcel.Parcelize
private class SaveState(
val superParcel: Parcelable?,
val startState: Int,
val endState: Int,
val progress: Float
) : Parcelable
}
Run Code Online (Sandbox Code Playgroud)
您将需要在您的 XML 中使用这个类,而不是MotionLayout它不太容易出错,并且会尊重正确的视图状态保存机制,因此您不再需要向活动或片段添加任何额外的代码。
如果您想禁用保存,您可以使用android:saveEnabled="false"XML 或isSaveEnabled = false代码来完成。
| 归档时间: |
|
| 查看次数: |
563 次 |
| 最近记录: |