Не удается использовать MotionLayout и настроить видимость с помощью привязки данных

Я использую implementation 'androidx.constraintlayout:constraintlayout:2.0.0-beta1', и у меня включена привязка данных.

Когда мой взгляд

<ImageView
            android:id="@+id/im_lightning"
            android:layout_width="24dp"
            android:layout_height="24dp"
            android:layout_marginTop="24dp"
            android:layout_marginEnd="4dp"
            android:contentDescription="@string/charging"
            android:src="@drawable/ic_lightning"
            android:visibility="@{batteryViewModel.liveData.charging ? View.VISIBLE : View.GONE}"
            app:layout_constraintBottom_toBottomOf="@id/tv_percent"
            app:layout_constraintRight_toLeftOf="@id/tv_percent"
            app:layout_constraintTop_toTopOf="@id/tv_percent"
            app:layout_constraintVertical_bias="1.0" />

Оборачивается вокруг макета координатора, изменения его видимости происходят должным образом. Как только я оборачиваю его в MotionLayout, изменения видимости перестают работать, как раньше. Если быть точным, вид не отображается, когда должен быть. Он становится видимым на секунду после запуска события, а затем снова становится невидимым. Это известная ошибка?

Код на случай, если понадобится:

Схема координатора:

<androidx.constraintlayout.widget.ConstraintLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorBackground">
        <ImageView (same as above) />
</androidx.constraintlayout.widget.ConstraintLayout>

Макет движения:

<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"
    tools:context=".ui.MainActivity">

    <androidx.constraintlayout.motion.widget.MotionLayout
        android:id="@+id/motion_layout"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:background="@color/colorBackground"
        app:layoutDescription="@xml/home_scene_0"
        app:showPaths="true">

        <ImageView (same as above) />
    </androidx.constraintlayout.motion.widget.MotionLayout>
    <data>
        <import type="android.view.View" />
        <variable
            name="batteryViewModel"
            type="rish.crearo.minimalphone.viewmodels.BatteryViewModel" />
    </data>
</layout>

person Crearo Rotar    schedule 01.09.2019    source источник
comment
@ tim-castelijns Что действительно беспокоит меня в SO - до такой степени, что я просто не люблю публиковать здесь вопросы - это вопросы, помеченные как повторяющиеся / не относящиеся к теме yada yada без объяснения или предоставления ссылки на повторяющийся вопрос. Я благодарен вам за то, что вы нашли время отметить этот вопрос, но без обратной связи я не смогу лучше задать вопрос в следующий раз, когда опубликую на StackOverflow. Кроме того, я снова искал это, похоже, я нигде не могу найти этот вопрос.   -  person Crearo Rotar    schedule 16.09.2019
comment
Не знаете, какой ответ вы ожидаете, кроме ответа на связанный вопрос. Вопрос неплохой, улучшать не надо. Макет движения контролирует видимость его дочерних элементов. Казалось, что проблема здесь такая же, как и там, отсюда и конец. Если вы скажете, что ответ на связанный вопрос вам не подходит, я с радостью открою ваш вопрос повторно.   -  person Tim    schedule 16.09.2019
comment
@ tim-castelijns Прошу прощения. Между ссылкой вверху вопроса и помеченным как дубликат внизу я пропустил ссылку. Я прыгнул с пистолета! Связанный вопрос работает для меня.   -  person Crearo Rotar    schedule 17.09.2019


Ответы (1)


У меня такая же проблема. Кажется, что если вы манипулируете одними и теми же атрибутами представления (в данном случае видимостью) в привязке данных и сцене движения, сцена движения превосходит привязанное значение, поэтому вам нужно привязать значение к сцене.

TL; DR Свяжите набор ограничений сцены движения атрибута представления (а не layout.xml)

Для этого я использовал @BindingAdapter.

@BindingAdapter("goneUnlessOnMotionLayout")
public static void goneUnlessOnMotionLayout(View view, boolean visible) {
  if (view.getParent() instanceof MotionLayout) {
        final MotionLayout layout = (MotionLayout) view.getParent();
        final int setToVisibility = visible ? View.VISIBLE : View.GONE;
        final float setToAlpha = visible ? 1f : 0f;

        for (int constraintId : layout.getConstraintSetIds()) {
            final ConstraintSet constraint = layout.getConstraintSet(constraintId);
            if (constraint != null) {
                constraint.setVisibility(view.getId(), setToVisibility);
                constraint.setAlpha(view.getId(), setToAlpha);
            }
        }
    }
}

обратите внимание на notifyPropertyChanged в вашей модели представления во время выполнения motionLayout, то есть motionLayout.progress! = 0 или 1, это вызовет разрыв естественного движения между ограничениями

person Idan    schedule 16.09.2019
comment
Выглядит многообещающе. Я попробую и отметлю правильно, если работает! - person Crearo Rotar; 16.09.2019
comment
Ответ на этот вопрос SO работает. Я полагаю, что это более правильно, когда макет движения берет под контроль все представления внутри него, и поэтому вы должны указать это в ограничениях. - person Crearo Rotar; 17.09.2019
comment
Спасибо за решение @Idan. Я добавил constraint.applyTo(layout) к вашему решению, иначе оно не применило значение, пока я не смахнул. Я также пропустил часть setAlpha. - person Tobias Lindberg; 22.04.2020
comment
Спасибо, решение работает отлично, сначала оно не работало у меня должным образом, но я понял, что устанавливал app:visibilityMode="ignore" для ограничений начала / конца, что мешало правильной настройке видимости. Спасибо еще раз. - person ZakariaBK; 29.05.2020
comment
Привет, @Idan! Как ты используешь GoedUnlessOnMotionLayout в своей анимационной сцене? - person Sharas; 17.03.2021