Równomierne rozmieszczenie widoków przy użyciu ConstraintLayout

Odpowiedzi:

323

Istnieją dwa sposoby osiągnięcia tego za pomocą ConstraintLayout: łańcuchów i wytycznych . Aby używać łańcuchów, upewnij się, że używasz wersji ConstraintLayoutBeta 3 lub nowszej, a jeśli chcesz korzystać z edytora układu graficznego w Android Studio, upewnij się, że korzystasz z Android Studio 2.3 Beta 1 lub nowszego.

Metoda 1 - Korzystanie z łańcuchów

Otwórz edytor układu i dodaj swoje widżety w zwykły sposób, dodając w razie potrzeby ograniczenia nadrzędne. W tym przypadku dodałem dwa przyciski z ograniczeniami u dołu rodzica i po stronie rodzica (lewa strona dla przycisku Zapisz i prawa strona dla przycisku Udostępnij):

wprowadź opis obrazu tutaj

Zauważ, że w tym stanie, jeśli przewrócę do widoku poziomego, widoki nie wypełniają rodzica, ale są zakotwiczone w rogach:

wprowadź opis obrazu tutaj

Podświetl oba widoki, klikając Ctrl / Cmd lub przeciągając ramkę wokół widoków:

wprowadź opis obrazu tutaj

Następnie kliknij prawym przyciskiem myszy widoki i wybierz „Wyśrodkuj w poziomie”:

wprowadź opis obrazu tutaj

Tworzy to dwukierunkowe połączenie między widokami (tak definiuje się łańcuch). Domyślnie stylem łańcucha jest „spread”, który jest stosowany nawet wtedy, gdy nie jest dołączony żaden atrybut XML. Trzymając się tego stylu łańcucha, ale ustawiając szerokość naszych widoków, aby 0dpumożliwić widokom wypełnienie dostępnej przestrzeni, równomiernie rozłożone na rodzica:

wprowadź opis obrazu tutaj

Jest to bardziej widoczne w widoku poziomym:

wprowadź opis obrazu tutaj

Jeśli wolisz pominąć edytor układu, wynikowy kod XML będzie wyglądał następująco:

<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
    android:id="@+id/button_save"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="@string/button_save_text"
    android:layout_marginStart="8dp"
    android:layout_marginBottom="8dp"
    android:layout_marginEnd="4dp"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintRight_toLeftOf="@+id/button_share"
    app:layout_constraintHorizontal_chainStyle="spread" />

<Button
    android:id="@+id/button_share"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    android:text="@string/button_share_text"
    android:layout_marginStart="4dp"
    android:layout_marginEnd="8dp"
    android:layout_marginBottom="8dp"
    app:layout_constraintLeft_toRightOf="@+id/button_save"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintBottom_toBottomOf="parent" />

</android.support.constraint.ConstraintLayout>

Detale:

  • ustawienie szerokości każdego elementu na 0dp lub MATCH_CONSTRAINTumożliwienie widokom wypełnienia elementu nadrzędnego (opcjonalnie)
  • widoki muszą być połączone ze sobą dwukierunkowo (po prawej stronie przycisku Zapisz łącza do przycisku udostępniania, po lewej stronie od przycisku udostępniania łącza do przycisku zapisywania), nastąpi to automatycznie za pośrednictwem edytora układu po wybraniu opcji „Wyśrodkuj w poziomie”
  • pierwszy widok w łańcuchu może określać styl łańcucha za pomocą layout_constraintHorizontal_chainStyle, patrz dokumentacja dla różnych stylów łańcucha, jeśli pominięto styl łańcucha, domyślną wartością jest „rozłożenie”
  • ciężar łańcucha można regulować za pomocą layout_constraintHorizontal_weight
  • ten przykład dotyczy łańcucha poziomego, istnieją odpowiednie atrybuty dla łańcuchów pionowych

Metoda 2 - Korzystanie z wytycznych

Otwórz układ w edytorze i kliknij przycisk wskazówek:

wprowadź opis obrazu tutaj

Następnie wybierz „Dodaj wytyczne pionowe”: wprowadź opis obrazu tutaj

