Проблема с несколькими переходами в 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>

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

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

15
0
9 847
5

Ответы 5

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

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

Спасибо за ваш ответ! Я подумал, что это способ заставить его работать, но это разрушает идею наличия всех частей анимации в xml. В основном переходы в xml устарели. Возможно, сейчас просто невозможно иметь более одного Перехода.

aba 28.10.2018 15:34

Таким образом, даже если вы хотите запустить анимацию по умолчанию без нажатия кнопки, этот код необходимо использовать. И это нигде не упоминается в Android Docs.

Lalit Fauzdar 20.03.2020 08:16

Это решение также используется в официальных примерах приложений - github.com/android/views-widgets-samples/blob/master/…

frangulyan 02.04.2020 02:23

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

Еще один ответ котлины:

with(view as MotionLayout) {
    setTransition(R.id.startState, R.id.endState)
    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, которое я смог придумать.

Разве это не устраняет причину появления ConstraintLayout?

Abbas 27.02.2021 19:33

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

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

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

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