Criar uma IU responsiva com o ConstraintLayout Parte do Android Jetpack.

O ConstraintLayout permite que você crie layouts grandes e complexos com uma hierarquia de visualização plana (sem grupos de visualização aninhados). Ele é semelhante a RelativeLayout: todas as visualizações são dispostas de acordo com as relações entre visualizações irmãs e layout pai, mas são mais flexíveis que RelativeLayout e mais fáceis de usar com o Layout Editor do Android Studio.

Todo o poder do ConstraintLayout está disponível diretamente nas ferramentas visuais do Layout Editor, porque a API de layout e o Layout Editor foram especialmente criados um para o outro. Assim, você pode criar todo o layout com o ConstraintLayout, usando o recurso de arrastar e soltar, em vez de editar o XML.

Esta página fornece um guia para criar um layout com o ConstraintLayout no Android Studio 3.0 ou versões posteriores. Para saber mais sobre o Layout Editor, consulte o guia do Android Studio para Criar uma IU com o Layout Editor.

Para ver uma variedade de layouts que você pode criar com o ConstraintLayout, confira o projeto de exemplos de layout restrito no GitHub (link em inglês).

Visão geral sobre restrições

Para definir a posição de uma visualização no ConstraintLayout, adicione pelo menos uma restrição horizontal e uma vertical para a visualização. Cada restrição representa uma conexão ou alinhamento para outra visualização, o layout pai ou uma linha guia invisível. Cada restrição define a posição da visualização ao longo do eixo vertical ou horizontal. Assim, cada visualização precisa ter pelo menos uma restrição para cada eixo, mas muitas vezes são necessárias mais.

Quando você solta uma visualização no Layout Editor, ela permanece onde você a deixou mesmo que não haja restrições. No entanto, isso serve apenas para facilitar a edição. Se uma visualização não tiver restrições quando você executar o layout em um dispositivo, ela será desenhada na posição [0,0], isto é, no canto superior esquerdo.

Na figura 1, o layout fica bem no editor, mas não há restrição vertical na visualização C. Quando esse layout é colocado em um dispositivo, a visualização C fica alinhada horizontalmente às extremidades esquerda e direita da visualização da propriedade A, mas aparece na parte superior da tela, porque não tem restrição vertical.

Figura 1. O editor mostra a visualização C abaixo de A, mas não tem restrição vertical.

Figura 2. A visualização C está agora verticalmente restrita abaixo da visualização A.

Embora a falta de uma restrição não cause um erro de compilação, o Layout Editor indica a ausência de restrições como um erro na barra de ferramentas. Para ver os erros e outros alertas, clique em Show Warnings and Errors. Para ajudar a evitar a ausência de restrições, o Layout Editor pode adicionar automaticamente restrições com os recursos Autoconnect and infer constraints.

Adicionar ConstraintLayout ao seu projeto

Para usar o ConstraintLayout no seu projeto, faça o seguinte:

  1. Certifique-se de que o repositório maven.google.com esteja declarado no seu arquivo build.gradle ao nível de módulo:
        repositories {
            google()
        }
        
  2. Adicione a biblioteca como uma dependência no mesmo arquivo build.gradle, conforme mostrado no exemplo a seguir. Observe que a versão mais recente pode ser diferente da mostrada no exemplo:
        dependencies {
            implementation 'com.android.support.constraint:constraint-layout:1.1.2'
        }
        
  3. Na barra de ferramentas ou na notificação de sincronização, clique em Sync Project with Gradle Files.

Agora você está pronto para criar seu layout com o ConstraintLayout.

Converter um layout

Figura 3. O menu para converter um layout no ConstraintLayout.

Para converter um layout já existente em um layout restrito, siga estas etapas:

  1. Abra o layout no Android Studio e clique na guia Design, na parte inferior da janela do editor.
  2. Na janela Component Tree, clique com o botão direito do mouse no layout e em Convert layout to ConstraintLayout .

Criar um novo layout

Para iniciar um novo arquivo de layout restrito, siga estas etapas:

  1. Na janela Project, clique na pasta do módulo e selecione File > New > XML > Layout XML .
  2. Digite um nome para o arquivo de layout e “android.support.constraint.ConstraintLayout” para a Root Tag.
  3. Clique em Finish.

Adicionar ou remover uma restrição

Para adicionar uma restrição, faça o seguinte:

