I am using motion layout in my mainactivity. It is working proplerly. However when I move to other activities and navigate back to my mainactivity sometimes the activity is reset and the layout is in its starting state.How do I keep this from happening ? Apart from this I also have another question about motion layout which I have asked here
6 Answers
What I did was adding a field, a boolean field to be specific and use the life cycle to handle it.
private var hasMotionScrolled = false
override fun onResume() {
super.onResume()
if (hasMotionScrolled) motionLayout.progress = MOTION_TRANSITION_COMPLETED
}
override fun onPause() {
super.onPause()
hasMotionScrolled = motionLayout.progress > MOTION_TRANSITION_INITIAL
}
companion object {
private const val MOTION_TRANSITION_COMPLETED = 1F
private const val MOTION_TRANSITION_INITIAL = 0F
}
So in my case, motion layout is doing an animation related to scrolling. If this is not your case maybe you can use directly the motionLayout.progress
. My problem with using the progress
directly was that intermediate states would make other elements not visible when navigating back, that is why implemented an all or nothing boolean flag.
I don't see this as a clean solution, a flag is always something that means something else could have been better, if you can find something official, please let me know in the comments.

- 9,887
- 3
- 45
- 59
-
1Only working solution in combination with NavigationComponents. Small improvement: don't forget to save the variable in `onSaveInstanceState` – fklappan Jul 15 '20 at 21:16
You have to save/restore the progress of your MotionLayout:
override fun onSaveInstanceState(outState: Bundle) {
super.onSaveInstanceState(outState)
outState.putFloat("progress", motionLayout.progress)
}
override fun onCreate(savedInstanceState: Bundle?) {
...
if (savedInstanceState != null)
motionLayout.progress = savedInstanceState.getFloat("progress", 0f)
...
}

- 769
- 9
- 27
This is how I do it with Fragment
Create an instance variable on your Fragment
class:
var motionProgress = 0f // 0f being initial state
On your onViewCreated
function, give the current value to the layout:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
binding.motionLayout.progress = motionProgress
}
Finally, when navigating away from the Fragment
, update the value of motionProgress
on function onPause
:
override fun onPause() {
super.onPause()
motionProgress = binding.motionLayout.progress
}

- 9,887
- 3
- 45
- 59

- 739
- 6
- 10
You can add a transition listener to the motion layout & save a flag when the transition is completed. Afterwards, when the activity gets recreated, you can read that flag and use smth like:
motionLayout.setState(R.id.end, ConstraintSet.WRAP_CONTENT, ConstraintSet.WRAP_CONTENT)
Where R.id.end is the id from constraintSetEnd property.
class ExtMotionLayout : MotionLayout {
constructor(context: Context) : super(context)
constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
override fun onSaveInstanceState(): Parcelable? {
return SavedState(progress, super.onSaveInstanceState())
}
override fun onRestoreInstanceState(state: Parcelable?) {
if (state is SavedState) {
progress = state.progress
super.onRestoreInstanceState(state.superState)
} else super.onRestoreInstanceState(state)
}
class SavedState : BaseSavedState {
val progress: Float
constructor(progress: Float, source: Parcelable?) : super(source) {
this.progress = progress
}
constructor(superState: Parcel) : super(superState) {
progress = superState.readFloat()
}
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeFloat(progress)
}
}
}

- 9
- 1
class CustomMotionLayout(context: Context, attrs: AttributeSet) : MotionLayout(context, attrs) {
init {
isSaveEnabled = true
}
override fun onSaveInstanceState(): Parcelable {
return SavedState(progress, super.onSaveInstanceState())
}
override fun onRestoreInstanceState(state: Parcelable?) {
if (state is SavedState) {
progress = state.progress
super.onRestoreInstanceState(state.superState)
} else super.onRestoreInstanceState(state)
}
class SavedState(val progress: Float, source: Parcelable?) : BaseSavedState(source) {
override fun writeToParcel(out: Parcel, flags: Int) {
super.writeToParcel(out, flags)
out.writeFloat(progress)
}
}
}
Use CustomMotionLayout
instead of default MotionLayout
Just keep in mind to provide id to your motion layout

- 121
- 3