Pojawi się nowa wytyczna, która domyślnie będzie prawdopodobnie zakotwiczona po lewej stronie w wartościach względnych (oznaczonych strzałką skierowaną w lewo):

względne wytyczne edytora układu

Kliknij strzałkę skierowaną w lewo, aby przełączyć ją na wartość procentową, a następnie przeciągnij prowadnicę do znaku 50%:

Wytyczna procentowa edytora układu

Wytycznej można teraz używać jako zakotwiczenia dla innych widoków. W moim przykładzie dołączyłem prawą stronę przycisku zapisywania i lewą stronę przycisku udostępniania do wytycznych:

ostateczny układ

Jeśli chcesz, aby widoki wypełniały dostępne miejsce, ograniczenie powinno być ustawione na „Dowolny rozmiar” (faliste linie biegnące poziomo):

dowolne ograniczenie rozmiaru

(To jest to samo, co ustawienie layout_widthna0dp ).

Wytyczne można również utworzyć w XML dość łatwo, zamiast za pomocą edytora układu:

<android.support.constraint.Guideline
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:id="@+id/guideline"
    android:orientation="vertical"
    app:layout_constraintGuide_percent="0.5" />
AdamK
źródło
1
Nie mogłem znaleźć sposobu na stworzenie wytycznych z ograniczeniami. Chcę, aby wytyczna pozioma znajdowała się pośrodku dwóch widoków. Wyobraź sobie większy widok z wysokością 100 dp na górze i mniejszy z wysokością 50 dp na dole. Chcę umieścić prowadnicę w środku przestrzeni między nimi.
headsvk
3
Myślę, że nie można dodawać ograniczeń do samych wytycznych. Możesz dodać wiele wytycznych, a następnie ograniczyć widoki do tych wytycznych. Możesz zadać nowe pytanie ze szczegółami na temat tego, co próbujesz osiągnąć. Możesz również wkleić go tutaj.
AdamK
Dziękuję, drogi panie. To była szybka i skuteczna pomoc.
iSofia
Chcę nadać widokom proporcjonalną szerokość. Na przykład chcę, aby przycisk udostępniania miał dwukrotnie większą szerokość niż przycisk zapisywania. Bez wytycznych, ponieważ moje widoki nie są umieszczone obok siebie, jak w tym przykładzie. Czy to możliwe?
Shubham Naik
Musisz przeliczyć wartości podane przez wytyczne na rzeczywiste marginesy lub wypełnienia. Wytyczne działają tylko w trybie projektowania.
Abhinav Saxena,
49

Aby utworzyć 2 widoki w tej samej linii, o równej szerokości, wystarczy zdefiniować

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    >

    <Button
        android:id="@+id/button1"
        android:layout_width="0dp"  
        android:layout_height="wrap_content"
        android:text="Button 1"
        app:layout_constraintEnd_toStartOf="@+id/button2"
        app:layout_constraintStart_toStartOf="parent" />

    <Button
        android:id="@+id/button2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 2"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button1" />

</android.support.constraint.ConstraintLayout>

Uwaga

  • width = 0dp (MATCH_CONSTRAINT )
  • Ograniczenie button1i button2musi jak powyżej

Wynik

WIĘCEJ
Jeśli chcesz mieć View1większy rozmiar niż View2możesz użyć weightlub percent.
Przykład: View1szerokość = 2 * View2szerokość użyj wagi

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <Button
        android:id="@+id/button3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 3"
        app:layout_constraintEnd_toStartOf="@+id/button4"
        app:layout_constraintHorizontal_weight="2"
        app:layout_constraintStart_toStartOf="parent"
        />

    <Button
        android:id="@+id/button4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 4"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@+id/button3"
        />

</android.support.constraint.ConstraintLayout>

Wynik

Na przykład View1szerokość = 2 * View2szerokość użyj procentu

<android.support.constraint.ConstraintLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    >

    <Button
        android:id="@+id/button5"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 5"
        app:layout_constraintEnd_toStartOf="@+id/button6"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintWidth_percent="0.667"
        />

    <Button
        android:id="@+id/button6"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:text="Button 6"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toEndOf="@+id/button5"
        app:layout_constraintWidth_percent="0.333"
        />

</android.support.constraint.ConstraintLayout>