Vídeo 1. O lado esquerdo de uma visualização está restrito ao lado esquerdo do pai.

  1. Arraste uma visualização da janela Palette para o editor.

    Quando você adiciona uma visualização em um ConstraintLayout, ele exibe uma caixa delimitadora com alças quadradas de redimensionamento em cada canto e alças circulares de restrições em cada lado.

  2. Clique na visualização para selecioná-la
  3. Realize uma das seguintes ações:
    • Clique em uma alça de restrição e arraste-a para um ponto de fixação disponível. Esse ponto pode ser a borda de outra visualização, a borda do layout ou uma linha guia. Observe que, conforme você arrasta a alça de restrição, o Layout Editor mostra possíveis âncoras de conexão e sobreposições azuis.
    • Clique em um dos botões Create a connection na seção Layout da janela Attributes, como mostrado na figura 4.

      Figura 4. A seção Layout da janela Attributes permite que você crie conexões.

Quando a restrição é criada, o editor fornece uma margem padrão para separar as duas visualizações.

Ao criar restrições, lembre-se das seguintes regras:

  • Cada visualização precisa ter pelo menos duas restrições: uma horizontal e uma vertical.
  • Você só pode criar restrições entre uma alça de restrição e um ponto de fixação que compartilham o mesmo plano. Assim, um plano vertical (os lados esquerdo e direito) de uma visualização só pode ser restrito a outro plano vertical; e as linhas de base só podem ser restritas a outras linhas de base.
  • Cada alça de restrição só pode ser usada para uma única restrição, mas você pode criar várias restrições (de diferentes visualizações de fixação) para o mesmo ponto.

Você pode excluir uma restrição realizando uma das seguintes ações:

  • Clique em uma restrição para selecioná-la e pressione Delete.
  • Pressione Control e mantenha essa opção pressionada (Command no macOS) e, em seguida, clique em um ponto de fixação de restrição. Observe que a restrição fica vermelha para indicar que você pode clicar para excluí-la, como mostrado na figura 5.

    Figura 5. Uma restrição vermelha indica que você pode clicar para excluí-la.

  • Na seção Layout da janela Attributes, clique em um ponto de fixação de restrição, como mostrado na figura 6.

    Figura 6. Clique em um ponto de fixação de restrição para excluí-la.

Vídeo 2. Como adicionar uma restrição que se opõe a outra já existente.

Se você adiciona restrições opostas em uma visualização, as linhas de restrição se tornam sinuosas como uma mola para indicar as forças opostas, como mostrado no vídeo 2. O efeito é mais visível quando o tamanho da visualização é definido como "fixed" ou "wrap content". Nesse caso, a visualização é centralizada entre as restrições. Se, em vez disso, você quiser que a visualização expanda o tamanho para atender às restrições, mude o tamanho para “match constraints” ou, se quiser manter o tamanho atual, mas mover a visualização para que ela não fique centralizada, ajuste o viés da restrição .

Você pode usar restrições para atingir diferentes tipos de comportamento de layout, conforme descrito nas seções a seguir.

Posição do pai

Restringir o lado de uma visualização à borda correspondente do layout.

Na figura 7, o lado esquerdo da visualização está conectado à borda esquerda do layout pai. Você pode definir a distância a partir da borda com margem.

Figura 7. Uma restrição horizontal em relação ao pai.

Posição da ordem

Defina a ordem de exibição de duas visualizações, vertical ou horizontalmente.

Na figura 8, B está restrito a ficar sempre à direita de A, e C está restrito abaixo de A. No entanto, essas restrições não implicam alinhamento, de modo que B ainda possa se mover para cima e para baixo.

Figura 8. Uma restrição horizontal e vertical.

Alinhamento

Alinhe a borda de uma visualização com a mesma borda de outra.

Na figura 9, o lado esquerdo de B está alinhado com o lado esquerdo de A. Para alinhar os centros de uma visualização, crie uma restrição em ambos os lados.

Você pode deslocar o alinhamento arrastando a visualização para dentro a partir da restrição. Por exemplo, a figura 10 mostra B com um alinhamento de deslocamento de 24 dp. O deslocamento é definido pela margem da visualização restrita.

Você também pode selecionar todas as visualizações que quer alinhar e, em seguida, clicar em Align na barra de ferramentas para selecionar o tipo de alinhamento.

Figura 9. Uma restrição de alinhamento horizontal.

Figura 10. Uma restrição de deslocamento de alinhamento horizontal.

Alinhamento da linha de base

Alinhe a linha de base do texto de uma visualização à linha de base do texto de outra.

