Проблема с несколькими переходами в Android MotionLayout

Я играю с MotionLayout в Android. Я использую альфа 2 версию.

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

Я хочу реагировать на два разных нажатия кнопок и запускать анимацию для каждого из них. Мой текущий подход состоит в том, чтобы установить два Transitions в MotionScene с OnClick триггер в каждом.

Проблема в том, что только первый переход кажется найденным. Со вторым просто ничего не происходит. Я делаю что-то не так или вы можете просто установить один переход на MotionScene? Если это так, то есть ли другое решение проблемы?

Вот важные части моей сцены движения

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

Любая помощь приветствуется.

С наилучшими пожеланиями

6 ответов

У меня такая же проблема. Решение, которое я нашел, состояло в том, чтобы выбрать, какой из переходов:

(в коде Java)...

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();//                
        });

Более котлинный ответ:

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

Поддерживаются множественные переходы.

В коде, которым вы поделились, у вас есть 4 набора ограничений: start_home -> end_home, start_search -> end_search. Вместо этого используйте только 3 набора, один из которых является базовым состоянием, например start -> end_home и start -> end_search. «Начало» здесь представляет собой базовое состояние экрана.

Это происходит потому, что, скажем, вы сначала выполнили домашнее действие, а затем вы выполнили действие поиска, тогда поиск не будет работать, потому что начальные критерии (start_search) не будут соответствовать start_home или end_home (которые были применены последними)

Я думаю, что Аба права. У меня также возникла проблема с добавлением нескольких переходов в один файл сцены. Теоретически MotionLayout должен поддерживать это, потому что каждый переход будет иметь отдельный триггер (часто как щелчок или смахивание). Возможно, это ошибка MotionLayout, которую нужно исправить. Исходя из моего опыта, обрабатывается только первый переход, который встречается в файле сцены. Итак, в настоящее время я не думаю, что есть способ поддерживать более одного перехода в описании макета (сцене). Говоря более конкретно, все движения должны запускаться один раз одним и тем же триггером.

Привет, после некоторого удара и попытки, я нашел хороший способ, и я сделаю все возможное, чтобы сделать его как можно проще. Если у вас все еще есть сомнения, не стесняйтесь спрашивать!

Итак, как вы сказали, вам нужно 2 перехода для 2 кнопок сравнения с помощью onClick

Что вы можете сделать, так это иметь 2 перехода diff с их соответствующим набором ограничений

как например:

         <Transition 
android:id="@+id/transition_1" 
motion:constraintSetEnd="@+id/2" 
motion:constraintSetStart="@id/1" 
motion:duration="150">

</Transition>

<Transition 
android:id="@+id/transition_2" 
motion:constraintSetEnd="@+id/4" 
motion:constraintSetStart="@id/3" 
motion:duration="150">

</Transition>

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

        <Constraint
            android:id="@+id/v1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />

        <Constraint
            android:id="@+id/v2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>
    
    <ConstraintSet android:id="@+id/2">

        <Constraint
            android:id="@+id/v1"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />

        <Constraint
            android:id="@+id/v2"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>
    
    <ConstraintSet android:id="@+id/3">

        <Constraint
            android:id="@+id/v3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />

        <Constraint
            android:id="@+id/v4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>
    
    <ConstraintSet android:id="@+id/4">

        <Constraint
            android:id="@+id/v3"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />

        <Constraint
            android:id="@+id/v4"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            motion:layout_constraintBottom_toBottomOf="parent"
            motion:layout_constraintEnd_toEndOf="parent"
            motion:layout_constraintStart_toStartOf="parent" />
    </ConstraintSet>

Затем добавьте код в onClick, чтобы программно воспроизвести этот переход.

         // CODE LIKE THIS IN YOUR ONCLICK BUTTON FUNCTION FOR 1st BUTTON
motionLayoutObject.setTransition(R.id.transition_1)
motionLayoutObject.transitionToEnd()

         // CODE LIKE THIS IN YOUR ONCLICK BUTTON FUNCTION FOR 2nd BUTTON
motionLayoutObject.setTransition(R.id.transition_2)
motionLayoutObject.transitionToEnd()

Мне кажется, что MotionLayout поддерживает только один Transition, когда вы добавляете второй Transition к MotionScene подать второй Transitionпохоже, игнорируется. Однако у вас может быть несколько MotionLayout в вашем макете и создать MotionScene для каждого MotionLayout. Это также сохранит MotionScene очиститель файлов и упрощает обслуживание.

В вашем файле макета вам понадобится родительский макет, который может содержать несколько MotionLayout файлы.

<?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>

Сцена движения первая.

<?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>

Сцена движения вторая

<?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>

Это единственное решение XML, которое я мог придумать.

Другие вопросы по тегам