Derinlemesine Constraint Layout

Nurullah Ikinci
Oct 12, 2018 · 10 min read

Constraint Layout I/O 2016 da birçok güzelliği ve kolaylığı ile hayatımıza girdi, Google in dökümanları çok güzel olsa da türkçe kaynak sikintisi oldugunu farketmem bu yazıyı yazma sebebim oldu.

Constraint layout complex layoutları android studio içerisindeki visual editörde yapmamızı olabildiğince kolaylaştırıyor. Çok sık kullanılan Relative ve Linear layout ile içiçe viewlar la yapabileceğimiz layoutu daha kucuk view hierarchy ile daha performanslı daha okunaklı yapmamızı sağlıyor. Performans olarak google ın nexus5x ve constraint layout 1.0.2 ile yaptığı testlerde viewın oluştururken measure/layout fazlarında %40 daha hızlı olduğunu ortaya koydu. Performans konusunu başka bi yazıda detaylı şekilde değinmek üzere kenara bırakıp constraint layouta devam edelim.

12 Nisanda release olan 1.1.0 versiyonuyla daha da güçlenen Constraint Layout ta alttaki konuları açıklamaya çalışacağım

  • Relative positioning
  • Gone margin
  • Centering positioning and bias
  • Circle positioning
  • Percent dimension
  • Ratio
  • Chains
  • Guideline
  • Barrier
  • Group

Öncelikle constraint layout android sdk icinde gelmiyor dependency olarak eklememiz gerekli. Api 9+ destegi olduğu icin projenize eklemek sorun çıkartmayacak diye düşünüyorum .Su an icin son surum 1.1.3 bunu projemize ekleyerek başlayalım

dependencies {
compile 'com.android.support.constraint:constraint-layout:1.1.3'
}

Relative positioning

Öncelikle syntax ına bakalım. Alttaki ornekte layout_constraintLeft ile view ın en solu icin constraint tanımlayacağızı söylüyoruz _toRightOfile de constraint olacağı view ın yonunu belirliyoruz burda( sağında olacağını belirtiyoruz ) = in diğer tarafında da constraint olacağı view ı söylüyoruz.

app:layout_constraintLeft_toRightOf="@+id/buttonA

Alttaki property ler ile view lara constraint ekleyebilirsiniz.

layout_constraintLeft_toRightOflayout_constraintRight_toLeftOflayout_constraintRight_toRightOflayout_constraintTop_toTopOflayout_constraintTop_toBottomOflayout_constraintBottom_toTopOflayout_constraintBottom_toBottomOflayout_constraintBaseline_toBaselineOflayout_constraintStart_toEndOflayout_constraintStart_toStartOflayout_constraintEnd_toStartOflayout_constraintEnd_toEndOf

Örnek olarak bakarsak alttaki iki button umuz var B butonu A butonunun sağında olmasını istiyorsak B button unun left constraint ini A butonunun Right ına vermemiz gerekiyor.

Constraint leri direk xml den verebiliriz yada daha kolay olarak design editörden seçtiğimiz view in 4 yanındaki yuvarlak kutucuğu sürükleyerek de ekleyebiliriz

Sag ve sol constrainti parent verilmis button
<Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
/>

Gone margin

android:layout_marginStartandroid:layout_marginEndandroid:layout_marginLeftandroid:layout_marginTopandroid:layout_marginRightandroid:layout_marginBottom

Gone Margin constraint layout ile hayatımıza girdi ve tam olarak işlevi margin degeri set ettigin widget in margininin olduğu widgetin visibility si gone oldugunda artık view margin degeri ile degil gone margin degeri ile marginini set ediyor. Ornek olarak üstteki B button una bakarsak left constraint i olarak A button u verilmiş ve marginLeft degeri set edilmiş. Bu durumda A button unun visibility gone oldugunda B button u A nın olduğu yere kayacak ve soldan margin degeri kadar boşluk bırakacak. Listelerde böyle item larınız olduğunu düşünürseniz, A button unun göründüğü item larda layout sola dayalı, A button unun görünmediği item larda soldan B button unun margini kadar boşluklu bi görüntü olacak. Burda goneMargin devreye giriyor. B nin goneMarginLeft degeri set edilirse A button u gone olduğu durumda margin olarak artık B nin goneMarginLeft degerini kullanacak.

GoneMargin degeri view in 4 yönündeki margin icin set edilebilir

layout_goneMarginStartlayout_goneMarginEndlayout_goneMarginLeftlayout_goneMarginToplayout_goneMarginRightlayout_goneMarginBottom
<Button
android:id="@+id/button13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/button14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
app:layout_goneMarginStart="150dp"
android:text="Button2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/button13"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/button13"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
android:visibility="gone"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/button14"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginStart="8dp"
android:text="Button2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@+id/button13"
app:layout_constraintTop_toTopOf="parent"
app:layout_goneMarginStart="150dp"
/>

