0

I'm trying to add multiple animations in my MotionLayout. The scene currently has two Transitions but will eventually have four.

First transition is kind of a mix between YouTube Player and Netflix Player where controllers disappear either by dropping down or shrinking.

The second transition is a simple rotation applied on the rewindButton.

Layout Hierarchy:

MotionLayout (First transition <OnClick>)
    -> Previous Button.
    -> Rewind Button. (Second transition <OnClick>)
    -> Play/Plause Button.
    -> Forward Button.
    -> Next Button.
    -> Other Views.

Layout for reference:

<androidx.constraintlayout.motion.widget.MotionLayout
    android:id="@+id/playerUIContainer"

    android:layout_width="match_parent"
    android:layout_height="match_parent"

    android:background="#00000000"
    android:elevation="3dp"

    app:layoutDescription="@xml/player_controls_animations"

    tools:background="#000000"
    tools:visibility="visible"
    >

    <com.aaa.views.UntouchableCarouselView
        android:id="@+id/screenshotsView"

        android:layout_width="match_parent"
        android:layout_height="match_parent"

        android:focusable="false"
        android:clickable="false"

        android:visibility="gone"

        app:indicatorVisibility="gone"

        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        app:slideInterval="10000"

        tools:visibility="visible"
        />

    <ImageView
        android:id="@+id/backButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_marginTop="10dp"
        android:layout_marginEnd="5dp"

        android:padding="5dp"

        android:contentDescription="@string/dummyImageDescription"
        android:src="@drawable/ic_back"

        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"

        tools:visibility="visible"
        />

    <TextView
        android:id="@+id/contentTitle"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="5dp"
        android:textColor="#FFFFFF"
        android:textSize="@dimen/player_content_title_text_size"
        android:textStyle="bold"

        app:layout_constraintStart_toEndOf="@id/backButton"
        app:layout_constraintEnd_toStartOf="@id/channelListButton"
        app:layout_constraintTop_toTopOf="@id/backButton"
        app:layout_constraintBottom_toBottomOf="@id/backButton"

        tools:text="Harry Potter and The Prisoner of Azkaban"
        tools:visibility="visible"
        />

    <ImageView
        android:id="@+id/channelListButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginTop="10dp"
        android:layout_marginEnd="10dp"
        android:src="@drawable/menu"
        android:padding="5dp"
        android:contentDescription="@string/dummyImageDescription"

        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintBottom_toBottomOf="@+id/backButton"

        android:visibility="gone"

        tools:visibility="gone"
        />

    <ImageView
        android:id="@+id/rewindButton"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:src="@drawable/ic_rewind_10"

        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toStartOf="@id/prevButton"
        app:layout_constraintTop_toTopOf="@id/playPauseButton"
        app:layout_constraintBottom_toBottomOf="@id/playPauseButton"

        app:layout_constraintHorizontal_chainStyle="spread"
        />

    <ImageView
        android:id="@+id/prevButton"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:src="@drawable/previous"
        android:padding="5dp"
        android:contentDescription="@string/dummyImageDescription"

        app:layout_constraintStart_toEndOf="@id/rewindButton"
        app:layout_constraintEnd_toStartOf="@+id/playPauseButton"
        app:layout_constraintTop_toTopOf="@id/playPauseButton"
        app:layout_constraintBottom_toBottomOf="@id/playPauseButton"

        app:layout_constraintHorizontal_chainStyle="spread"

        android:visibility="gone"

        tools:visibility="gone"
        />

    <ImageView
        android:id="@+id/playPauseButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:src="@drawable/ic_pause"
        android:padding="5dp"
        android:contentDescription="@string/dummyImageDescription"

        app:layout_constraintStart_toEndOf="@id/prevButton"
        app:layout_constraintEnd_toStartOf="@id/nextButton"
        app:layout_constraintTop_toBottomOf="@id/contentTitle"
        app:layout_constraintBottom_toTopOf="@id/timeSeekBar"

        app:layout_constraintHorizontal_chainStyle="spread"

        tools:visibility="visible"
        />

    <ImageView
        android:id="@+id/nextButton"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:src="@drawable/next"
        android:padding="5dp"
        android:contentDescription="@string/dummyImageDescription"

        app:layout_constraintStart_toEndOf="@+id/playPauseButton"
        app:layout_constraintEnd_toStartOf="@id/forwardButton"
        app:layout_constraintTop_toTopOf="@id/playPauseButton"
        app:layout_constraintBottom_toBottomOf="@id/playPauseButton"

        app:layout_constraintHorizontal_chainStyle="spread"

        android:visibility="gone"

        tools:visibility="gone"
        />

    <ImageView
        android:id="@+id/forwardButton"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:src="@drawable/ic_forward_10"

        app:layout_constraintStart_toEndOf="@id/nextButton"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toTopOf="@id/playPauseButton"
        app:layout_constraintBottom_toBottomOf="@id/playPauseButton"

        app:layout_constraintHorizontal_chainStyle="spread"
        />

    <ProgressBar
        android:id="@+id/playerLoading"

        style="?android:attr/progressBarStyleLarge"
        android:layout_width="@dimen/player_loading_width"
        android:layout_height="@dimen/player_loading_height"
        android:visibility="gone"

        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintTop_toBottomOf="@id/contentTitle"
        app:layout_constraintBottom_toTopOf="@id/timeSeekBar"

        tools:visibility="visible"
        />

    <TextView
        android:id="@+id/playerProgressUpdate"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:visibility="gone"

        android:textSize="@dimen/player_buffering_text_size"
        android:textColor="@color/white"

        app:layout_constraintLeft_toLeftOf="@id/playerLoading"
        app:layout_constraintRight_toRightOf="@id/playerLoading"
        app:layout_constraintTop_toBottomOf="@id/playerLoading"

        tools:text="90%"
        tools:visibility="visible"
        />

    <TextView
        android:id="@+id/seedsCount"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:textSize="@dimen/player_torrent_info_text_size"
        android:textColor="@color/white"

        app:layout_constraintEnd_toEndOf="@id/peersCount"
        app:layout_constraintBottom_toTopOf="@id/peersCount"

        android:visibility="visible"
        android:alpha="1"

        tools:text="50"
        tools:visibility="visible"
        />

    <TextView
        android:id="@+id/peersCount"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:textSize="@dimen/player_torrent_info_text_size"
        android:textColor="@color/white"

        app:layout_constraintEnd_toEndOf="@id/playerDownloadSpeed"
        app:layout_constraintBottom_toTopOf="@id/playerDownloadSpeed"

        android:visibility="visible"

        tools:text="3"
        tools:visibility="visible"
        />

    <TextView
        android:id="@+id/playerDownloadSpeed"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:textSize="@dimen/player_torrent_info_text_size"
        android:textColor="@color/white"

        android:layout_marginBottom="10dp"

        app:layout_constraintBottom_toTopOf="@id/totalDuration"
        app:layout_constraintEnd_toEndOf="@id/totalDuration"

        android:visibility="visible"

        tools:text="123.45 KB/s"
        tools:visibility="visible"
        />

    <ImageView
        android:id="@+id/subtitlesSwitchBtn"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:src="@drawable/ic_subtitles_on"
        android:background="@color/black"

        app:layout_constraintStart_toStartOf="@id/currentPosition"
        app:layout_constraintBottom_toTopOf="@id/currentPosition"
        />

    <TextView
        android:id="@+id/subtitlesText"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:textColor="@color/white"
        android:textSize="@dimen/player_subtitles_text_size"
        android:paddingStart="@dimen/player_subtitles_text_padding_start"
        android:paddingEnd="@dimen/player_subtitles_text_padding_end"
        android:gravity="center"

        android:background="@color/transparent_inversion_grey"

        android:visibility="gone"

        app:layout_constraintTop_toBottomOf="@id/playPauseButton"
        app:layout_constraintBottom_toTopOf="@id/timeSeekBar"
        app:layout_constraintStart_toEndOf="@id/subtitlesSwitchBtn"
        app:layout_constraintEnd_toStartOf="@id/playerDownloadSpeed"
        />

    <TextView
        android:id="@+id/currentPosition"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_marginStart="@dimen/player_ui_padding_start"
        android:layout_marginBottom="@dimen/player_ui_padding_bottom"

        android:gravity="center"

        android:text="@string/default_time"
        android:textSize="@dimen/player_current_time_text_size"
        android:textColor="#FFFFFF"
        android:singleLine="true"
        android:ellipsize="none"

        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"

        tools:text="@string/default_time"
        tools:visibility="visible"
        />

    <com.aaa.pieces_progressbar.PiecesSeekBar
        android:id="@+id/timeSeekBar"

        android:layout_width="0dp"
        android:layout_height="@dimen/player_seek_bar_height"

        android:layout_marginEnd="8dp"
        android:layout_marginStart="8dp"

        app:trackHeight="@dimen/player_seek_bar_track_height"

        android:thumb="@drawable/player_seek_bar_thumb"

        app:layout_constraintStart_toEndOf="@id/currentPosition"
        app:layout_constraintEnd_toStartOf="@id/totalDuration"
        app:layout_constraintTop_toTopOf="@+id/currentPosition"
        app:layout_constraintBottom_toBottomOf="@id/currentPosition"

        tools:visibility="visible"
        />

    <TextView
        android:id="@+id/totalDuration"

        android:layout_width="wrap_content"
        android:layout_height="wrap_content"

        android:layout_marginBottom="@dimen/player_ui_padding_bottom"
        android:layout_marginEnd="@dimen/player_ui_padding_end"

        android:gravity="center"

        android:text="@string/default_time"
        android:textColor="#FFFFFF"
        android:textSize="@dimen/player_current_time_text_size"
        android:singleLine="true"
        android:ellipsize="none"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toStartOf="@id/playerMaximizeButton"

        tools:text="@string/default_time"
        tools:visibility="visible"
        />

    <ImageView
        android:id="@+id/playerMaximizeButton"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_margin="5dp"
        android:visibility="visible"
        android:src="@drawable/ic_fullscreen_enter"
        android:layout_gravity="end"
        android:contentDescription="@string/dummyImageDescription"

        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"

        tools:visibility="gone"
        />
