Entendendo o que é ConstraintLayout — um sistema flexível de posicionamento para Android que permite construir hierarquias planas de views usando constraints (restrições) em vez de LinearLayout e RelativeLayout aninhados. O ConstraintLayout resolve o problema do "aninhamento infernal" (layout nesting hell), reduzindo a profundidade da hierarquia a um único nível e acelerando a renderização da tela. A biblioteca faz parte do Jetpack e está disponível a partir do Android 2.3 (API 9) através da support-library. Os principais mecanismos estão descritos na documentação oficial do Android.
Pontos principais
ConstraintLayout é um ViewGroup da biblioteca AndroidX ConstraintLayout, projetado para criar interfaces flexíveis e eficientes através de constraints declarativos. Ao contrário do LinearLayout, que organiza elementos em uma linha, ou do RelativeLayout, que posiciona elementos em relação aos vizinhos, o ConstraintLayout permite ancorar cada elemento em relação a qualquer outro elemento e ao pai simultaneamente.
A biblioteca foi anunciada no Google I/O 2016 como uma solução para acelerar a renderização de telas complexas. O principal problema que o ConstraintLayout resolve é o aninhamento de layouts. Cada ViewGroup aninhado adiciona pelo menos duas passadas de measure e uma passada de layout. Uma tela com 4 níveis de aninhamento executa 8 passadas de measure; o ConstraintLayout com a mesma funcionalidade executa apenas 2 passadas. De acordo com o Google (Android Performance Blog, 2017), substituir três LinearLayouts aninhados por um ConstraintLayout reduz o tempo de onMeasure em 40%.
A versão atual ConstraintLayout 2.1.4 funciona de forma estável no Android 2.3+ (API 9) através do AndroidX. A versão 2.0 introduziu o posicionamento circular, o Flow (ajuste automático de elementos) e o suporte ao MotionLayout. O ConstraintLayout é essencial para entender o desenvolvimento moderno do Android — ele é usado no Jetpack Compose como conceito básico de modificadores, nos modelos padrão do Android Studio e no Material Design 3.
A hierarquia plana do ConstraintLayout significa que todas as views filhas estão no mesmo nível de aninhamento. Em vez de colocar o elemento A em um LinearLayout, e o LinearLayout em um RelativeLayout, todos os elementos são vinculados diretamente ao ConstraintLayout pai ou uns aos outros através de atributos. Isso proporciona: menor consumo de memória (cada ViewGroup é um objeto no heap Java), layout pass mais rápido (menos chamadas recursivas) e comportamento mais previsível quando os tamanhos de tela mudam.
Uma constraint é uma conexão entre a borda de uma View (ou seu centro) e a borda de outra View ou do pai. Cada View pode ter até 8 constraints: left, top, right, bottom, start, end, baseline e center. No mínimo, duas constraints perpendiculares são suficientes para o posicionamento (por exemplo, top + left).
Formato do atributo: app:layout_constraint[Source]_to[Target]Of="[id]" — onde Source é a borda vinculada (Left, Right, Top, Bottom, Start, End, Baseline) e Target é a borda de destino. Exemplo: app:layout_constraintTop_toBottomOf="@+id/header" significa "a borda superior do elemento atual está vinculada à borda inferior do elemento header". Para vincular ao pai, usa-se o id parent.
Bias (viés) é um parâmetro que funciona quando constraints opostos estão presentes (left + right ou top + bottom). Os valores variam de 0 a 1: 0 — pressionado para a borda esquerda/superior, 0.5 — centralizado, 1 — para a borda direita/inferior. Atributos: layout_constraintHorizontal_bias (0.0–1.0) e layout_constraintVertical_bias. As margens são definidas com o padrão android:layout_margin*, mas constraints e margens funcionam de forma independente: a margem é um deslocamento da constraint, não da View vizinha.
A partir do ConstraintLayout 1.1+, foi adicionado suporte para tamanhos percentuais através de layout_constraintWidth_percent e layout_constraintHeight_percent. Um valor de 0.3 significa 30% da largura/altura do pai. Combinado com bias, isso permite criar layouts adaptativos sem programação.
Uma Chain (cadeia) é um grupo de duas ou mais Views conectadas por constraints bidirecionais (A está vinculado a B, B está vinculado a A). As cadeias distribuem automaticamente o espaço entre os elementos de acordo com um dos modos: spread (uniformemente, considerando margens), spread_inside (uniformemente, elementos externos sem margem de borda), packed (elementos pressionados com um bias comum). O modo é definido através do atributo app:layout_constraintHorizontal_chainStyle ou layout_constraintVertical_chainStyle.
Uma Guideline (guia) é uma View auxiliar, invisível em tempo de execução, que define uma linha para vinculação. Uma Guideline pode ser horizontal ou vertical, posicionada em dp, porcentagens (app:layout_constraintGuide_percent) ou com um deslocamento da borda (app:layout_constraintGuide_begin/end). As Guidelines são indispensáveis para layouts adaptativos — por exemplo, para dividir a tela em duas metades iguais independentemente do tamanho do dispositivo.
De acordo com o Google I/O 2017, cadeias com spread_inside são 15–20% mais eficientes do que LinearLayouts aninhados com weight, pois evitam a passada dupla de measure necessária para o cálculo do weight.
Uma Barrier (barreira) é uma View virtual que ajusta dinamicamente sua posição com base no tamanho de um grupo de elementos. Ao contrário de uma Guideline com posição fixa, uma Barrier é "empurrada" pelo elemento mais largo do grupo. Por exemplo, se você tem um título e uma descrição com comprimentos desconhecidos, uma Barrier vinculada à borda direita do texto mais largo permite colocar um ícone logo após eles. Atributos: app:barrierDirection (left, right, top, bottom, start, end) e app:constraint_referenced_ids (lista de ids separada por vírgulas).
Group é um contêiner virtual que gerencia a visibilidade de várias Views simultaneamente. Em vez de chamar setVisibility para cada elemento individualmente, basta alterar a visibilidade de um Group. O Group não afeta o posicionamento — apenas a visibilidade. Flow é um ajudante virtual para criar layouts "fluidos": os elementos se ajustam automaticamente para uma nova linha/coluna quando o espaço acaba, como texto em um parágrafo. O Flow suporta wrapMode: none, chain e aligned.
Essas ferramentas (Barrier, Group, Flow, Guideline) são chamadas de ajudantes virtuais porque não são Views no sentido clássico — elas não ocupam espaço na hierarquia e não participam de eventos de foco ou toque. Seu objetivo é simplificar a manutenção de layouts complexos sem adicionar contêineres aninhados.
Um formulário de login simples com um campo de e-mail, um campo de senha e um botão. Todos os elementos estão vinculados ao pai, exceto o botão — ele está abaixo do campo de senha. É usada uma hierarquia plana — todos os três elementos estão no mesmo nível.
<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="match_parent"
android:layout_height="match_parent">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/email_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="32dp"
android:layout_marginHorizontal="16dp" />
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/password_input"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/email_input"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="16dp"
android:layout_marginHorizontal="16dp" />
<Button
android:id="@+id/login_button"
android:layout_width="0dp"
android:layout_height="wrap_content"
app:layout_constraintTop_toBottomOf="@+id/password_input"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintEnd_toEndOf="parent"
android:layout_marginTop="24dp"
android:layout_marginHorizontal="16dp"
android:text="Entrar" />
</androidx.constraintlayout.widget.ConstraintLayout>
Todos os elementos têm largura de 0dp (match_constraint), o que significa que eles se estendem da constraint start até end considerando as margens horizontais. Isso é equivalente a match_parent com margens, mas sem aninhamento.
Três botões distribuídos uniformemente na horizontal com margens de borda. A cadeia spread_inside coloca os botões externos nas bordas e o botão do meio centralizado entre eles.
<Button
android:id="@+id/btn_left"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/btn_center"
android:text="Esquerda" />
<Button
android:id="@+id/btn_center"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn_left"
app:layout_constraintRight_toLeftOf="@+id/btn_right"
android:text="Centro" />
<Button
android:id="@+id/btn_right"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintLeft_toRightOf="@+id/btn_center"
app:layout_constraintRight_toRightOf="parent"
android:text="Direita" />
A cadeia é criada automaticamente quando os elementos têm constraints bidirecionais. O modo spread_inside é definido em qualquer elemento da cadeia através de app:layout_constraintHorizontal_chainStyle="spread_inside". Isso elimina a necessidade de um LinearLayout com weightSum e layout_weight.
Criação de duas colunas iguais usando uma Guideline vertical a 50%. O elemento esquerdo está vinculado ao pai esquerdo e sua borda direita à guideline; o elemento direito está vinculado com sua borda esquerda à guideline e ao pai direito.
<androidx.constraintlayout.widget.Guideline
android:id="@+id/gl_midpoint"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent="0.5" />
<TextView
android:id="@+id/left_card"
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_toLeftOf="@+id/gl_midpoint"
android:layout_margin="8dp"
android:background="@color/card_background" />
<TextView
android:id="@+id/right_card"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintLeft_toRightOf="@+id/gl_midpoint"
app:layout_constraintRight_toRightOf="parent"
android:layout_margin="8dp"
android:background="@color/card_background" />
Uma Guideline com porcentagem de 0.5 se adapta automaticamente à largura da tela. Tanto no tablet quanto no telefone, a proporção das colunas permanece 50/50. Para nomenclatura esquerda/direita, use atributos start/end para compatibilidade RTL.
Tabela de comparação dos três principais ViewGroups para desenvolvimento Android: ConstraintLayout, LinearLayout e RelativeLayout. Critérios: flexibilidade, desempenho, complexidade do código e casos de uso.
| Característica | ConstraintLayout | LinearLayout | RelativeLayout |
|---|---|---|---|
| Aninhamento | Plano (um nível) | Requer aninhamento para layouts complexos | Um nível, mas flexibilidade limitada |
| Desempenho de measure | 2 passadas (~40% mais rápido) | 4+ passadas com weight | 2 passadas |
| Tamanhos percentuais | Sim (guide_percent, width_percent) | Apenas via weight/frame | Não |
| Suporte RTL | Integrado (start/end) | Integrado | Via start/end (API 17+) |
| Barrier/Group/Flow | Sim (ajudantes virtuais) | Não | Não |
| Animações MotionLayout | Sim | Não | Não |
| Quando usar | Todos os layouts complexos, telas com >5 elementos | Listas unidirecionais simples, linhas com botões | Layouts relativos simples (código legado) |
De acordo com o Android Vitals (Google, 2025), aplicativos que usam ConstraintLayout como contêiner principal mostram em média 18% menos quadros jank ao renderizar telas complexas em comparação com aplicativos que usam LinearLayouts aninhados. Na IT Sectr, mudamos para o ConstraintLayout como padrão para todos os layouts XML em 2018 — isso reduziu a profundidade média da hierarquia da tela de 4.2 para 1.8 níveis e acelerou o desenvolvimento de novos formulários em 25%.
Perguntas frequentes
match_parent no ConstraintLayout funciona como de costume — estica a View ao tamanho do pai. 0dp (match_constraint) significa que o tamanho da View é calculado a partir das constraints: se as constraints left e right com margens forem definidas, a largura = parent — marginLeft — marginRight. A diferença no comportamento: match_parent ignora o bias e pode transbordar durante a animação; match_constraint respeita corretamente todas as restrições e é recomendado pelo Google como modo principal para ConstraintLayout.
Use uma combinação de: tamanhos percentuais (layout_constraintWidth_percent) para elementos que devem ocupar uma parte da tela; Guideline com porcentagens para dividir a tela em zonas; Barrier para posicionamento em relação a conteúdo dinâmico; Flow com wrapMode para ajustar cartões a uma nova linha. Uma abordagem alternativa é usar SlidingPaneLayout em combinação com ConstraintLayout para interfaces master-detail em tablets.
Jetpack Compose não usa ConstraintLayout como ViewGroup, mas fornece uma versão do ConstraintLayout para compose (androidx.constraintlayout:constraintlayout-compose) com a mesma API em Kotlin DSL: createRefFor(), constrainAs(), linkTo(), chain(), guideFrom(). Isso é útil para layouts complexos que são mais fáceis de descrever através de constraints do que com Column/Row. No entanto, no Compose, recomenda-se começar com Column/Row/Box e passar para ConstraintLayout apenas quando for necessário posicionamento relativo complexo.
No Android Studio, abra o Layout Inspector (Tools → Layout Inspector), selecione o aplicativo em execução e passe o cursor sobre o elemento problemático. Você verá todas as constraints, margens, padding e bias em uma representação 3D. Para XML, use o painel Design no editor de layouts — ele destaca conflitos de constraints em amarelo e constraints ausentes em vermelho. No código, certifique-se de que cada View tenha duas constraints perpendiculares, caso contrário, o elemento terminará em (0,0).
Resumo
Vamos desenvolver um aplicativo móvel chave na mão
A IT Sectr cria aplicativos para iOS e Android para startups e empresas desde 2017. Nós vamos aconselhá-lo e propor a melhor solução.
Leia também