Centering positioning and bias

Alttaki örnekte ekranın ortasındaki button örneğini görebilirisiniz

Centered Button
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"

/>

Bias

Bias ile view in bi tarafında boşluğun diğer tarafına oranını belirliyoruz. Yatayda 0 en sol 1 en sag, dikeyde 0 en üst 1 en alt olarak işlevini yerine getiriyor, Default olarak 0.5 geliyor ve üstteki Centered Button orneginde görüldüğü gibi hem yatayda hem dikeyde ekranın ortasında.Aşağıdaki attribute lar ile bias degerini set edip butonu saga sola yukarı aşağı götürebiliriz .Ayrıca design editörden properties tabındaki seek bar dan da set edebiliriz

layout_constraintHorizontal_biaslayout_constraintVertical_bias

alttaki ornekte horizontal bias i ve vertical bias i set edilmiş buton ornegini görebilirsiniz

horizontal and vertical bias setted

<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHorizontal_bias="0.7"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintVertical_bias="0.2"
/>

Circle positioning

layout_constraintCircle : Constraint vereceğimiz widget idlayout_constraintCircleRadius :Diğer view a olan uzaklığı. Burda view imiz ile constraint verdigimiz view in center ları arası uzaklığı belirtiyoruzlayout_constraintCircleAngle : View imizin konulacağı açıyı veriyoruz ( 0-360 arasında)

Kısaca,

Alttaki örnekte de center daki buttona 45 ve 315 derecelik ve 150dp uzaklıkta 2 button örneğini görebilirsiniz

Circle Constraint
<Button
android:id="@+id/button4"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Angle 45"
app:layout_constraintCircle="@id/button4"
app:layout_constraintCircleAngle="45"
app:layout_constraintCircleRadius="150dp"

/>


<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Angle 315"
app:layout_constraintCircle="@id/button4"
app:layout_constraintCircleAngle="315"
app:layout_constraintCircleRadius="150dp"
/>

Percent dimension

Kullanacağımız attributel ar yatay yada dikey olarak ihtiyacımız olanı seçerek baslayabiliriz

app:layout_constraintHeight_percent="yüzdeOrani"
app:layout_constraintWidth_percent="yüzdeOrani"

Altta width percent i 0.4 height percent i 0.2 olan button ornegini bulabilirsiniz

<Button
android:id="@+id/button4"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintHeight_percent="0.2"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintWidth_percent="0.4"
/>

Ratio

app:layout_constraintDimensionRatio="1,1"

Burda dikkat etmemiz gereken bi boyutun uzunluğunun 0dp yani match constraint olması gerektiği. Verdigimiz ratio ya gore system diger boyutunu hesaplayacak. Eğer hem width hem de height ini 0 girersek sistem sığabilecek olan tarafı yerleştirip diğer boyutu ratio uya gore hesaplayacak.

Eğer özellikle bir boyutun oranlanmasını istiyorsak, ratio degerini hesaplanmasını istediğimizi boyuta göre vermemiz gerekiyor.

Mesela biz once width in sonrasında height in hesaplanmasını istiyorsak width ve height degerini 0 verip ratio degerini H ile vermemiz gerekiyor

app:layout_constraintDimensionRatio=”H,4:3"

Sistem once width hesaplayıp daha sonra height i 4:3 oranında büyütüyor

Tam tersi durumda yani once height ın daha sonra width in oranlanmasını istersek width ve height degerini 0 verip ratio degerini W ile vermemiz gerekiyor

app:layout_constraintDimensionRatio=”W,4:3" 

Bu sekilde kullanımda once sistem height i hesaplayıp daha sonra 4:3 oranında width boyutunu belirliyor

Aşağıda 4:3 oranında image kullandığım layoutu görebilirsiniz

Ratio 4:3 imageview
<ImageView
android:id="@+id/imageView"
android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="H,4:3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
app:srcCompat="@drawable/karagol"
/>

Chains

Chain with editor

Chainin 3 style i var, burda kullanacagimiz attribute:

app:layout_constraintHorizontal_chainStyle="spread_inside"
  • CHAIN_SPREAD Bu default style i. ve item ları eşit boşluklarlarla yayıyor
  • CHAIN_SPREAD_INSIDE . Bu style da köşelere birer item atıp kalanları eşit boşluklarla ortaya diziyor
  • CHAIN_PACKED Bu style da item lari arka arkaya diziyor
  • style olmasa itemların width ini match constraint verip weight property si ile layouttaki weight ini ayarlayabiliriz. Bu özellik Linear layoutun weight özelliği ile ayni işlevde
app:layout_constraintHorizontal_weight="1"

