ConstraintLayout - центрирование видов рядом друг с другом по вертикали или горизонтали

Как выровнять по центру 3 кнопки рядом друг с другом по вертикали, используя ConstraintLayout?

Чтобы было ясно, я хочу преобразовать эту простую структуру макета в плоский пользовательский интерфейс, используя ConstraintLayout

<?xml version="1.0" encoding="utf-8"?>
<FrameLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">
<LinearLayout
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:layout_gravity="center"
    android:orientation="vertical">
    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />

    <Button
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        />
</LinearLayout>
</FrameLayout>

Я получил ближайшее решение следующим образом

<android.support.constraint.ConstraintLayout
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"
android:layout_width="match_parent"
android:layout_height="match_parent">


<Button
    android:id="@+id/button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintBottom_toTopOf="@+id/button2"
    />

<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    tools:layout_conversion_absoluteHeight="48dp"
    tools:layout_conversion_absoluteWidth="88dp"
    tools:layout_conversion_absoluteX="148dp"
    tools:layout_conversion_absoluteY="259dp"
    app:layout_constraintBottom_toTopOf="@+id/button3"
    app:layout_constraintTop_toBottomOf="@+id/button"
    app:layout_constraintRight_toRightOf="parent"/>

<Button
    android:id="@+id/button3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"

    app:layout_constraintLeft_toLeftOf="parent"
    tools:layout_conversion_absoluteHeight="48dp"
    tools:layout_conversion_absoluteWidth="88dp"
    tools:layout_conversion_absoluteX="148dp"
    tools:layout_conversion_absoluteY="307dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button2"
    app:layout_constraintRight_toRightOf="parent"/>

 </android.support.constraint.ConstraintLayout>

Но ясно видно, что полученный результат не соответствует требуемому. я не хочу никаких полей или пробелов между 3 кнопками, все, что я хочу, это выровнять эти 3 кнопки по центру рядом друг с другом по вертикали, как они в LinearLayout, который имеет вертикальную ориентацию.


person Darish    schedule 30.03.2017    source источник


Ответы (2)


Правильное решение

Хорошо, что вы создали цепочку между этими тремя представлениями. Имея цепочку, вы можете указать «стиль» цепочки, и это повлияет на то, как представления распределяются по оси цепочки. Стиль цепочки можно контролировать с помощью кнопки «цепочка» прямо под видом:

введите описание изображения здесь

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

spread (по умолчанию)
введите здесь описание изображения

spread_inside
введите здесь описание изображения

упаковано
введите здесь описание изображения

Как видите, packed — это то, что вам нужно.
Установка стиля цепочки приведет к добавлению следующего атрибута к первому дочернему элементу в цепочке, поэтому вы можете сделать это также из XML:

app:layout_constraintVertical_chainStyle="packed"

Наивное решение

Решение, предложенное в другом ответе, может выглядеть так, как будто оно работает, но на самом деле это неподходящее решение для вашей проблемы. Рассмотрим случай, когда у вас есть виды с разной высотой, скажем, нижний больше. Это решение заблокирует средний вид в центре и расположит другие виды выше и ниже. Это не приведет к "группе по центру" (центрируется только средний вид). Вы можете увидеть сравнение на изображении ниже:

введите описание изображения здесь

person Maciej Ciemięga    schedule 30.03.2017
comment
Очень хороший пример, показывающий разницу между этим и наивным решением. - person Lorne Laliberte; 07.04.2017
comment
app:layout_constraintVertical_chainStyle="packed" в каком представлении находится это свойство? - person EpicPandaForce; 11.04.2018
comment
Почему у меня нет значка Цепи, я тоже использую последнюю студию. - person JPM; 21.08.2018
comment
@JPM Я считаю, что для того, чтобы увидеть значок цепочки над представлением в редакторе, между обоими элементами уже должно существовать ограничение. например, при вертикальном расположении верхнему требуется атрибут app:layout_constraintBottom_toTopOf="@id/view2", а нижнему — app:layout_constraintTop_toBottomOf="@id/view1". Вы можете добавить их с помощью визуального редактора, а не в XML. В качестве альтернативы вы можете выбрать несколько представлений в иерархии представлений, щелкнуть правой кнопкой мыши и добавить туда цепочку. - person Big McLargeHuge; 09.04.2019
comment
Какой интуитивный, естественный метод центрирования. - person Jeffrey Blattman; 17.06.2019
comment
Если я установлю visibility последнего представления на View.GONE во время выполнения, цепочки больше не центрируются. Есть идеи, как это исправить? - person Karthik; 12.08.2020
comment
@Karthik Правильно ли они отцентрированы, если вы сделаете это GONE не во время выполнения, а в файле xml? - person Maciej Ciemięga; 12.08.2020

«Редактор макетов» Android Studio

  1. перетащите три кнопки в «Редактор макетов» Android Studio

  2. Выберите эти кнопки вместе, перетащив мышь

  3. Упакуйте их вертикально, используя кнопку «упаковать» в «Редакторе макетов».

  4. Выровняйте их по центру по горизонтали с помощью кнопки «Выровнять по центру по горизонтали».

  5. Выровняйте их по центру по вертикали с помощью кнопки «Выровнять по центру по вертикали».

По xml


<?xml version="1.0" encoding="utf-8"?>
<android.support.constraint.ConstraintLayout
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"
android:layout_width="match_parent"
android:layout_height="match_parent"
tools:layout_editor_absoluteY="25dp"
tools:layout_editor_absoluteX="0dp">


<Button
    android:id="@+id/button1"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    app:layout_constraintVertical_chainStyle="packed"
    app:layout_constraintBottom_toTopOf="@+id/button2"
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"/>

<Button
    android:id="@+id/button2"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:layout_conversion_absoluteHeight="48dp"
    tools:layout_conversion_absoluteWidth="88dp"
    tools:layout_conversion_absoluteX="148dp"
    tools:layout_conversion_absoluteY="259dp"
    app:layout_constraintVertical_chainStyle="packed"
    app:layout_constraintBottom_toTopOf="@+id/button3"
    app:layout_constraintTop_toBottomOf="@+id/button1"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"/>

<Button
    android:id="@+id/button3"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    tools:layout_conversion_absoluteHeight="48dp"
    tools:layout_conversion_absoluteWidth="88dp"
    tools:layout_conversion_absoluteX="148dp"
    tools:layout_conversion_absoluteY="307dp"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/button2"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintLeft_toLeftOf="parent"/>
</android.support.constraint.ConstraintLayout>
person Darish    schedule 30.03.2017
comment
Имейте в виду, что это первое решение является наивным и недействительным. Это только обманет других разработчиков, пожалуйста, не предлагайте это ... то же самое и с принятым ответом. Только второе решение, которое было более подробно описано в моем ответе, является правильным подходом к правильному центрированию группы представлений в ConstraintLayout. - person Maciej Ciemięga; 31.03.2017
comment
В ConstraintLayout вы должны использовать только атрибут chainStyle, другое решение действительно больше похоже на хак для достижения центрирования группы, который только кажется решением проблемы из вопроса. Если есть правильное решение против неправильного, зачем кому-то вообще хотеть использовать неправильное...? Цепочки специально разработаны для решения проблемы группировки. Тем не менее, вы по-прежнему продвигаете неправильное решение как принятый ответ, а также как часть своего ответа. Это только одурачит других разработчиков, которые попытаются решить эту проблему в будущем, это действительно нехорошо. - person Maciej Ciemięga; 31.03.2017