Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it possible to disable MotionLayout?

I'v got a Fragment that hosts a RecyclerView within a MotionLayout. On top of the recycler view I've got a view that collapses and expands, all done in my motion scene. It is triggered by a click as well as responding to dragging the recycler view. So far this all works as intended.

Now comes the crux: I'd like to hide the collapsing views completely for some states within my app. But if I set the views visibility or change its height, it still comes back into view when I drag the recyclerview.

So is it possible to disable the MotionLayout completely (Lock the constraints) until I enable it again. To disable the drag recogniser would also be a viable solution.

Now some simplified XML to demonstrate the situation.

The layout containing the motion layout with header view and recyclerview

<?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"
    xmlns:tools="http://schemas.android.com/tools"
    android:id="@+id/favouritesMotionLayout"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    app:layoutDescription="@xml/favourites_motion_scene"
    android:animateLayoutChanges="true">

    <ImageView
        android:id="@+id/headerView"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        ...
        />

    <androidx.swiperefreshlayout.widget.SwipeRefreshLayout
        android:id="@+id/swipeRefreshLayout"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        ...
    >

        <androidx.recyclerview.widget.RecyclerVieww
            android:id="@+id/favoritesList"
            android:layout_width="match_parent"
            android:layout_height="match_parent" />

    </androidx.swiperefreshlayout.widget.SwipeRefreshLayout>

</androidx.constraintlayout.motion.widget.MotionLayout>

The corresponding motion 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:constraintSetStart="@id/expanded"
        motion:constraintSetEnd="@id/collapsed"
        motion:duration="300">
        <OnSwipe
            motion:touchAnchorId="@id/swipeRefreshLayout"
            motion:touchAnchorSide="top"
            motion:dragDirection="dragUp" />
    </Transition>

    <ConstraintSet android:id="@+id/expanded">
        ... Constraints for expanded header ...
    </ConstraintSet>

    <ConstraintSet android:id="@+id/collapsed">
        ... ... Constraints for collapsed header ...
    </ConstraintSet>

</MotionScene>

Using constraint layout version "2.0.0-alpha3"

implementation "com.android.support.constraint:constraint-layout:2.0.0-alpha3"

So recap: I'd like to be able to disable the motion layout, so that I can scroll the recyclerview without the header expanding, until I tell it to be enabled again. Unfortunately it is not as easy as favouritesMotionLayout.isEnabled = false, but that is the way I was thinking.

like image 855
stephanmantel Avatar asked Mar 12 '19 10:03

stephanmantel


3 Answers

Now with ConstraintLayout beta 2 you can! This is the official way to do it:

motionLayout.getTransition(R.id.yourTransition).setEnable(false)

like image 59
LPirro Avatar answered Sep 28 '22 08:09

LPirro


Recently I've been hacking around MotionLayout a lot, so far I found my trick to disable Motionlayout is like below.

layoutContainer.setTransitionListener(object: MotionLayout.TransitionListener {
        override fun onTransitionTrigger(p0: MotionLayout?, p1: Int, p2: Boolean, p3: Float) {}
        override fun onTransitionStarted(p0: MotionLayout?, p1: Int, p2: Int) {}
        override fun onTransitionCompleted(p0: MotionLayout?, p1: Int) {}
        override fun onTransitionChange(p0: MotionLayout?, startedScene: Int, endScene: Int, p3: Float) {
            when(currentFragmentTag) {
                TAG_DEFAULTBACKGROUND ->  {
                    if( startedScene==R.id.halfExpanded ) {
                        layoutContainer.transitionToState(startedScene)
                    }
                }
            }
        }
    })

So basically, I'm telling to MotionLayout to go back on certain situations. I feel like onTransitionTrigger or onTransitionStarted should contain the stopping function but it won't listen at those moments.

onTransitionChange is where it actually starts moving. I think you'll get the point of this trick vice versa.

Happy coding!

like image 32
John Lee Avatar answered Sep 28 '22 06:09

John Lee


Actually, i managed to get it working by setting the start state of my scene for both start and end. In kotlin:

motionLayout.setTransition(R.id.start, R.id.start)

And when i needed to enable my layout:

motionLayout.setTransition(R.id.start, R.id.end)

No need to change your scene xml, worked flawlessly for me in alpha-03

like image 40
Lucas Rodrigues Avatar answered Sep 28 '22 07:09

Lucas Rodrigues