Wynik

Phan Van Linh
źródło
23

Cóż, jeśli to komuś pomoże

kluczem jest tu app:layout_constraintHorizontal_weight="1"i
najlepiej o układzie ograniczeniem jest to, że obsługuje zależność cykliczna i tutaj jest to, co mam zrobić używając dokładnie tego.

Na pierwsze dziecko
app:layout_constraintEnd_toStartOf="@+id/textInputSecondChild"

Na drugie dziecko

app:layout_constraintLeft_toRightOf="@+id/textInputFirstChild"

tutaj jest pełne demo

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputParent"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintRight_toRightOf="parent">

    <EditText
        android:id="@+id/editTextParent"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/state" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputFirstChild"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintEnd_toStartOf="@+id/textInputSecondChild"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintLeft_toLeftOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textInputParent">

    <EditText
        android:id="@+id/editTextChildOne"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/pin_code" />
</android.support.design.widget.TextInputLayout>

<android.support.design.widget.TextInputLayout
    android:id="@+id/textInputSecondChild"
    android:layout_width="0dp"
    android:layout_height="wrap_content"
    app:layout_constraintHorizontal_weight="1"
    app:layout_constraintLeft_toRightOf="@+id/textInputFirstChild"
    app:layout_constraintRight_toRightOf="parent"
    app:layout_constraintTop_toBottomOf="@+id/textInputParent">

    <EditText
        android:id="@+id/editTextChildSecond"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:hint="@string/country" />
</android.support.design.widget.TextInputLayout>
rookieDeveloper
źródło
9

Powinieneś przeczytać o obciążonych łańcuchach. Przykład kodu jest tutaj.

<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="wrap_content"
    >

    <TextView
        android:id="@+id/figure_1"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toStartOf="@id/figure_2"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toStartOf="parent"
        tools:text="1"
        />

    <TextView
        android:id="@+id/figure_2"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toStartOf="@id/figure_3"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/figure_1"
        tools:text="2"
        />

    <TextView
        android:id="@+id/figure_3"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        android:layout_marginEnd="8dp"
        android:layout_marginRight="8dp"
        app:layout_constraintEnd_toStartOf="@id/figure_4"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/figure_2"
        tools:text="3"
        />

    <TextView
        android:id="@+id/figure_4"
        android:layout_width="0dp"
        android:layout_height="wrap_content"
        android:layout_marginStart="8dp"
        android:layout_marginLeft="8dp"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintHorizontal_weight="1"
        app:layout_constraintStart_toEndOf="@id/figure_3"
        tools:text="4"
        />
</android.support.constraint.ConstraintLayout>

Tak ustawić android:layout_width="0dp", app:layout_constraintHorizontal_weight="1"a następnie połączyć każdy widok z sąsiadów, takich jak:

app:layout_constraintStart_toEndOf="@id/figure_2"
app:layout_constraintEnd_toStartOf="@id/figure_4"

wprowadź opis obrazu tutaj

CoolMind
źródło
Jaki sens ma publikowanie jeszcze jednej odpowiedzi, dokładnie takiej jak inna, opublikowanej dwa lata temu?
@ Subzero, widziałem wiele razy równe odpowiedzi z wysoką stawką. Nawet linie kodu były takie same. Podejrzewam, że niektórzy autorzy skopiowali moje i dostali nawet więcej plusów. W tym przypadku odpowiedzi są różne, użyłem również innych źródeł, aby zrozumieć, jak działają wagi ConstraintLayout, i tylko pierwsza odpowiedź nie wystarczyła, aby uzyskać powyższy obrazek.
CoolMind,
3

Gdy już masz swoje powiązane elementy, nadal możesz używać na nich ciężarów, takich jak układ względny, aby zachować je równomiernie. Poniższy przykład pokazuje, jak zachować je w równych odstępach z różnymi rozmiarami textViews.

<TextView1
     app:layout_constraintHorizontal_weight="1" />
 <TextView2
     app:layout_constraintHorizontal_weight="1" />
 <TextView3
     app:layout_constraintHorizontal_weight="1" />
 <TextView4
     app:layout_constraintHorizontal_weight="1" />

wprowadź opis obrazu tutaj

tzg
źródło