aba
aba

Reputation: 233

Problem with multiple Transitions in Android MotionLayout

I'm playing around with the MotionLayout in Android. I'm using the alpha 2 version.

'com.android.support.constraint:constraint-layout:2.0.0-alpha2'

I want to react to two different button clicks and trigger an animation for each of them. My current approach is to set two Transitions in the MotionScene with an OnClick trigger in each one.

The problem is that only the first transition seems to be found. For the second one just nothing happens. Am I doing something wrong or can you just set one transition per MotionScene? If that's the case ist there a different solution to the problem?

Here are the important parts of my Motion Scene

<MotionScene xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:motion="http://schemas.android.com/apk/res-auto">

<Transition
    motion:constraintSetStart="@id/startHome"
    motion:constraintSetEnd="@id/endHome"
    motion:duration="300">
    <OnClick
        motion:mode="toggle"
        motion:target="@+id/imageView_bottom_home" />
</Transition>

<Transition
    motion:constraintSetStart="@id/startSearch"
    motion:constraintSetEnd="@id/endSearch"
    motion:duration="300">
    <OnClick
        motion:mode="toggle"
        motion:target="@+id/imageView_bottom_search" />
</Transition>

<ConstraintSet android:id="@+id/startSearch">
    <Constraint
        android:id="@id/imageView_bottom_search"
        ...startConstraints... />
</ConstraintSet>

<ConstraintSet android:id="@+id/endSearch">
    <Constraint
        android:id="@id/imageView_bottom_search"
        ...endConstraints... />
</ConstraintSet>

<ConstraintSet android:id="@+id/startHome">
    <Constraint
        android:id="@id/imageView_bottom_home"
        ...startConstraints... />
</ConstraintSet>

<ConstraintSet android:id="@+id/endHome">
    <Constraint
        android:id="@id/imageView_bottom_home"
        ...endConstraints... />
</ConstraintSet>

Any help appreciated.

Best regards

Upvotes: 21

Views: 13650

Answers (5)

Ganges
Ganges

Reputation: 11

Multiple transitions are supported.

In the code you shared, you have 4 constraint sets, start_home -> end_home, start_search -> end_search. Instead, have only 3 sets, with one being the base state like, start -> end_home and start -> end_search. The 'start' here represents the base state of the screen

This happens because, say you did the home action first and then you did the search action, then the search is not going to work because the starting criteria (start_search) is not going to match the start_home or end_home (which got applied last)

Upvotes: 1

Shawn
Shawn

Reputation: 1392

Seems to me that MotionLayout only supports one Transition, when you add a second Transition to the MotionScene file the second Transition appears to be ignored. You can however have multiple MotionLayouts in your layout and create a MotionScene for each MotionLayout. This will also keep the MotionScene file cleaner and allow for easier maintenance.

In your layout file, you'll need a Parent layout that can contain multiple MotionLayout files.

<?xml version="1.0" encoding="utf-8"?>
<layout 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">

    <data>
        ...
    </data>

    <!-- [databinding] {"msg":"Only one layout element with 1 view child is allowed. So a Parent Layout is required for Multiple motion layouts. -->
    <FrameLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <androidx.constraintlayout.motion.widget.MotionLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutDescription="@xml/motion_scene_01"
            tools:context=".menu.contextual.FragmentContextualOne"
            tools:showPath="true">

            <Button
                android:id="@+id/btn_one"
                android:layout_width="64dp"
                android:layout_height="64dp"
                tools:layout_editor_absoluteX="8dp"
                tools:layout_editor_absoluteY="310dp" />
        </androidx.constraintlayout.motion.widget.MotionLayout>

        <androidx.constraintlayout.motion.widget.MotionLayout
            android:id="@+id/m2"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            app:layoutDescription="@xml/motion_scene_02">

            <Button
                android:id="@+id/btn_two"
                android:layout_width="64dp"
                android:layout_height="64dp"
                tools:layout_editor_absoluteX="8dp"
                tools:layout_editor_absoluteY="500dp" />
        </androidx.constraintlayout.motion.widget.MotionLayout>
    </FrameLayout>
</layout>

Motion Scene One.

<?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
            android:id="@+id/transition_sine_wave"
            motion:constraintSetStart="@+id/wave_start"  
            motion:constraintSetEnd="@+id/wave_end"
            motion:duration="2000"
            motion:motionInterpolator="linear">
            <OnClick
                motion:touchAnchorId="@+id/btn_one"
                motion:touchAnchorSide="right"
                motion:targetId="@+id/btn_one"/>
        </Transition>

    <ConstraintSet android:id="@+id/wave_start">
        <Constraint
            android:id="@+id/btn_one"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginStart="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintTop_toTopOf="parent"
            motion:layout_constraintStart_toStartOf="parent"/>

    </ConstraintSet>

    <ConstraintSet android:id="@+id/wave_end">
        <Constraint
            android:id="@+id/btn_one"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginEnd="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintTop_toTopOf="parent" />
    </ConstraintSet>
</MotionScene>

Motion Scene Two

<?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
        android:id="@+id/transition_straight"
        motion:constraintSetEnd="@+id/right_end"
        motion:constraintSetStart="@+id/left_start"
        motion:duration="2000"
        motion:motionInterpolator="linear" >
        <OnClick
            motion:targetId="@+id/btn_two"
            motion:clickAction="toggle"/>
    </Transition>

    <ConstraintSet android:id="@+id/left_start">
        <Constraint
            android:id="@+id/btn_two"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginStart="8dp"
            android:layout_marginBottom="100dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>

    <ConstraintSet android:id="@+id/right_end">
        <Constraint
            android:id="@+id/btn_two"
            android:layout_width="64dp"
            android:layout_height="64dp"
            android:layout_marginEnd="8dp"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent" />
    </ConstraintSet>
</MotionScene>

This is the only XML solution I could come up with.

Upvotes: 0

Dambakk
Dambakk

Reputation: 665

A more kotlin'y answer:

with(view as MotionLayout) {
    setTransition(R.id.startState, R.id.endState)
    transitionToEnd()
}

Upvotes: 1

Mehdi Haghgoo
Mehdi Haghgoo

Reputation: 3484

I think aba is right. I am also having problem adding multiple transitions to a single scene file. Theoretically, MotionLayout should support this because every transition will have a separate trigger (often as click or swipe). Maybe this is a bug with MotionLayout that needs to be fixed. Out of my experience, only the first transition that is encountered in the scene file is cared for. So, currently, I don't think there is a way to support more than one transition in a layout description (scene). To put it more specifically, all motion needs to be started once with the same trigger.

Upvotes: 0

close_file
close_file

Reputation: 331

I had the same problem. The solution I found was to select which one transitions:

(in java code)...

MotionLayout motionConteiner = findViewById(R.id.motion_container);
button1.setOnClickListener((v) -> {
            motionConteiner.setTransition(R.id.start1, R.id.end1);
            motionConteiner.transitionToEnd();//                
        });
button2.setOnClickListener((v) -> {
            motionConteiner.setTransition(R.id.start2, R.id.end2);
            motionConteiner.transitionToEnd();//                
        });

Upvotes: 19

Related Questions