Na figura 11, a primeira linha de B está alinhada com o texto em A.

Para criar uma restrição de linha de base, clique com o botão direito do mouse na visualização de texto que você quer restringir e, em seguida, clique em Show Baseline. Em seguida, clique na linha de base do texto e arraste a linha para outra linha de base.

Figura 11. Uma restrição de alinhamento da linha de base.

Restringir a uma linha guia

Você pode adicionar uma linha guia vertical ou horizontal à qual seja possível restringir visualizações. A linha guia ficará invisível para os usuários do app. Você pode posicionar a linha guia dentro do layout com base nas unidades de dp ou em porcentagem, em relação à borda do layout.

Para criar uma linha guia, clique em Guidelines na barra de ferramentas e clique em Add Vertical Guideline ou Add Horizontal Guideline.

Arraste a linha pontilhada para reposicioná-la e clique no círculo na borda da linha guia para alternar o modo de medição.

Figura 12. Uma visualização restrita a uma linha guia.

Restringir a uma barreira

Assim como uma linha guia, uma barreira é uma linha invisível à qual você pode restringir as visualizações. A exceção é que uma barreira não define a própria posição; em vez disso, a posição da barreira se move com base na posição das visualizações contidas nela. Isso é útil quando você quer restringir uma visualização a um conjunto em vez de a uma visualização específica.

Por exemplo, a figura 13 mostra que a visualização C está restrita ao lado direito de uma barreira. A barreira é definida como "extremidade" (ou o lado direito em um layout da esquerda para a direita) da visualização A e da visualização B. Portanto, a barreira se move dependendo de o lado direito da visualização A ou B estar mais à direita.

Para criar uma barreira, siga estas etapas:

  1. Clique em Guidelines na barra de ferramentas e depois clique em Add Vertical Barrier ou Add Horizontal Barrier.
  2. Na janela Component Tree, selecione as visualizações que precisam estar dentro da barreira e arraste-as para o componente de barreira.
  3. Selecione a barreira na Component Tree, abra a janela Attributes e defina o barrierDirection.

Agora você pode criar uma restrição de outra visualização para a barreira.

Você também pode restringir à barreira as visualizações que estão dentro dela. Dessa forma, você pode garantir que todas as visualizações na barreira estejam sempre alinhadas entre si, mesmo que não saiba qual será a maior ou a mais alta.

Você também pode incluir uma linha guia dentro de uma barreira para garantir uma posição “mínima” para ela.

Figura 13. A visualização C está restrita a uma barreira, que se move com base na posição/tamanho da visualização A e da visualização B.

Ajustar o viés da restrição

Quando você adiciona uma restrição a ambos os lados de uma visualização, e o tamanho da mesma dimensão é "fixed" ou "wrap content", a visualização fica centralizada entre as duas restrições com um viés de 50% por padrão. Você pode ajustar o viés arrastando o controle deslizante na janela Attributes ou arrastando a visualização, como mostrado no vídeo 3.

Se, em vez disso, você quiser que a visualização estenda o tamanho dela para atender às restrições, mude o tamanho para "match constraints".

Vídeo 3. Como ajustar o viés da restrição.

Ajustar o tamanho da visualização

Figura 14. Quando uma visualização é selecionada, a janela Attributes inclui controles para 1 proporção de tamanho, 2 exclusão de restrições, 3 altura/largura, 4 margens e 5 viés de restrição. Você também pode destacar restrições individuais no Layout Editor clicando nelas na 6 lista de restrições.

Você pode usar as alças dos cantos para redimensionar uma visualização, mas essa opção codifica o tamanho para que a visualização não seja redimensionada para diferentes tamanhos de tela ou de conteúdo. Para selecionar um modo de dimensionamento diferente, clique em uma visualização e abra a janela Attributes no lado direito do editor.

Perto da parte superior da janela Attributes está o inspetor de visualizações, que inclui controles para vários atributos de layout, como mostrado na figura 14. Ele está disponível somente para visualizações em um layout de restrição.

