最新消息:雨落星辰是一个专注网站SEO优化、网站SEO诊断、搜索引擎研究、网络营销推广、网站策划运营及站长类的自媒体原创博客

android - Support configuration change with MutableTransitionState - Stack Overflow

programmeradmin0浏览0评论

I am using MutableTransitionState to support animation for a Popup in my Compose app. The problem is, the Popup disappears after a configuration change such as screen rotation because I am using expandedState = remember { MutableTransitionState(false) }.

I would like the Popup to survive a configuration change to improve user experience. In order to achieve this, I've written the following code:

data class Holder(var expandedState: MutableTransitionState<Boolean>)

val expandedSaver = Saver<Holder, MutableTransitionState<Boolean>>(
    save = { it.expandedState},
    restore = { Holder(it) }
)

@Composable
public fun SomeComposable() {
    val holder = rememberSaveable(stateSaver = expandedSaver) {
         mutableStateOf(Holder(MutableTransitionState(false)))
    }
    ...
}

However, when I run the code, I get the usual error complaining that I should consider implementing a custom Saver for this class despite already using a custom saver!

I am using MutableTransitionState to support animation for a Popup in my Compose app. The problem is, the Popup disappears after a configuration change such as screen rotation because I am using expandedState = remember { MutableTransitionState(false) }.

I would like the Popup to survive a configuration change to improve user experience. In order to achieve this, I've written the following code:

data class Holder(var expandedState: MutableTransitionState<Boolean>)

val expandedSaver = Saver<Holder, MutableTransitionState<Boolean>>(
    save = { it.expandedState},
    restore = { Holder(it) }
)

@Composable
public fun SomeComposable() {
    val holder = rememberSaveable(stateSaver = expandedSaver) {
         mutableStateOf(Holder(MutableTransitionState(false)))
    }
    ...
}

However, when I run the code, I get the usual error complaining that I should consider implementing a custom Saver for this class despite already using a custom saver!

Share Improve this question edited Feb 3 at 9:49 tyg 16.2k4 gold badges36 silver badges48 bronze badges asked Feb 2 at 15:48 kc_devkc_dev 7981 gold badge9 silver badges23 bronze badges
Add a comment  | 

1 Answer 1

Reset to default 1

Using rememberSaveable on a MutableTransitionState won't work.

You use the rememberSaveable overload with the stateSaver parameter. That implies that the value is a MutableState which is unnecessary. You probably meant to use the overload using the saver parameter.

But that won't work either. You would have to construct a MutableTransitionState off the single expanded property of your Holder, but a MutableTransitionState has both a currentState and a targetState property. You would need to save both if you want to restore the MutableTransitionState to what it was before. Furthermore, there is a third property isRunning which is internal and cannot be accessed by your code, so you will never be able to restore it.

Bottom line: You cannot fully save and restore a MutableTransitionState. After a configuration change at least some parts of the state are irrevocably lost.


If you are only interested in saving the targetState then the second approach you had in your original question is the way to go. You just need to update the MutableTransitionState's targetState when expanded changes1:

var expanded by rememberSaveable { mutableStateOf(false) }
val expandedState = remember { MutableTransitionState(expanded) }
    .apply { targetState = expanded }

The rest of your code shouldn't touch expandedState directly anymore, so it would be best to never save the MutableTransitionState in a variable in the first place. That would prevent accidently doing something like expandedState.targetState = !expandedState.targetState. When you only need it for an AnimatedVisibility you could rewrite it like this:

var expanded by rememberSaveable { mutableStateOf(false) }

AnimatedVisibility(
    visibleState = remember { MutableTransitionState(expanded) }
        .apply { targetState = expanded },
    // ...
)

Now only the expanded variable is accessible by the rest of your code (and it survives configuration changes), the MutableTransitionState is hidden but will always be updated accordingly when expanded changes.


1 expanded is used twice here. The first usage is needed when the MutableTransitionState is constructed to set the initial value. It is behind a remember, so it is only executed once (until a configuration change takes place, then it is executed again and a new MutableTransitionState is created).
The second usage is needed to actually start a transition. Whenever the MutableState expanded changes, a recomposition occurs. The remember lambda is skipped, but the apply is executed again, setting targetState to the new value.

发布评论

评论列表(0)

  1. 暂无评论