gpt4 book ai didi

android - 如何在不自动播放过渡的情况下恢复 MotionLayout 的过渡状态?

转载 作者:行者123 更新时间:2023-12-04 04:31:32 26 4
gpt4 key购买 nike

我的代码Activity

class 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)
}
}
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>
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>
观察到的行为
enter image description here
预期行为
配置更改后,运动布局保持在其开始状态
编辑(骇人听闻的解决方案)
我最终创建了这些扩展功能
  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
)
)
}
然后我这样称呼他们: onCreate , onCreateView
    if (savedInstanceState != null) {
binding.transactionsMotionLayout.restoreState(savedInstanceState, MOTION_LAYOUT_STATE_KEY)
}
onSaveInstanceState
    binding.transactionsMotionLayout.saveState(outState, MOTION_LAYOUT_STATE_KEY)
这导致了 MotionLayouts 的预期行为。在 Activity s 和 MotionLayouts里面 Fragment s。但我对所需的代码量不满意,所以如果有人能提出更清洁的解决方案,我会很高兴听到这个:)

最佳答案

我不明白你为什么没有这样做,但你需要扩展 MotionLayout正确保存 View 状态。
您当前的解决方案(除了需要在 Activity 和 fragment 层进行额外处理)在可拆卸 fragment 的情况下将失败,因为它们在内部处理 View 保存状态而没有实际填充 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
}
你需要在你的 XML 中使用这个类而不是 MotionLayout但是它不太容易出错,并且会尊重正确的 View 状态保存机制,因此您不再需要向 Activity 或 fragment 添加任何额外的代码。
如果您想禁用保存,可以使用 android:saveEnabled="false" XML 或 isSaveEnabled = false在代码中。

关于android - 如何在不自动播放过渡的情况下恢复 MotionLayout 的过渡状态?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/65048418/

26 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com