Você pode alterar a forma como a altura e a largura são calculadas clicando nos símbolos indicados com a frase de destaque 3 na figura 14. Esses símbolos representam o modo de tamanho como mostrado a seguir. Clique no símbolo para alternar entre essas configurações:

  • Fixed: você define uma dimensão específica na caixa de texto abaixo ou redimensiona a visualização no editor.
  • Wrap Content: a visualização se expande apenas o necessário para ajustar o conteúdo.
  • Match Constraints: a exibição se expande o máximo possível para atender às restrições de cada lado, depois de contabilizar as margens da visualização. No entanto, você pode modificar esse comportamento com os atributos e valores a seguir. Esses atributos entram em vigor somente quando você define a largura da visualização para corresponder às restrições:
    • layout_constraintWidth_default
      • spread: expande a visualização o máximo possível para atender às restrições de cada lado. Este é o comportamento padrão.
      • wrap: expande a visualização somente o necessário para ajustar o conteúdo, mas ainda permite que a visualização seja menor, se as restrições exigirem. Portanto, a diferença entre essa opção e o uso de Wrap Content (acima) é que a definição da largura como Wrap Content força a largura a corresponder exatamente à largura do conteúdo. Por outro lado, o uso de Match Constraints com layout_constraintWidth_default definido como wrap também permite que a visualização seja menor do que a largura do conteúdo.
    • layout_constraintWidth_min

      Isso leva uma dimensão dp para a largura mínima da visualização.

    • layout_constraintWidth_max

      Isso leva uma dimensão dp para a largura máxima da visualização.

    No entanto, se a dimensão especificada tem apenas uma restrição, a visualização se expande para ajustar o conteúdo. O uso desse modo na altura ou na largura também permite definir uma proporção de tamanho.

Observação: não é possível usar match_parent para nenhuma visualização em um ConstraintLayout. Em vez disso, use "match constraints" (0dp).

Figura 15. A visualização é definida como um aspecto de 16:9 com a largura com base em uma proporção da altura.

Definir o tamanho como uma proporção

Você pode definir o tamanho da visualização como uma proporção, como 16:9, se pelo menos uma das dimensões de visualização está definida como "match constraints" (0dp). Para ativar a proporção, clique em Toggle Aspect Ratio Constraints (frase de destaque 1 na figura 13) e, em seguida, digite a proporção largura:altura na entrada exibida.

Se a largura e a altura estiverem definidas para corresponder às restrições, você poderá clicar em Toggle Aspect Ratio Constraint para selecionar a dimensão com base na proporção da outra. O inspetor de visualização indica qual dimensão é definida como uma proporção conectando as bordas correspondentes a uma linha sólida.

Por exemplo, se você definir ambos os lados como "match constraints", clique em Toggle Aspect Ratio Constraint duas vezes para definir a largura como uma proporção da altura. Agora o tamanho total é determinado pela altura da visualização, que pode ser definida de qualquer forma, como mostrado na figura 15.

Ajustar as margens da visualização

Para garantir que todas as suas visualizações sejam espaçadas uniformemente, clique em Margin na barra de ferramentas para selecionar a margem padrão para cada visualização adicionada ao layout. Qualquer alteração feita à margem padrão se aplica somente às visualizações que você adiciona a partir de então.

Você pode controlar a margem de cada visualização na janela Attributes, clicando no número da linha que representa cada restrição. Na figura 13, a frase de destaque 4 mostra que a margem inferior está definida para 16 dp.

Figura 16. O botão Margin da barra de ferramentas.

Todas as margens oferecidas pela ferramenta são fatores de 8 dp para ajudar a alinhar suas visualizações com as Recomendações para a grade quadrada de 8dp.

Controlar grupos lineares com uma cadeia

Figura 17. Uma cadeia horizontal com duas visualizações.

Uma cadeia é um grupo de visualizações vinculadas umas às outras com restrições de posição bidirecionais. As visualizações em uma cadeia podem ser distribuídas vertical ou horizontalmente.

Figura 15. Exemplos de cada estilo de cadeia.

As cadeias podem ser estilizadas de uma das seguintes maneiras:

  1. Spread: as visualizações são distribuídas uniformemente depois que as margens são contabilizadas. Esse é o padrão.
  2. Spread inside: a primeira e a última visualizações ficam fixadas nas restrições de cada extremidade da cadeia, e o restante é distribuído uniformemente.
  3. Weighted: quando a cadeia é definida como spread ou spread inside, você pode preencher o espaço restante definindo uma ou mais visualizações como "match constraints" (0dp). Por padrão, o espaço é distribuído de maneira uniforme entre cada visualização definida como "match constraints", mas você pode atribuir uma importância ponderada a cada visualização usando os atributos layout_constraintHorizontal_weight e layout_constraintVertical_weight. Se você estiver familiarizado com layout_weight em um layout linear, isso funcionará da mesma maneira. Assim, a visualização com o maior valor ponderado terá mais espaço. As visualizações com o mesmo valor ponderado terão o mesmo espaço.
  4. Packed: as visualizações serão agrupadas depois que as margens forem contabilizadas. Em seguida, você pode ajustar o viés de toda a cadeia (esquerda/direita ou para cima/para baixo) mudando o viés principal de visualização da cadeia.

