Espaçamento uniforme de vistas usando ConstraintLayout

Respostas:

323

Existem duas maneiras de fazer isso usando ConstraintLayout: Cadeias e diretrizes . Para usar cadeias, verifique se você está usando o ConstraintLayoutBeta 3 ou mais recente e se deseja usar o editor de layout visual no Android Studio, verifique se está usando o Android Studio 2.3 Beta 1 ou mais recente.

Método 1 - usando cadeias

Abra o editor de layout e adicione seus widgets normalmente, adicionando restrições pai, conforme necessário. Nesse caso, adicionei dois botões com restrições na parte inferior do pai e no lado do pai (lado esquerdo para o botão Salvar e lado direito para o botão Compartilhar):

insira a descrição da imagem aqui

Observe que, nesse estado, se eu alternar para a visualização em paisagem, as visualizações não preenchem o pai, mas são ancoradas nos cantos:

insira a descrição da imagem aqui

Destaque as duas vistas, clicando Ctrl / Cmd ou arrastando uma caixa ao redor das vistas:

insira a descrição da imagem aqui

Em seguida, clique com o botão direito do mouse nas visualizações e escolha "Centralizar horizontalmente":

insira a descrição da imagem aqui

Isso configura uma conexão bidirecional entre as visualizações (que é como uma Cadeia é definida). Por padrão, o estilo da cadeia é "spread", aplicado mesmo quando nenhum atributo XML é incluído. Aderindo-se a esse estilo de cadeia, mas definindo a largura de nossas visualizações, 0dppermite que elas preencham o espaço disponível, espalhando-se uniformemente pelo pai:

insira a descrição da imagem aqui

Isso é mais perceptível na exibição em paisagem:

insira a descrição da imagem aqui

Se você preferir pular o editor de layout, o XML resultante será semelhante a:

<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>

Detalhes:

  • definir a largura de cada item como 0dpou MATCH_CONSTRAINTpermitir que as visualizações preencham o pai (opcional)
  • as visualizações devem ser vinculadas bidirecionalmente (links à direita do botão salvar para compartilhar, à esquerda nos links para compartilhar), isso ocorrerá automaticamente através do editor de layout ao escolher "Centralizar horizontalmente"
  • a primeira vista da cadeia pode especificar o estilo da cadeia layout_constraintHorizontal_chainStyle, consulte a documentação para vários estilos de cadeia. Se o estilo da cadeia for omitido, o padrão será "spread".
  • a ponderação da corrente pode ser ajustada via layout_constraintHorizontal_weight
  • Neste exemplo, para uma cadeia horizontal, existem atributos correspondentes para cadeias verticais

Método 2 - Usando uma Diretriz

Abra seu layout no editor e clique no botão de orientação:

insira a descrição da imagem aqui

Em seguida, selecione "Adicionar orientação vertical": insira a descrição da imagem aqui

Uma nova diretriz será exibida e, por padrão, provavelmente será ancorada à esquerda em valores relativos (indicados pela seta voltada para a esquerda):

orientação relativa do editor de layout

Clique na seta voltada para a esquerda para alternar para um valor percentual e arraste a diretriz para a marca de 50%:

orientação percentual do editor de layout

A diretriz agora pode ser usada como uma âncora para outras visualizações. No meu exemplo, anexei o lado direito do botão Salvar e o lado esquerdo do botão compartilhar à diretriz:

layout final

Se você deseja que as visualizações preencham o espaço disponível, a restrição deve ser definida como "Qualquer tamanho" (as linhas onduladas que estão na horizontal):

qualquer restrição de tamanho

(É o mesmo que definir layout_widthpara 0dp).

Uma diretriz também pode ser criada em XML com bastante facilidade, em vez de usar o editor de layout:

<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
fonte
1
Não consegui encontrar uma maneira de criar uma diretriz com uma restrição. Eu quero que uma orientação horizontal esteja no meio de duas visualizações. Imagine uma visualização maior com 100dp de altura na parte superior e menor com 50dp de altura na parte inferior. Eu quero colocar uma orientação no meio do espaço entre eles.
headsvk
3
Não acho que você possa adicionar restrições à própria diretriz. Você pode adicionar várias diretrizes e restringir as visualizações a essas diretrizes. Você pode postar uma nova pergunta com detalhes sobre o que você está tentando alcançar. Sinta-se livre para colá-lo aqui também.
AdamK
Obrigado, caro senhor. Foi uma ajuda oportuna e eficaz.
iSofia 12/09
Eu quero dar largura proporcional às visualizações. Por exemplo, eu quero que o botão de compartilhamento tenha o dobro da largura do botão de salvar. Sem usar diretrizes, pois minhas visualizações não são posicionadas próximas umas das outras, como neste exemplo. é possível?
Shubham Naik
Você precisa converter os valores fornecidos pelas diretrizes em margens ou preenchimentos reais. As diretrizes funcionam apenas no modo de design.
Abhinav Saxena
49

Para criar duas vistas na mesma linha, largura igual, basta definir

<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>

Nota

  • width = 0dp ( MATCH_CONSTRAINT)
  • Restrição button1e button2deve gostar acima

Resultado

MAIS
Se você quiser View1maior do View2que pode usar weightou percent.
Exemplo, View1width = 2 * View2width use weight

<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>

Resultado

Exemplo, View1largura = 2 * View2largura usa porcentagem

<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>

Resultado

Phan Van Linh
fonte
23

Bem, se isso ajuda alguém

a chave está aqui app:layout_constraintHorizontal_weight="1"e
a melhor coisa sobre o layout de restrição é que ele suporta dependência circular e aqui é isso que eu fiz usando exatamente isso.

Para o primeiro filho
app:layout_constraintEnd_toStartOf="@+id/textInputSecondChild"

Para o segundo filho

app:layout_constraintLeft_toRightOf="@+id/textInputFirstChild"

aqui está a demonstração completa

<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
fonte
9

Você deve ler sobre correntes pesadas. Um exemplo de código está aqui.

<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>

Assim, definir android:layout_width="0dp", app:layout_constraintHorizontal_weight="1"e vincular cada ponto de vista com os países vizinhos, como:

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

insira a descrição da imagem aqui

CoolMind
fonte
qual o sentido de postar mais uma resposta exatamente como outra, postada há dois anos?
@ Subzero, eu vi muitas vezes respostas iguais com taxa alta. Até as linhas de código eram as mesmas. Eu suspeito, alguns autores copiaram dos meus e até conseguiram mais vantagens. Nesse caso, as respostas são diferentes, também usei outras fontes para entender como os pesos funcionam ConstraintLayout, e a primeira resposta não foi suficiente para obter uma imagem acima.
CoolMind 19/07/19
3

Depois de ter seus itens encadeados, você ainda poderá usá-los como um layout relativo para mantê-los espaçados uniformemente. O exemplo abaixo mostra como mantê-los espaçados uniformemente com diferentes tamanhos de 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" />

insira a descrição da imagem aqui

tzg
fonte