Burda dikkat etmemiz gereken chain in ilk elemanı. Chain ile ilgili chainStyle olsun yada chaine bias vereceksek bunu chainin ilk elemanına vermemiz lazım

Aşağıda 0.2 Horizontal_bias li packed chain ornegini inceleyebilirsiniz

Horizontal_bias packed chain
<Button
android:id="@+id/button15"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button1"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button16"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/button16"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button2"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toStartOf="@+id/button17"
app:layout_constraintStart_toEndOf="@+id/button15"
app:layout_constraintTop_toTopOf="parent"
/>
<Button
android:id="@+id/button17"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Button3"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toEndOf="@+id/button16"
app:layout_constraintTop_toTopOf="parent"
/>

Virtual Helper objects

Guideline

<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="20dp"
/>

Mesela muhtemelen ekranlarınızda en dis layoutta padding vardır sag-sol da yada üst-alt ta. Ama layoutumuzun icinde bi view yatayda full ekranı kaplıyor sagdan soldan marginsiz yani. Boyle bi ekranda muhtemelen root layouta padding verme yerine içteki layoutların hepsine margin veriyorsunuz. Guideline ile padding li layout ları guideline a, paddings view ları parent a constraint verirsek istediğimiz ekranı elde etmiş oluruz. Aşağıda bu durumun ornegini görebilirsiniz

<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="20dp"
/>
<Button
android:id="@+id/button8"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_marginEnd="8dp"
android:layout_marginLeft="8dp"
android:layout_marginRight="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Button"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/guideline"
/>
<ImageView
android:id="@+id/imageView2"
android:layout_width="0dp"
android:layout_height="0dp"
android:layout_marginTop="16dp"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="4:3"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/button8"
app:layout_constraintVertical_bias="0.0"
app:srcCompat="@drawable/karagol"
/>
<Button
android:id="@+id/button9"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginEnd="8dp"
android:layout_marginRight="8dp"
android:layout_marginTop="16dp"
android:text="Button"
app:layout_constraintEnd_toStartOf="@+id/guideline2"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/imageView2"
/>

Barrier

Burda dikkat etmeniz gereken referenced_ids ve barrierDirection. Verdiginiz idlerin direction tarafına barrier çekiyorsunuz gibi düşünebilirsiniz. Yani alttaki ornekte button10 ve button11 in endine barrier çekilmiş. Sağdaki button un lefti de barrier e constraint verilmiş

    app:barrierDirection="end"
app:constraint_referenced_ids="button10,button11"
<android.support.constraint.Guideline
android:id="@+id/guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_begin="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_end="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_end="20dp"
/>
<android.support.constraint.Guideline
android:id="@+id/guideline3"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_begin="20dp"
/>
<Button
android:id="@+id/button10"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Button"
app:layout_constraintBottom_toTopOf="@+id/guideline1"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintTop_toTopOf="@+id/guideline"
/>
<Button
android:id="@+id/button11"
android:layout_width="200dp"
android:layout_height="wrap_content"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:text=" asdsadhasduhasiudhasiudhiuas"
app:layout_constraintStart_toStartOf="@+id/guideline3"
app:layout_constraintTop_toBottomOf="@+id/button10"
/>
<android.support.constraint.Barrier
android:id="@+id/barrier2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:barrierDirection="end"
app:constraint_referenced_ids="button10,button11"
/>

<Button
android:id="@+id/button12"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="8dp"
android:layout_marginLeft="8dp"
android:layout_marginStart="8dp"
android:layout_marginTop="8dp"
android:text="Button"
app:layout_constraintBottom_toTopOf="@+id/guideline1"
app:layout_constraintStart_toEndOf="@+id/barrier2"
app:layout_constraintTop_toTopOf="@+id/guideline"
/>

Group

Uygulamalarınızda belli bi durumda bazı view ları gösterip, bazı view ları gizlediğiniz olmuştur. Mesele uygulamamızda şöyle bi ihtiyaç oldu, user loginli ise kullanıcı resmi ve adi gorunsun, login degilse login button u ve kayıt ol butonları görünmli. Group yardimci objesiyle view ları gruplayıp grup üzerinden gruptaki elemanların özellik set edebiliriz. Design editörden add group diyip view ları grubun icine atarak ekleyebiliriz. Yada xmlden direkt de verebiliriz. Bu durumda loginli ve loginsiz viewları gruplayıp grup uzerinden tum itemları gösterip gizleyebiliriz

<android.support.constraint.Group
android:id="@+id/group"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:constraint_referenced_ids="button13,button10,button11"
/>

Evet Bu kadar :)

Daha detaylı bilgiler icin google in kendi dökümanlarına bakabilir, codelab da kendinizi geliştirebilirsiniz

Yazıyla ilgili feedback, yada eklemek istedikleriniz varsa yorum yazabilir yada linkedin den iletişime gecebilirsiniz