</androidx.constraintlayout.motion.widget.MotionLayout>

Scene Layout:

<MotionScene>

    <Transition
        motion:duration="1000"

        motion:constraintSetStart="@id/rewindRotationOnClick"
        motion:constraintSetEnd="@id/rewindRotationOnReset"

        motion:motionInterpolator="easeInOut"
        >

        <OnClick
            motion:targetId="@id/rewindButton"
            motion:clickAction="transitionToEnd"
            />

        <KeyFrameSet>
            <KeyAttribute
                motion:motionTarget="@id/rewindButton"

                android:rotation="0"
                motion:framePosition="1"
                />

            <KeyAttribute
                motion:motionTarget="@id/rewindButton"

                android:rotation="90"
                motion:framePosition="80"
                />

            <KeyAttribute
                motion:motionTarget="@id/rewindButton"

                android:rotation="0"
                motion:framePosition="99"
                />
        </KeyFrameSet>
    </Transition>

    <ConstraintSet
        android:id="@+id/rewindRotationOnClick"
        >

        <Constraint
            android:id="@id/rewindButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@id/prevButton"
            app:layout_constraintTop_toTopOf="@id/playPauseButton"
            app:layout_constraintBottom_toBottomOf="@id/playPauseButton"
            />
    </ConstraintSet>

    <ConstraintSet
        android:id="@+id/rewindRotationOnReset"
        >

        <Constraint
            android:id="@id/rewindButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@id/prevButton"
            app:layout_constraintTop_toTopOf="@id/playPauseButton"
            app:layout_constraintBottom_toBottomOf="@id/playPauseButton"
            />
    </ConstraintSet>

    <Transition
        motion:duration="@integer/player_controlsTransitionDuration"

        motion:constraintSetStart="@id/showControls"
        motion:constraintSetEnd="@id/hideControls"

        motion:motionInterpolator="easeIn"
        >

        <OnClick
            motion:clickAction="toggle"
            motion:targetId="@id/playerUIContainer"
            />
    </Transition>

    <ConstraintSet
        android:id="@+id/showControls"
        >

        <Constraint
            android:id="@id/rewindButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:alpha="1"

            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@id/prevButton"
            app:layout_constraintTop_toTopOf="@id/playPauseButton"
            app:layout_constraintBottom_toBottomOf="@id/playPauseButton"
            />

        <Constraint
            android:id="@id/playPauseButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:visibility="visible"

            app:layout_constraintStart_toEndOf="@id/prevButton"
            app:layout_constraintEnd_toStartOf="@id/nextButton"
            app:layout_constraintTop_toBottomOf="@id/contentTitle"
            app:layout_constraintBottom_toTopOf="@id/timeSeekBar"
            />

        <Constraint
            android:id="@id/forwardButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:alpha="1"

            app:layout_constraintStart_toEndOf="@id/playPauseButton"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@id/playPauseButton"
            app:layout_constraintBottom_toBottomOf="@id/playPauseButton"
            />

        <Constraint
            android:id="@id/currentPosition"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:layout_marginStart="@dimen/player_ui_padding_start"
            android:layout_marginBottom="@dimen/player_ui_padding_bottom"

            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            />

        <Constraint
            android:id="@id/subtitlesSwitchBtn"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toStartOf="@id/currentPosition"
            app:layout_constraintBottom_toTopOf="@id/currentPosition"
            />

        <Constraint
            android:id="@id/timeSeekBar"

            android:layout_width="0dp"
            android:layout_height="@dimen/player_seek_bar_height"

            android:layout_marginEnd="8dp"
            android:layout_marginStart="8dp"

            app:layout_constraintStart_toEndOf="@id/currentPosition"
            app:layout_constraintEnd_toStartOf="@id/totalDuration"
            app:layout_constraintTop_toTopOf="@+id/currentPosition"
            app:layout_constraintBottom_toBottomOf="@id/currentPosition"
            />

        <Constraint
            android:id="@id/seedsCount"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintEnd_toEndOf="@id/peersCount"
            app:layout_constraintBottom_toTopOf="@id/peersCount"
            />

        <Constraint
            android:id="@id/peersCount"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintEnd_toEndOf="@id/playerDownloadSpeed"
            app:layout_constraintBottom_toTopOf="@id/playerDownloadSpeed"
            />

        <Constraint
            android:id="@id/playerDownloadSpeed"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:layout_marginBottom="10dp"

            app:layout_constraintBottom_toTopOf="@id/totalDuration"
            app:layout_constraintEnd_toEndOf="@id/totalDuration"
            />

        <Constraint
            android:id="@id/totalDuration"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:layout_marginBottom="@dimen/player_ui_padding_bottom"
            android:layout_marginEnd="@dimen/player_ui_padding_end"

            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/playerMaximizeButton"
            />

        <Constraint
            android:id="@id/contentTitle"

            android:layout_width="0dp"
            android:layout_height="wrap_content"

            android:layout_marginStart="5dp"

            app:layout_constraintStart_toEndOf="@id/backButton"
            app:layout_constraintEnd_toStartOf="@id/channelListButton"
            app:layout_constraintTop_toTopOf="@id/backButton"
            app:layout_constraintBottom_toBottomOf="@id/backButton"
            />

        <Constraint
            android:id="@id/backButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            android:layout_marginTop="10dp"

            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            />
    </ConstraintSet>

    <ConstraintSet
        android:id="@+id/hideControls"
        >

        <Constraint
            android:id="@id/rewindButton"

            android:layout_width="0dp"
            android:layout_height="0dp"

            android:alpha="0"

            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintEnd_toStartOf="@id/prevButton"
            app:layout_constraintTop_toTopOf="@id/playPauseButton"
            app:layout_constraintBottom_toBottomOf="@id/playPauseButton"
            />

        <Constraint
            android:id="@id/playPauseButton"

            android:layout_width="0dp"
            android:layout_height="0dp"

            android:visibility="gone"

            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"
            app:layout_constraintTop_toBottomOf="@id/contentTitle"
            app:layout_constraintBottom_toTopOf="@id/timeSeekBar"
            />

        <Constraint
            android:id="@id/forwardButton"

            android:layout_width="0dp"
            android:layout_height="0dp"

            android:alpha="0"

            app:layout_constraintStart_toEndOf="@id/playPauseButton"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintTop_toTopOf="@id/playPauseButton"
            app:layout_constraintBottom_toBottomOf="@id/playPauseButton"
            />

        <Constraint
            android:id="@id/currentPosition"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="@id/totalDuration"
            />

        <Constraint
            android:id="@id/subtitlesSwitchBtn"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toStartOf="@id/currentPosition"
            app:layout_constraintTop_toTopOf="@id/playerDownloadSpeed"
            />

        <Constraint
            android:id="@id/timeSeekBar"

            android:layout_width="0dp"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toEndOf="@id/currentPosition"
            app:layout_constraintEnd_toStartOf="@id/totalDuration"
            app:layout_constraintTop_toTopOf="@id/totalDuration"
            />

        <Constraint
            android:id="@id/seedsCount"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintEnd_toEndOf="@id/peersCount"
            app:layout_constraintTop_toBottomOf="parent"
            />

        <Constraint
            android:id="@id/peersCount"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintEnd_toEndOf="@id/playerDownloadSpeed"
            app:layout_constraintTop_toBottomOf="@id/seedsCount"
            />

        <Constraint
            android:id="@id/playerDownloadSpeed"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintTop_toBottomOf="@id/peersCount"
            app:layout_constraintEnd_toEndOf="@id/totalDuration"
            />

        <Constraint
            android:id="@id/totalDuration"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintTop_toBottomOf="@id/playerDownloadSpeed"
            app:layout_constraintEnd_toStartOf="@id/playerMaximizeButton"
            />

        <Constraint
            android:id="@id/contentTitle"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintStart_toEndOf="@id/backButton"
            app:layout_constraintTop_toTopOf="@id/backButton"
            app:layout_constraintBottom_toBottomOf="@id/backButton"
            />

        <Constraint
            android:id="@id/backButton"

            android:layout_width="wrap_content"
            android:layout_height="wrap_content"

            app:layout_constraintBottom_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            />
    </ConstraintSet>