A visualização principal da cadeia, que corresponde à visualização mais à esquerda em uma cadeia horizontal e à visualização superior em uma cadeia vertical, define o estilo da cadeia em XML. No entanto, você pode alternar entre spread, spread inside e packed selecionando qualquer visualização na cadeia e, em seguida, clicando no botão de cadeia que aparece abaixo da visualização.

Para criar uma cadeia, selecione todas as visualizações da propriedade a serem incluídas, clique com o botão direito do mouse em uma das visualizações, selecione Chains e, em seguida, selecione Center Horizontally ou Center Vertically, como mostrado no vídeo 4:

Vídeo 4. Como criar uma cadeia horizontal.

Veja algumas outras coisas a serem consideradas ao usar cadeias:

  • Uma visualização pode fazer parte de uma cadeia vertical e horizontal, facilitando a criação de layouts de grade flexíveis.
  • Uma cadeia só funciona corretamente se cada extremidade está restrita a outro objeto no mesmo eixo, como mostrado na figura 14.
  • Embora a orientação de uma cadeia seja vertical ou horizontal, o uso de uma opção não alinha as visualizações naquela direção. Portanto, inclua outras restrições para conseguir a posição adequada para cada visualização na cadeia, por exemplo, restrições de alinhamento.

Criar restrições automaticamente

Em vez de adicionar restrições a todas as visualizações à medida que você as coloca no layout, é possível mover cada visualização para as posições desejadas e, em seguida, clicar em Infer Constraints para criar restrições automaticamente.

Infer Constraints verifica o layout para determinar o conjunto de restrições mais eficaz para todas as visualizações. Faz o possível para restringir as visualizações às suas posições atuais, permitindo flexibilidade. Talvez seja necessário fazer alguns ajustes para garantir que o layout responda da forma que você pretende para diferentes tamanhos de tela e orientações.

Autoconnect to parent é um recurso separado que você pode ativar. Se ativado, quando você adiciona visualizações filhas a um pai, esse recurso cria automaticamente duas ou mais restrições para cada visualização enquanto elas são adicionadas ao layout, mas somente quando é apropriado restringi-la ao layout pai. O Autoconnect não cria restrições para outras visualizações no layout.

O recurso de conexão automática fica desativado por padrão. Para ativá-lo, clique em Enable Autoconnection to Parent na barra de ferramentas do Layout Editor.

Animações de frames-chave

Em um ConstraintLayout, você pode animar mudanças no tamanho e na posição dos elementos usando ConstraintSet e TransitionManager.

Um ConstraintSet é um objeto leve que representa as restrições, as margens e o preenchimento de todos os elementos derivados em um ConstraintLayout. Quando você aplica um ConstraintSet a um ConstraintLayout exibido, o layout atualiza as restrições de todos os derivados.

Para criar uma animação usando ConstraintSets, especifique dois arquivos de layout que funcionam como um frame-chave de início e fim para a animação. Você pode carregar um ConstraintSet a partir do segundo arquivo de frames-chave e aplicá-lo ao ConstraintLayout.

O exemplo de código abaixo mostra como animar movendo um único botão para a parte inferior da tela.

// MainActivity.kt

    fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.keyframe_one)
        constraintLayout = findViewById(R.id.constraint_layout) // member variable
    }

    fun animateToKeyframeTwo() {
        val constraintSet = ConstraintSet()
        constraintSet.load(this, R.layout.keyframe_two)
        TransitionManager.beginDelayedTransition()
        constraintSet.applyTo(constraintLayout)
    }
    
    // layout/keyframe1.xml
    // Keyframe 1 contains the starting position for all elements in the animation as well as final colors and text sizes

    <?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"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="Button"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </android.support.constraint.ConstraintLayout>
    
    // layout/keyframe2.xml
    // Keyframe 2 contains another ConstraintLayout with the final positions

    <?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"
        android:layout_width="match_parent"
        android:layout_height="match_parent">

        <Button
            android:id="@+id/button2"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:text="Button"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintBottom_toBottomOf="parent" />
    </android.support.constraint.ConstraintLayout>

    

Outros recursos

ConstraintLayout é usado no app de demonstração Sunflower.