ConstraintLayout: как исключить дочерний элемент из вычислений wrap_content - PullRequest
2 голосов
/ 16 марта 2020

Рассмотрим этот простой ConstraintLayout content_main.xml, где один View является "обычным", а другой View концептуально является частью анимированного фона, и в то же время является макетом относительно обычного View :

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:background="#000">

    <!--LinearLayout    Fixes 'wrap_content' but breaks positioning
            android:layout_width="0dp"
            android:layout_height="0dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            app:layout_constraintRight_toRightOf="parent"-->

    <View
            android:id="@+id/shouldBeExcludedFromWrapContent"
            android:layout_width="100dp"
            android:layout_height="100dp"
            android:layout_marginTop="30dp"
            app:layout_constraintTop_toBottomOf="@id/partOfWrapContent"
            app:layout_constraintLeft_toRightOf="@id/partOfWrapContent"
            android:background="@android:drawable/star_big_on" />

    <!--/LinearLayout-->

    <View
            android:id="@+id/partOfWrapContent"
            android:layout_width="300dp"
            android:layout_height="300dp"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintLeft_toLeftOf="parent"
            android:background="@android:drawable/sym_action_call" />

</androidx.constraintlayout.widget.ConstraintLayout>

со следующим в MainActivity.onCreate():

        setContentView(R.layout.content_main)
        findViewById<View>(R.id.shouldBeExcludedFromWrapContent)
            .animate()
            .rotationBy(5 * 360f)
            .translationXBy(-900f)
            .translationYBy(-900f)
            .setDuration(5_000L)
            .start()

это приводит к следующей анимации (оба с androidx.constraintlayout:constraintlayout:1.1.3 и 2.0.0-beta4):

actual result

Вопрос

Как я могу игнорировать вычисления wrap_content @id/shouldBeExcludedFromWrapContent? Я хочу, чтобы его обрезал родительский элемент, поэтому конечный результат будет следующим:

expected

Примечание:

  • крайне важно , чтобы анимированное представление было макетом относительно его родного брата через ConstraintLayout (Взломать родительский контроль, который я привел в качестве примера выше, не вариант. В реальном коде отношения являются гораздо более сложными и не могут быть аппроксимированы или дублированы)

  • android:layout_height должно быть wrap_content, потому что реальный макет имеет динамическое c содержание / высоту и является часть ScrollView

Принятие ответа

Должно быть либо

  • ссылка на авторитетный источник о том, что это не поддерживается (например, ссылка на официальный трекер проблем для ConstraintLayout, где это обсуждалось, или ссылка на исходный код ConstraintLayout), или

  • решение для Задача сформулирована в заголовке (или эквивалентном)

Ответы [ 5 ]

1 голос
/ 28 марта 2020

вам просто нужно добавить это для вашего shouldBeExcludedFromWrapContent просмотра.

    android:translationX="100dp"
    android:translationY="100dp"

И обновите свои ограничения следующим образом. По этой причине ваша группа просмотра занимает ненужное место.

    app:layout_constraintTop_toBottomOf="@id/partOfWrapContent"
    app:layout_constraintLeft_toRightOf="@id/partOfWrapContent"

до

    app:layout_constraintRight_toRightOf="@id/partOfWrapContent"
    app:layout_constraintBottom_toBottomOf="@id/partOfWrapContent"

Надеюсь, это поможет вам. Удачи. ;)

0 голосов
/ 26 марта 2020

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

Мне удалось воспроизвести то, что вы хотите, и ниже вы видите результат .

код просто оборачивает ваш код в Framelayout следующим образом:

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="300dp"
android:layout_height="300dp"
android:id="@+id/frame">

<androidx.constraintlayout.widget.ConstraintLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="top|start"
    android:background="#000">


<View
    android:id="@+id/shouldBeExcludedFromWrapContent"
    android:layout_width="100dp"
    android:layout_height="100dp"
    app:layout_constraintTop_toBottomOf="@id/partOfWrapContent"
    app:layout_constraintLeft_toRightOf="@id/partOfWrapContent"
    android:background="@android:drawable/star_big_on" />



<View
    android:id="@+id/partOfWrapContent"
    android:layout_width="300dp"
    android:layout_height="300dp"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"
    android:background="@android:drawable/sym_action_call" />


</androidx.constraintlayout.widget.ConstraintLayout>
</FrameLayout>

есть один пропущенный шаг, как в этом коде: размеры framelayout жестко закодированы до 300dp, но если я правильно понимать, что вам нужно их обернуть в partOfWrapContent, который будет различаться по размеру. Исправление для этого не очень элегантно, но вы можете сделать это в java с помощью следующего кода

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.test);
    FrameLayout frame=(FrameLayout) findViewById(R.id.frame) ;
    View partOfWrapContent=(View) findViewById(R.id.partOfWrapContent);
    ViewGroup.LayoutParams params = frame.getLayoutParams();
    //get the desired size of your drawables in dp and feed it into dipH and dipW
    float dipH = 300f;
    float dipW = 300f;
    Resources r = getResources();
    float pxH = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dipH,
            r.getDisplayMetrics()
    );
    float pxW = TypedValue.applyDimension(
            TypedValue.COMPLEX_UNIT_DIP,
            dipW,
            r.getDisplayMetrics()
    );
    params.height=(int)pxH;
    params.width=(int)pxW;
    frame.setLayoutParams(params);
    findViewById(R.id.shouldBeExcludedFromWrapContent)
            .animate()
            .rotationBy(5 * 360f)
            .translationXBy(-900f)
            .translationYBy(-900f)
            .setDuration(5_000L)
            .start();


}

, в этом коде вам нужно будет указать размер partOfWrapContent, который, я думаю, вы можете получить из ваших доступных ресурсов. При таком подходе вы можете иметь анимированные объекты, поступающие из любого места (при условии, что это XD снизу или справа), но я полагаю, что вы можете немного изменить это, изменив android:layout_gravity="top|start" (возможно, используйте слишком большой контраст и вставьте partOfWrapContent в центре, таким образом, ваши анимированные объекты могут появиться откуда угодно) Я не уверен, что вам достаточно динамически c, но, возможно, это хотя бы даст вам некоторые идеи.

enter image description here

0 голосов
/ 24 марта 2020

Я бы создал один основной макет, который будет иметь «match_parent» или аналогичный размер. В этом макете вы можете иметь 2 дочерних элементов:

  1. ConstraintLayout с содержимым переноса.
  2. Вид со звездой

В данном случае вид звезды будет исключен из содержимого упаковки ConstraintLayout.

0 голосов
/ 26 марта 2020

Попробуйте изменить ограничение shouldBeExcludedFromWrapContent следующим образом:

app:layout_constraintTop_toBottomOf="@id/partOfWrapContent"  
app:layout_constraintLeft_toRightOf="@id/partOfWrapContent"

на

app:layout_constraintTop_toBottomOf="parent"  
app:layout_constraintLeft_toRightOf="parent"
0 голосов
/ 16 марта 2020

Не уверен, но это может быть решением, которое вы ищете. За исключением представления partOfWrapContent, сделайте все потомки высоты компоновки ограничения match_parent. Таким образом, макет противопоказания получит высоту представления partOfWrapContent. Это может решить вашу проблему. Надеюсь, это поможет.

Обновление: попробуйте установить максимальную высоту для макета ограничения, как показано ниже:

android:layout_height="wrap_content"
app:layout_constraintHeight_max="40dp"
app:layout_constrainedHeight="true"
...