Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Motion Layout reset on navigating between activities

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

like image 406
Pemba Tamang Avatar asked Jan 02 '19 06:01

Pemba Tamang


People also ask

What is a motionlayout?

“A MotionLayout is a ConstraintLayout which allows you to animate layouts between various states.” — Developer Documentation I strongly suggest to anyone who hasn’t seen it yet to read this series of articles by Nicolas Roard that explains the key concepts of Motion Layout.

How do I convert an activity_main_scene to a motion layout?

Select the Convert to MotionLayout menu item. An activity_main_scene.xml is generated when you click the Convert to MotionLayout button demonstrated above. Let’s better understand the contents of this file.

How to implement animations in an Android application using motionlayout?

To implement animations in an Android application using MotionLayout. To follow along, you will need to have some knowledge of the Kotlin programming language. You should also have Android Studio 4.0 installed on your computer. Open Android studio and create a new project.

How do I create a motionlayout from an existing constraintlayout?

If you're using AndroidX, add the following dependency: Create a MotionLayout file: MotionLayout is a subclass of ConstraintLayout, so you can transform any existing ConstraintLayout into a MotionLayout by replacing the class name in your layout resource file, as shown in the following examples:


4 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.

like image 70
cutiko Avatar answered Jan 04 '23 03:01

cutiko


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)
        ...
    }
like image 36
kroegerama Avatar answered Jan 04 '23 03:01

kroegerama


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
}
like image 31
Jim Ovejera Avatar answered Jan 04 '23 03:01

Jim Ovejera


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.

like image 25
Andrei Avatar answered Jan 04 '23 03:01

Andrei