</MotionScene>

Start and end ConstraintSets are exactly the same for rewindButton and the animation takes place in the <KeyFrameSet>. That is because I want the rewindButton` to reset to its original state on completion.

Both these transitions work in the MotionLayout-Editor, the problem is only the first transition works.

The second transition only works if I remove the first transition from the scene. But only on first click, I don't know why.

ConstraintLayout Version: 2.0.4.

Abbas
  • 3,529
  • 5
  • 36
  • 64
  • are you sure it supports multiple transitions ? – a_local_nobody Feb 27 '21 at 19:21
  • @a_local_nobody Not sure, but it should. – Abbas Feb 27 '21 at 19:52
  • https://stackoverflow.com/questions/52997908/problem-with-multiple-transitions-in-android-motionlayout – a_local_nobody Feb 27 '21 at 19:54
  • @a_local_nobody yes, I saw this post, but the post merely implies that. – Abbas Feb 27 '21 at 19:58
  • @a_local_nobody Besides implementing the provided solutions or workarounds would not work in this case. The `onClick` listener on `rewindButton` is never fired when it is added as a target in the transition. Perhaps I could try placing the transition in another file unlinked to the original `MotionLayout`... I will try that and update here. – Abbas Feb 27 '21 at 20:02
  • There is also a google sample which provides uses multiple transitions: https://github.com/googlearchive/android-ConstraintLayoutExamples/blob/multi_state/motionlayout/src/main/res/xml/scene_26.xml. – Abbas Feb 27 '21 at 20:04
  • only reason i'm asking is because the last time i tried motion layout, i had a similar problem, but i didn't need it too badly, i was just playing around – a_local_nobody Feb 28 '21 at 05:43
  • @a_local_nobody To be honest neither do I, but I'd rather use the motion layout in this case for learning. I might end up using the method showed in your link or even use more traditional means for animations... But I'm in no hurry. – Abbas Feb 28 '21 at 06:01

0 Answers0