본문 바로가기
개발/안드로이드

Android ConstraintLayout

by darksilber 2017. 5. 31.
반응형

출처 - http://blog.naver.com/pistolcaffe/221010983726

 

이번 글은 ConstraintLayout 에 대한 분석 내용입니다.


ConstraintLayout 은 지난 2016 년 개최 되었던 Google I/O 에 공개 된 레이아웃 에디터에 상호연관 시키기 위해 도입 된 Layout 입니다.


언뜻보면 RelativeLayout 과 비슷해보이기도 하는데, ConstraintLayout 만의 강력한 기능으로 ​좀 더 유연하고 빠른 레이아웃을 구성할 수 있습니다.


레이아웃 에디터를 이용하면 ConstraintLayout 안의 widget 간의 관계를 쉽게 파악할 수 있으므로 좀더 편리한 UI 작업을 할 수 있습니다.


그러나 기존의 XML 만 이용하여 UI 작업을 하셨던 분들도 충분히 ConstraintLayout 에 익숙해 질 수 있습니다.


ConstraintLayout 의 특성에 대해 알아보고, RelativeLayout 과 혼동 될 수 있는 부분에 대해서는 비교를 통해 그 차이점을 알아보도록 하겠습니다.


그럼 ConstraintLayout 의 주요 특성에 대해 알아 보도록 하겠습니다.


본 포스팅은 아래 링크의 내용을 참고하여 구성되었습니다.


(https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html)

(https://news.realm.io/kr/news/constraintlayout-it-can-do-what-now)







Side Constraint 라고도 하며, RelativeLayout 의 toLeftOf, toRightOf, alignTop, alignParentBottom 등의 속성과 비슷하지만
좀 더 자세하게는 특정 위젯 의 가로축/세로축 사이드 부분을 타겟 위젯 의 가로축/세로축 사이드 에 위치시킨다(Constraint) 는 것입니다.

가로축 : Left, Right, End side
세로축 : Top, Bottom side and text Baseline

Relative positioning 과 관련 된 속성은 다음과 같습니다.
app:layout_constraintBaseline_toBaselineOf="@id/target"
app:layout_constraintBottom_toBottomOf="@id/target"
app:layout_constraintBottom_toTopOf="@id/target"
app:layout_constraintEnd_toEndOf="@id/target"
app:layout_constraintEnd_toStartOf="@id/target"
app:layout_constraintLeft_toLeftOf="@id/target"
app:layout_constraintLeft_toRightOf="@id/target"
app:layout_constraintRight_toLeftOf="@id/target"
app:layout_constraintRight_toRightOf="@id/target"
app:layout_constraintStart_toEndOf="@id/target"
app:layout_constraintStart_toStartOf="@id/target"
app:layout_constraintTop_toBottomOf="@id/target"
app:layout_constraintTop_toTopOf="@id/target"
 layout_constraint<S1>_to<S2>of  이러한 형태 인데요.
해당 속성을 사용하는 위젯의  S1 사이드 부분을 타겟 위젯의 S2 사이드에 Constraint 한다 라는 의미입니다.

몇가지 속성을 가지고 예를 들어 보겠습니다.


 


위 그림은 B 위젯을 A 위젯 오른쪽에 배치 시키는 내용의 그림 입니다.
A 와 B 위젯이 버튼이고 A 버튼의 id 는 btnA 그리고 B 버튼의 id 는 btnB 라고 가정 해보겠습니다.
app:layout_constraintLeft_toRightOf="@id/btnA"
그렇다면 side constraint 속성 중에 위의 속성을 B 위젯에 적용 해 볼 수 있는데요.
즉, B 위젯의 Left 사이드 영역을, A 위젯의 Right 사이드에 위치 시킨다는 의미 입니다.

다른 예로 B 버튼을 A 버튼 아래 쪽에 위치 시키려면 어떻게 할까요?
app:layout_constraintTop_toBottomOf="@id/btnA"
네. 이 속성을 B 에 적용 하면 됩니다.
B 위젯 Top 사이드 영역을 A 위젯 Bottom 사이드 영역에 위치 시킨다는 의미입니다.

또한, 특정 위젯을 ConstraintLayout parent 와 constraint 를 정의 하고 싶다면,
app:layout_constraintTop_toBottomOf="parent"
id 대신 parent 라고 입력 하여 사용 할 수 있습니다.






ConstraintLayout 에서의 사이드 Margin 은 기존의 있던 layout_margin 속성들을 그대로 사용하여 적용합니다.
이때 위젯간 Constraint 관계에 맞추어 margin 이 적용 됩니다.

위에서 예를 들었던 것과 같이 B 버튼을 A 버튼 오른쪽에 위치시키기 위해 아래와 같이 코드를 작성하였고 left margin 을 추가 하였다면
<Button
android:id="@+id/btnB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
app:layout_constraintLeft_toRightOf="@id/btnA"/>

 

B 위젯은 A 위젯과의 Side Constraint 를 유지한채 left margin 이 적용 되는 것입니다.

또한, margin 과 관련 된 내용으로 ConstraintLayout 에는 constraint 관계에 있는 위젯이 GONE 처리 되었을 때

별도의 여백을 설정 할 수 있는 layout_goneMargin 관련 속성이 존재하는데, 

이것에 대한 설명은 Visibility behavior 의 내용을 설명하면서 같이 알아 보겠습니다.






우리는 위젯의 gravity 를 center 로 설정하기 위해 android:layout_gravity 혹은 android:gravity 속성을 적절히 사용 해왔습니다.
RelativeLayout 에서는 child 위젯에서 layout_centerInParent, layout_centerInHorizontal, layout_centerVertical 속성을 사용 할 수 있었죠.

하지만 ConstraintLayout 에서는 android:gravity="center" 를 사용하거나  
child 위젯이 android:layout_gravity="center" 를 사용해도 center 적용이 되지 않습니다. 
그렇다고 RelativeLayout 처럼 center 로 배치시키는 명시적인 고유 속성이 있는것도 아니죠.

 ConstraintLayout 에서는 parent 의 가로축/세로축 양 사이드 와의 Constraint 을 통해 Center positioning 을 수행 할 수 있습니다.

<?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/btnB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="ConstraintLayout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

위 코드는 Button 을 가로축 center 로 배치시키는 내용 입니다.

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
중요한 부분은 바로 이부분인데요.

이렇게 버튼의 Left 사이드를 parent 의 left 에, 그리고 Right 사이드를 parent 의 right 에 constraint 시키면
parent 에서 이 버튼을 양옆에서 똑같은 힘으로 잡아당기는 식의 동작이 되면서, 가로축 기준 center 로 배치시키게 됩니다.


 

위와 같이 버튼이 정확히 center_horizontal 로 배치 된 것을 볼 수 있습니다.



자, 그럼 부록으로 ConstraintLayout 에서 parent 와의 constraint 관계를 RelativeLayout 의 align 속성과 헷갈릴 수 있는 부분에 대해 
비교를 통해 한번 짚고 넘어가보도록 하겠습니다. (... 사실 처음에 제가 많이 헷갈렸던 부분입니다)

RelativeLayout 에는 alignParentLeft, alignParentRight 처럼 child 위젯과 parent 의 양 사이드와의 어떠한 관계를 정의하는 속성이 있습니다.

현재 맥락은 Center positioning 에 대해 알아보고 있었고, 
RelativeLayout 에서는 child 위젯에서 layout_centerInParent, layout_centerHorizontal, layout_centerVertical 등의 
명시적인 속성을 사용하면 되는 문제이지만, 비교를 위해 RelativeLayout 에서 위 에제와 비슷한 논리로 alignParentLeft, alignParentRight 로 구성하면
어떻게 나타날까요?

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:gravity="center"
android:padding="5dp"
android:text="RelativeLayout" />

</RelativeLayout>

 

바로 이렇게 나타납니다.

즉, RelativeLayout 에서의 align 속성은 해당 사이드 영역에 나란히 배치시키는 의미이지만
ConstraintLayout 에서 side constraint 특성은 단순 align 시키는 의미보다 더 넓은 의미에서 각 side 영역을 정의하는 의미를 갖고 있는 셈입니다.



그럼 다시 돌아와서, Center positioning 과 관련 된 내용으로 ConstraintLayout 에서는 Bias 라는 특성을 제공 합니다.


 
<Center positioning with Bias>

app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintVertical_bias="0.5"

위의 예제에서,  버튼을 center 에 배치시키기 위해 parent 양 사이드 간의 constraint 를 정의 했었습니다.
bias 속성은 parent 의 양 사이드간의 constraint 가 정의 되었을 때 추가적으로 적용 할 수 있습니다.

default 값은 0.5 (center) 이며, 0.5  보다 작으면 left 쪽으로 편향되고, 크면 right 쪽으로 편향 됩니다.

아래는 예시 입니다.

<?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/btnA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="It's bias 0.5"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />

<Button
android:id="@+id/btnB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="5dp"
android:text="It's bias 0.2"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnA" />

</android.support.constraint.ConstraintLayout>

 

btnA 는 bias 가 0.5 로 설정 되어서 정확히 center 쪽에 위치하였고, btnB 는 0.2 로 설정되어서 left 사이드 쪽으로 편향 된 것을 확인 할 수 있습니다.
(Center Positioning 의 모든 예를 가로축 기준으로 알아보았으나 세로축도 동일하게 적용 가능 합니다)






이 특성은 View.GONE 속성과 관련 된 내용 입니다.
일반적인 GONE 특성 처럼, 특정 위젯을 GONE 으로 처리 하게 되면 위젯이 표시 되지 않고 레이아웃에 포함 되지 않습니다.
GONE 으로 처리 된 위젯은 기본적으로 width, height 이 0 으로 간주되며, 그 위젯에 정의 된 margin 또한 0 으로 처리 됩니다.

그러나 특정 위젯의 visibility 속성을 GONE 으로 처리하여도 Constraint 관계는 여전히 유지 됩니다.

예를들어, 아래와 같이 코드를 구성하여 TextView 를 나란히 배치 하였습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A" />

<TextView
android:id="@+id/w_C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_B" />
</android.support.constraint.ConstraintLayout>



여기서 widget two 를 GONE 처리 하여도 widget three 와의 constraint 관계는 유지 한채 GONE 이 적용 되므로
widget three 는 widget one 오른쪽에 위치하게 됩니다



위의 특성은 RelativeLayout 에서도 유사한 특성을 볼 수 있습니다.
어느 위젯 끼리 toLeftOf , below 등의 관계가 정의되어있다면 하나의 위젯이 GONE 처리 되어도 그 관계는 유지하죠.

그러나 ConstraintLayout 의 Visibility 특성에서, 한가지 더 알아봐야할 속성이 있습니다.
app:layout_goneMarginLeft=""
app:layout_goneMarginBottom=""
app:layout_goneMarginEnd=""
app:layout_goneMarginRight=""
app:layout_goneMarginStart=""
app:layout_goneMarginTop=""
바로 위의 속성 들인데요.
ConstraintLayout 에서는 특정 위젯끼리 side constraint 이 정의 되어있고, 
해당 side 기준으로 위 속성을 적용한 뒤 constraint 관계에 있는 위젯이 gone 처리가 되면 위의 margine 값이 별도로 지정 됩니다.

예제로 한번 알아보겠습니다.

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

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A" />

<TextView
android:id="@+id/w_C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_B"
app:layout_goneMarginLeft="100dp" />
</android.support.constraint.ConstraintLayout>

바로 위에서 사용하였던 예제의 코드에서, 마지막 TextView(w_C) 에 layout_marginLeft 와 layout_goneMarginLeft 속성을 추가 하였습니다.
이때 두번째 TextView(w_B) 는 visible 상태이므로 layout_marginLeft 속성에 정의 된 30dp 가 왼쪽 margine 으로 적용이 됩니다.

 



이제 두번째 TextView 를 GONE 해보겠습니다.


 
이제 세번째 TextView 의 왼쪽 margine 은 30dp 가 아닌 layout_goneMarginLeft 속성에 정의 한 100dp  가 적용 됩니다.

이렇듯 layout_goneMargin 에 대한 속성이 별도로 정의되어있는 상태에서 관계 된 widget 이 GONE 처리가 되면
일반 layout_margin 속성은 적용이 되지 않고 layout_goneMargin 속성이 적용 되는 것을 유의하시기 바랍니다.
(layout_margin 값에 더하여 goneMargin 값이 적용 되는 것이 아닙니다)

만약 layout_goneMargin 속성은 정의하지 않았고 layout_margin 속성만 정의되어있다면 
GONE 처리에 관계없이 항상 layout_margin 에 정의 된 값으로 여백이 적용됩니다. 
이에따라, layout_margin 으로 기본 여백이 들어가있는데 GONE 상태에서는 margin 을 0 으로 적용하고 싶다면 layout_goneMargin 을 0dp 로 정의 해야 합니다.

이 goneMargin 속성을 이용하여 간단한 레이아웃 애니메이션을 구현할때 특히 유용할 수 있는 레이아웃 형태를 깨지 않고 
임시로 위젯을 GONE 으로 표시 할 수 있는 레이아웃을 만들 수 있습니다.






ConstraintLayout 만의 또 하나의 장점인 Dimension Constraints 속성 입니다.
먼저 짚고 넘어가야 할 내용은, MATCH_CONSTRAINT 에 대한 내용 인데요.

우리는 일반적으로 layout_width 속성에 123dp 와 같은 특정 값 또는 WRAP_CONTENT / MATCH_PARENT 를 사용 하였습니다.
그러나 ConstraintLayout 에 속한 widget 들에 대해서,  MATCH_PARENT 를 지원하지 않는다고 합니다.

대신 MATCH_PARENT 처럼 부모의 width 혹은 height 크기 만큼 채우려면 parent 와의 constraint 를 정의 한 후 MATCH_CONSTRAINT 를 지정해야 하는데요.


android:layout_width="0dp"
MATCH_CONSTRAINT 는 해당 위젯의 width 혹은 height 를 "0dp" 로 설정하여 적용 할 수 있습니다.



 

MATCH_CONSTRAINT 에 대해서 Developer 사이트에 있는 3개의 예제를 가지고 알아보겠습니다.




 

일단 (a) 의 경우는 비교를 위한 예 인데요. A 위젯이 가로축 Center 에 배치 되고 있습니다.
ConstraintLayout 의 Center Positioning 특성 에서 우리는 위젯을 Center 에 배치시키는 방법에 대해 알아보았는데,
parent 와의 양 옆 side constraint 를 지정했었죠? 즉, 아래와 같이 코드가 작성 될 수 있습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />

</android.support.constraint.ConstraintLayout>

 



그럼 이제 본격적으로 MATCH_CONSTRAINT 속성에 대해 알아 보겠습니다.
(b) 의 경우 입니다.
 
(b) 에서는 위젯의 width 가 match_parent 처럼 적용이 되어있네요.
위에서 한번 언급했듯이 ConstraintLayout 에서는 child 가 match_parent 를 사용할 수 없는데요.
MATCH_PARENT 처럼 부모의 width 혹은 height 크기 만큼 지정하려면 parent 와의 side constraint 를 정의 한 후 MATCH_CONSTRAINT 를 지정하면 됩니다.

그러면 코드를 아래와 같이 구성해 볼 수 있습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />

</android.support.constraint.ConstraintLayout>

 
(a) 에서는 위젯을 center 로 배치시키기 위해 width 를 wrap_content 로 지정하였고 parent 양 사이드와의 constraint 를 지정했었습니다.
(b) 에서는 parent 양 사이드와의 constraint 를 유지 한채 width 를 0dp (MATCH_CONSTRAINT) 로 지정 하였습니다.

이렇듯 MATCH_CONSTRAINT 와 side constraint 를 활용하여 MATCH_PARENT 와 유사하게 크기를 지정할 수 있는 것입니다.



마지막으로 (c) 입니다.
 

우리가 다른 레이아웃에서 child 의 width 를 MATCH_PARENT 로 지정하고 margin 을 적용하면, 
해당 margin 이 적용 된 나머지 부분이 MATCH_PARENT 로 되는 것을 알고 있습니다.

ConstraintLayout 도 마찬가지로, 
margin 이 적용 된 상태에서 MATCH_CONSTRAINT 을 적용하면 해당 여백이 적용 된 나머지 부분이 MATCH_CONSTRAINT 로 적용 됩니다.

<TextView
android:id="@+id/w_A"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:layout_marginLeft="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />





우선적으로 parent 와의 MATCH_CONSTRAINT 예시만 들고있는데, 
특정 위젯 간의 side constraint 를 지정하여 MATCH_CONSTRAINT 를 적용 할 수도 있습니다.
하나의 예제를 더 보고, Ratio 에 대해 알아보겠습니다.


 

ConstraintLayout 에서 위와같이 위젯의 width 를 특정 dp 로 지정하지 않고 
Widget Three 가 Widget One 과 Widget Two 에 너비를 합친 만큼의 너비를 갖으려면 어떻게 해야 할까요?
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A" />

<TextView
android:id="@+id/w_C"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="@id/w_A"
app:layout_constraintRight_toRightOf="@id/w_B"
app:layout_constraintTop_toBottomOf="@id/w_A" />

</android.support.constraint.ConstraintLayout>

바로 Widget Three 의 width 를 0dp (MATCH_CONSTRAINT) 로 지정 한뒤 
left constraint 를 Widget One , right constraint 를 Widget Two 로 설정 하면 됩니다.
더 나아가서 widget three 의 width 를 wrap_content 로 지정하면 center positioning 에서 알아본 내용처럼 
Widget One 과 widget Two 너비 기준 center 에 위치 하겠죠?

이렇듯 MATCH_CONSTRAINT 와 side constraint 의 관계를 유념하시면 좋을 것 같습니다.




다음은 Ratio 에 대한 내용입니다.

ConstraintLayout 에서는 위젯의 width, height 를 비율로 지정 할 수 있는 기능이 있습니다.
비율로 지정하고 싶은 width/height 에 0dp (MATCH_CONSTRAINT) 로 지정 한 후 layout_constraintDimensionRatio 속성을 사용하는 것인데요.

layout_constraintDimensionRatio="width:height" 형식의 비율로 사용 할 수 있습니다.

예를들어, 특정 TextView 의 width 는 text 크기 만큼만 지정하도록 wrap_content 로 놓고
height 는 width 에 지정 된 크기 만큼 비율로 설정하고 싶다면 아래와 같이 코드를 작성하면 됩니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintDimensionRatio="1:1" />

 

여담이긴한데, 위 예제 코드에서 TextView 의 left side constraint 를 따로 지정해줬는데요. 
(이 예제에서는 굳이 left constraint 속성이 필요하지 않은데 말이죠)
Developer 사이트 에서는 side constraint 없이 layout_constraintDimensionRatio 만 적용해도 ratio 가 적용 되는 것처럼 예제를 제시해놨는데
실제로는 side constraint 가 없으면 layout_constraintDimensionRatio 가 적용되지 않더라구요. 버그인지 의도 된 것인진 모르겠어서..
ConstraintLayout 코드를 분석중에 있습니다.

아무튼, side constraint 과 같이 써주세요.


다시 돌아와서, width 와 height 를 둘다 0dp (MATCH_CONSTRAINT) 로 지정한 뒤 ratio 를 적용하는 방법도 있습니다.
예제를 한번 볼게요.
<TextView
android:id="@+id/w_A"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="16:9"
android:textSize="15sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="h,16:9" />

width 와 height 모두 0dp (MATCH_CONSTRAINT) 로 지정 하였고,
세로축 parent 양 사이드와의 constraint 를 지정 하였습니다
마지막으로 layout_constraintDimensionRatio 가 적용 되어있네요.

그런데 위에서 사용했던 layout_constraintDimensionRatio="1:1" 과는 약간 다른모습이죠?
app:layout_constraintDimensionRatio="h 혹은 w, width:height" 
이 포맷은 w (width) 또는 h (height) 를 constraint 시키고 지정 종횡비율을 적용 한다는 의미 입니다.

위 예제에서는, 세로축 parent 양 사이드와의 constraint 가 정의 되어있으므로
height 를 match_constraint 시키고 16:9 종횡비율을 적용 하겠다는 의미입니다.

그러면 결과 화면은 이렇게 나타납니다.

 

이러한 ConstraintLayout 에 Dimension Ratio 특성으로 여러 해상도에 대해 좀더 유연한 대응을 할 수 있게 되었습니다.






Dimension Constraints 에서 내용이 꽤 길어졌네요.
ConstraintLayout 에는 또 하나의 강력한 특성인 Chains 가 있습니다.

Chians 특성은 가로축/세로축 한축에 대해 특정 그룹을 짓는 것과 유사한 특성인데요.
Chain 을 설정하면 각 위젯이 서로 연결 되어 한 덩어리로 유연하게 배치시킬수 있는 장점이 있습니다.

일단 Chain 를 구성하는 방법부터 알아볼게요.

 

A, B 위젯이 있을 때 서로 쌍방향 constraint 가 정의 될 경우 두 위젯은 chain 관계에 있다고 간주합니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A"
app:layout_constraintRight_toRightOf="parent" />

첫번째 TextView 와 두번째 TextView 코드를 보면 서로 side 부분이 constraint 되있는 것을 볼 수 있습니다.
(XML 에서는 눈에 들어오지 않지만 레이아웃 에디터에서 두 위젯을 보면 서로 사이드가 연결 되어있는 것을 볼 수 있습니다.)

이 상태가 두 위젯이 chain 관계에 있다고 볼 수 있는 것입니다.



다음은 chain head 입니다.

 

각 chain 에는 head 가 되는 기준 위젯이 있습니다.
가로축 기준일 경우 chain 가장 왼쪽에 있는 위젯이 head 가 되고 세로축 기준일 경우 chain 가장 위쪽에 있는 위젯이 head 가 됩니다.

이 head 가 하는 역할은 chain 에 대한 내용을 계속 살펴보면서 언급하겠습니다.



이, chain 에는 특정 style 을 지정 할 수 있습니다.

 


CHAIN_SPREAD , CHIAN_SPREAD_INSIDE , CHAIN_PACKED  총 3개의 chain style 을 지원 합니다.
각각의 chain style 에 대해 살펴보겠습니다.




  • CHAIN_SPREAD -- the elements will be spread out  (default style)


spread 속성은 chain 으로 연결 된 widget 을 균일하게 퍼뜨리는 속성 입니다. 
기본 속성이며, chain 연결 후 별도의 style 를 지정하지 않으면 spread 속성으로 적용 됩니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A"
app:layout_constraintRight_toLeftOf="@+id/w_C" />

<TextView
android:id="@+id/w_C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_B"
app:layout_constraintRight_toRightOf="parent" />



세개의 위젯을 chain 으로 설정 하였습니다. 별도의 chain style 은 지정하지 않았으니 기본 속성인 spread 속성이 적용 됩니다.
spread 속성은 이와 같이 chain 관계에 있는 위젯들을 균일한 여백을 가지고 배치시키는 옵션 입니다.


  • Weighted chain -- in CHAIN_SPREAD mode, if some widgets are set to MATCH_CONSTRAINT, they will split the available space


spread 속성에서는 특정 위젯을 MATCH_CONSTRAINT 로 설정 하면 가용 공간의 크기로 지정 할 수도 있는데요.
위 예제코드에서 세번째 위젯만 width 를 0dp(MATCH_CONSTRAINT) 로 설정 해보겠습니다.



이렇게, 두번째 위젯 까지 배치 되고 남은 영역을 세번째 위젯의 width 로 지정 됩니다.

또한, spread 속성일 경우 weight 를 지정 할 수도 있습니다.
weight 로 지정할 위젯의 width 를 0dp (MATCH_CONSTRAINT) 로 지정 하고 weight 속성을 추가 하면 됩니다.
app:layout_constraintHorizontal_weight="1"



두번째와 세번째 위젯에 weight 를 각각 1로 적용해보겠습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

<TextView
android:id="@+id/w_B"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/w_A"
app:layout_constraintRight_toLeftOf="@+id/w_C" />

<TextView
android:id="@+id/w_C"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/w_B"
app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>


이렇게 weight 설정 된 두번째 세번째 위젯의 width 가 각각 1:1 로 배치 되었습니다.





  • CHAIN_SPREAD_INSIDE -- similar, but the endpoints of the chain will not be spread out


다음은 SPREAD_INSIDE 속성인데요.
기본 원리는 SPREAD 속성과 같지만 차이점은 Chain 의 양끝 side 부분은 spread 되지 않는 다는 점입니다.

그럼, chain style 를 한번 SPREAD_INSIDE 로 바꿔 보겠습니다.
chain style 은 chain 의 head 가 되는 위젯에 설정 하면 됩니다.
각 chain 의 head 가 하는 역할은 이렇게 해당 chain 의 특성을 정의 할때 사용 되어 집니다.

위 에제코드에서는 가로축 chain 이 지정 되어 있고 가장 왼쪽 위젯이 head 가 됩니다.
그러므로 head widget 에서 chain style 을 설정해보겠습니다.

가로축 chain 일 경우
app:layout_constraintHorizontal_chainStyle=""
세로축 chain 일 경우
app:layout_constraintVertical_chainStyle=""
속성을 사용 하면 됩니다.

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />



이렇게 균등하게 배치 되지만 chain 의 양 사이드는 spread 되지 않는 것을 볼 수 있습니다.




  • CHAIN_PACKED -- the elements of the chain will be packed together. The horizontal or vertical bias attribute of the child will then affect the positioning of the packed elements

마지막으로 PACKED 속성 입니다.
PACKED 속성은 chain 으로 연결 된 위젯을 하나로 묶어서 center 로 배치 시킵니다. 

head 위젯에서 chain style 을 PACKED 으로 바꿔 보겠습니다.

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

 

이때,  Center positioning 에서 알아보았던 bias 속성을 지정 할 수 있는데요.
head 위젯에 bias 를 적용하면, chain 단위에서 bias 특성이 적용 됩니다.
bias 의 기본 값은 0.5 라고 하였으니, 0.2 로 지정 해보겠습니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

 

이렇게 chain 의 bias 가 적용 된 것을 확인 할 수 있겠습니다.





Chain 속성에 대해 알아 보았고, 마지막 내용으로 Guideline 에 대해 알아보겠습니다.
ConstraintLayout 에는 레이아웃 작업을 돕기 위한 Guideline 객체를 지원 합니다.
이 또한 Chain 연결 처럼 XML 상으로 눈에 보이지 않지만 레이아웃 에디터에서 지정 된 Guideline 이 나타나는 것을 볼 수 있죠.
Guideline 은 기본적으로 gone 처리가 되어있기 때문에 실제로 화면에 나타나지 않습니다.
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintGuide_percent=".15" />
 
이런 식으로 Guideline 을 추가 하면 레이아웃 에디터에서 추가 된 Guideline 을 볼 수 있습니다.

 

그리고 배치 하고자 하는 위젯을 먼저 잡아놓은 Guideline 에 Constraint 시켜서 작업을 진행 할 수 있습니다.
Guideline 이 사용 된 예시는 Developer 사이트에 있는 좋은 예시를 첨부 합니다.
<android.support.constraint.Guideline
android:id="@+id/left_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".15" />

<android.support.constraint.Guideline
android:id="@+id/right_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".85" />

<android.support.constraint.Guideline
android:id="@+id/top_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".15" />

<android.support.constraint.Guideline
android:id="@+id/bottom_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".85" />

<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline"
app:layout_constraintLeft_toLeftOf="@+id/left_guideline"
app:layout_constraintRight_toRightOf="@+id/right_guideline"
app:layout_constraintTop_toTopOf="@+id/top_guideline" />

 

support library 였던 PercentRelativeLayout 이 ConstraintLayout 이 나오면서 Deperecated 되었는데, 
이 예제가 Developer 사이트에서 PrecenetRelativeLayout 대신에 이렇게 사용하도록 가이드 되고 있네요.
참고하시면 좋을 듯 합니다.




이렇게 해서 ConstraintLayout 에 대해 알아 보았습니다.
특성이 많아서 이해하는데 시간이 좀 걸렸는데, 앞으로 레이아웃 작업에 많은 이점이 있을 것 같습니다.
잘못 된 부분이 있으면 알려주시기 바랍니다. 
이상 마치겠습니다. 

[출처] Android ConstraintLayout 분석|작성자 pistolcaffe

이번 글은 ConstraintLayout 에 대한 분석 내용입니다.


ConstraintLayout 은 지난 2016 년 개최 되었던 Google I/O 에 공개 된 레이아웃 에디터에 상호연관 시키기 위해 도입 된 Layout 입니다.


언뜻보면 RelativeLayout 과 비슷해보이기도 하는데, ConstraintLayout 만의 강력한 기능으로 ​좀 더 유연하고 빠른 레이아웃을 구성할 수 있습니다.


레이아웃 에디터를 이용하면 ConstraintLayout 안의 widget 간의 관계를 쉽게 파악할 수 있으므로 좀더 편리한 UI 작업을 할 수 있습니다.


그러나 기존의 XML 만 이용하여 UI 작업을 하셨던 분들도 충분히 ConstraintLayout 에 익숙해 질 수 있습니다.


ConstraintLayout 의 특성에 대해 알아보고, RelativeLayout 과 혼동 될 수 있는 부분에 대해서는 비교를 통해 그 차이점을 알아보도록 하겠습니다.


그럼 ConstraintLayout 의 주요 특성에 대해 알아 보도록 하겠습니다.


본 포스팅은 아래 링크의 내용을 참고하여 구성되었습니다.


(https://developer.android.com/reference/android/support/constraint/ConstraintLayout.html)

(https://news.realm.io/kr/news/constraintlayout-it-can-do-what-now)







Side Constraint 라고도 하며, RelativeLayout 의 toLeftOf, toRightOf, alignTop, alignParentBottom 등의 속성과 비슷하지만
좀 더 자세하게는 특정 위젯 의 가로축/세로축 사이드 부분을 타겟 위젯 의 가로축/세로축 사이드 에 위치시킨다(Constraint) 는 것입니다.

가로축 : Left, Right, End side
세로축 : Top, Bottom side and text Baseline

Relative positioning 과 관련 된 속성은 다음과 같습니다.
app:layout_constraintBaseline_toBaselineOf="@id/target"
app:layout_constraintBottom_toBottomOf="@id/target"
app:layout_constraintBottom_toTopOf="@id/target"
app:layout_constraintEnd_toEndOf="@id/target"
app:layout_constraintEnd_toStartOf="@id/target"
app:layout_constraintLeft_toLeftOf="@id/target"
app:layout_constraintLeft_toRightOf="@id/target"
app:layout_constraintRight_toLeftOf="@id/target"
app:layout_constraintRight_toRightOf="@id/target"
app:layout_constraintStart_toEndOf="@id/target"
app:layout_constraintStart_toStartOf="@id/target"
app:layout_constraintTop_toBottomOf="@id/target"
app:layout_constraintTop_toTopOf="@id/target"
 layout_constraint<S1>_to<S2>of  이러한 형태 인데요.
해당 속성을 사용하는 위젯의  S1 사이드 부분을 타겟 위젯의 S2 사이드에 Constraint 한다 라는 의미입니다.

몇가지 속성을 가지고 예를 들어 보겠습니다.


 


위 그림은 B 위젯을 A 위젯 오른쪽에 배치 시키는 내용의 그림 입니다.
A 와 B 위젯이 버튼이고 A 버튼의 id 는 btnA 그리고 B 버튼의 id 는 btnB 라고 가정 해보겠습니다.
app:layout_constraintLeft_toRightOf="@id/btnA"
그렇다면 side constraint 속성 중에 위의 속성을 B 위젯에 적용 해 볼 수 있는데요.
즉, B 위젯의 Left 사이드 영역을, A 위젯의 Right 사이드에 위치 시킨다는 의미 입니다.

다른 예로 B 버튼을 A 버튼 아래 쪽에 위치 시키려면 어떻게 할까요?
app:layout_constraintTop_toBottomOf="@id/btnA"
네. 이 속성을 B 에 적용 하면 됩니다.
B 위젯 Top 사이드 영역을 A 위젯 Bottom 사이드 영역에 위치 시킨다는 의미입니다.

또한, 특정 위젯을 ConstraintLayout parent 와 constraint 를 정의 하고 싶다면,
app:layout_constraintTop_toBottomOf="parent"
id 대신 parent 라고 입력 하여 사용 할 수 있습니다.






ConstraintLayout 에서의 사이드 Margin 은 기존의 있던 layout_margin 속성들을 그대로 사용하여 적용합니다.
이때 위젯간 Constraint 관계에 맞추어 margin 이 적용 됩니다.

위에서 예를 들었던 것과 같이 B 버튼을 A 버튼 오른쪽에 위치시키기 위해 아래와 같이 코드를 작성하였고 left margin 을 추가 하였다면
<Button
android:id="@+id/btnB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
app:layout_constraintLeft_toRightOf="@id/btnA"/>

 

B 위젯은 A 위젯과의 Side Constraint 를 유지한채 left margin 이 적용 되는 것입니다.

또한, margin 과 관련 된 내용으로 ConstraintLayout 에는 constraint 관계에 있는 위젯이 GONE 처리 되었을 때

별도의 여백을 설정 할 수 있는 layout_goneMargin 관련 속성이 존재하는데, 

이것에 대한 설명은 Visibility behavior 의 내용을 설명하면서 같이 알아 보겠습니다.






우리는 위젯의 gravity 를 center 로 설정하기 위해 android:layout_gravity 혹은 android:gravity 속성을 적절히 사용 해왔습니다.
RelativeLayout 에서는 child 위젯에서 layout_centerInParent, layout_centerInHorizontal, layout_centerVertical 속성을 사용 할 수 있었죠.

하지만 ConstraintLayout 에서는 android:gravity="center" 를 사용하거나  
child 위젯이 android:layout_gravity="center" 를 사용해도 center 적용이 되지 않습니다. 
그렇다고 RelativeLayout 처럼 center 로 배치시키는 명시적인 고유 속성이 있는것도 아니죠.

 ConstraintLayout 에서는 parent 의 가로축/세로축 양 사이드 와의 Constraint 을 통해 Center positioning 을 수행 할 수 있습니다.

<?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/btnB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="ConstraintLayout"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>

위 코드는 Button 을 가로축 center 로 배치시키는 내용 입니다.

app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
중요한 부분은 바로 이부분인데요.

이렇게 버튼의 Left 사이드를 parent 의 left 에, 그리고 Right 사이드를 parent 의 right 에 constraint 시키면
parent 에서 이 버튼을 양옆에서 똑같은 힘으로 잡아당기는 식의 동작이 되면서, 가로축 기준 center 로 배치시키게 됩니다.


 

위와 같이 버튼이 정확히 center_horizontal 로 배치 된 것을 볼 수 있습니다.



자, 그럼 부록으로 ConstraintLayout 에서 parent 와의 constraint 관계를 RelativeLayout 의 align 속성과 헷갈릴 수 있는 부분에 대해 
비교를 통해 한번 짚고 넘어가보도록 하겠습니다. (... 사실 처음에 제가 많이 헷갈렸던 부분입니다)

RelativeLayout 에는 alignParentLeft, alignParentRight 처럼 child 위젯과 parent 의 양 사이드와의 어떠한 관계를 정의하는 속성이 있습니다.

현재 맥락은 Center positioning 에 대해 알아보고 있었고, 
RelativeLayout 에서는 child 위젯에서 layout_centerInParent, layout_centerHorizontal, layout_centerVertical 등의 
명시적인 속성을 사용하면 되는 문제이지만, 비교를 위해 RelativeLayout 에서 위 에제와 비슷한 논리로 alignParentLeft, alignParentRight 로 구성하면
어떻게 나타날까요?

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:gravity="center"
android:padding="5dp"
android:text="RelativeLayout" />

</RelativeLayout>

 

바로 이렇게 나타납니다.

즉, RelativeLayout 에서의 align 속성은 해당 사이드 영역에 나란히 배치시키는 의미이지만
ConstraintLayout 에서 side constraint 특성은 단순 align 시키는 의미보다 더 넓은 의미에서 각 side 영역을 정의하는 의미를 갖고 있는 셈입니다.



그럼 다시 돌아와서, Center positioning 과 관련 된 내용으로 ConstraintLayout 에서는 Bias 라는 특성을 제공 합니다.


 
<Center positioning with Bias>

app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintVertical_bias="0.5"

위의 예제에서,  버튼을 center 에 배치시키기 위해 parent 양 사이드 간의 constraint 를 정의 했었습니다.
bias 속성은 parent 의 양 사이드간의 constraint 가 정의 되었을 때 추가적으로 적용 할 수 있습니다.

default 값은 0.5 (center) 이며, 0.5  보다 작으면 left 쪽으로 편향되고, 크면 right 쪽으로 편향 됩니다.

아래는 예시 입니다.

<?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/btnA"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:gravity="center"
android:padding="5dp"
android:text="It's bias 0.5"
app:layout_constraintHorizontal_bias="0.5"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent" />

<Button
android:id="@+id/btnB"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="10dp"
android:gravity="center"
android:padding="5dp"
android:text="It's bias 0.2"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintTop_toBottomOf="@id/btnA" />

</android.support.constraint.ConstraintLayout>

 

btnA 는 bias 가 0.5 로 설정 되어서 정확히 center 쪽에 위치하였고, btnB 는 0.2 로 설정되어서 left 사이드 쪽으로 편향 된 것을 확인 할 수 있습니다.
(Center Positioning 의 모든 예를 가로축 기준으로 알아보았으나 세로축도 동일하게 적용 가능 합니다)






이 특성은 View.GONE 속성과 관련 된 내용 입니다.
일반적인 GONE 특성 처럼, 특정 위젯을 GONE 으로 처리 하게 되면 위젯이 표시 되지 않고 레이아웃에 포함 되지 않습니다.
GONE 으로 처리 된 위젯은 기본적으로 width, height 이 0 으로 간주되며, 그 위젯에 정의 된 margin 또한 0 으로 처리 됩니다.

그러나 특정 위젯의 visibility 속성을 GONE 으로 처리하여도 Constraint 관계는 여전히 유지 됩니다.

예를들어, 아래와 같이 코드를 구성하여 TextView 를 나란히 배치 하였습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A" />

<TextView
android:id="@+id/w_C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_B" />
</android.support.constraint.ConstraintLayout>



여기서 widget two 를 GONE 처리 하여도 widget three 와의 constraint 관계는 유지 한채 GONE 이 적용 되므로
widget three 는 widget one 오른쪽에 위치하게 됩니다



위의 특성은 RelativeLayout 에서도 유사한 특성을 볼 수 있습니다.
어느 위젯 끼리 toLeftOf , below 등의 관계가 정의되어있다면 하나의 위젯이 GONE 처리 되어도 그 관계는 유지하죠.

그러나 ConstraintLayout 의 Visibility 특성에서, 한가지 더 알아봐야할 속성이 있습니다.
app:layout_goneMarginLeft=""
app:layout_goneMarginBottom=""
app:layout_goneMarginEnd=""
app:layout_goneMarginRight=""
app:layout_goneMarginStart=""
app:layout_goneMarginTop=""
바로 위의 속성 들인데요.
ConstraintLayout 에서는 특정 위젯끼리 side constraint 이 정의 되어있고, 
해당 side 기준으로 위 속성을 적용한 뒤 constraint 관계에 있는 위젯이 gone 처리가 되면 위의 margine 값이 별도로 지정 됩니다.

예제로 한번 알아보겠습니다.

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

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A" />

<TextView
android:id="@+id/w_C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginLeft="30dp"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_B"
app:layout_goneMarginLeft="100dp" />
</android.support.constraint.ConstraintLayout>

바로 위에서 사용하였던 예제의 코드에서, 마지막 TextView(w_C) 에 layout_marginLeft 와 layout_goneMarginLeft 속성을 추가 하였습니다.
이때 두번째 TextView(w_B) 는 visible 상태이므로 layout_marginLeft 속성에 정의 된 30dp 가 왼쪽 margine 으로 적용이 됩니다.

 



이제 두번째 TextView 를 GONE 해보겠습니다.


 
이제 세번째 TextView 의 왼쪽 margine 은 30dp 가 아닌 layout_goneMarginLeft 속성에 정의 한 100dp  가 적용 됩니다.

이렇듯 layout_goneMargin 에 대한 속성이 별도로 정의되어있는 상태에서 관계 된 widget 이 GONE 처리가 되면
일반 layout_margin 속성은 적용이 되지 않고 layout_goneMargin 속성이 적용 되는 것을 유의하시기 바랍니다.
(layout_margin 값에 더하여 goneMargin 값이 적용 되는 것이 아닙니다)

만약 layout_goneMargin 속성은 정의하지 않았고 layout_margin 속성만 정의되어있다면 
GONE 처리에 관계없이 항상 layout_margin 에 정의 된 값으로 여백이 적용됩니다. 
이에따라, layout_margin 으로 기본 여백이 들어가있는데 GONE 상태에서는 margin 을 0 으로 적용하고 싶다면 layout_goneMargin 을 0dp 로 정의 해야 합니다.

이 goneMargin 속성을 이용하여 간단한 레이아웃 애니메이션을 구현할때 특히 유용할 수 있는 레이아웃 형태를 깨지 않고 
임시로 위젯을 GONE 으로 표시 할 수 있는 레이아웃을 만들 수 있습니다.






ConstraintLayout 만의 또 하나의 장점인 Dimension Constraints 속성 입니다.
먼저 짚고 넘어가야 할 내용은, MATCH_CONSTRAINT 에 대한 내용 인데요.

우리는 일반적으로 layout_width 속성에 123dp 와 같은 특정 값 또는 WRAP_CONTENT / MATCH_PARENT 를 사용 하였습니다.
그러나 ConstraintLayout 에 속한 widget 들에 대해서,  MATCH_PARENT 를 지원하지 않는다고 합니다.

대신 MATCH_PARENT 처럼 부모의 width 혹은 height 크기 만큼 채우려면 parent 와의 constraint 를 정의 한 후 MATCH_CONSTRAINT 를 지정해야 하는데요.


android:layout_width="0dp"
MATCH_CONSTRAINT 는 해당 위젯의 width 혹은 height 를 "0dp" 로 설정하여 적용 할 수 있습니다.



 

MATCH_CONSTRAINT 에 대해서 Developer 사이트에 있는 3개의 예제를 가지고 알아보겠습니다.




 

일단 (a) 의 경우는 비교를 위한 예 인데요. A 위젯이 가로축 Center 에 배치 되고 있습니다.
ConstraintLayout 의 Center Positioning 특성 에서 우리는 위젯을 Center 에 배치시키는 방법에 대해 알아보았는데,
parent 와의 양 옆 side constraint 를 지정했었죠? 즉, 아래와 같이 코드가 작성 될 수 있습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />

</android.support.constraint.ConstraintLayout>

 



그럼 이제 본격적으로 MATCH_CONSTRAINT 속성에 대해 알아 보겠습니다.
(b) 의 경우 입니다.
 
(b) 에서는 위젯의 width 가 match_parent 처럼 적용이 되어있네요.
위에서 한번 언급했듯이 ConstraintLayout 에서는 child 가 match_parent 를 사용할 수 없는데요.
MATCH_PARENT 처럼 부모의 width 혹은 height 크기 만큼 지정하려면 parent 와의 side constraint 를 정의 한 후 MATCH_CONSTRAINT 를 지정하면 됩니다.

그러면 코드를 아래와 같이 구성해 볼 수 있습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />

</android.support.constraint.ConstraintLayout>

 
(a) 에서는 위젯을 center 로 배치시키기 위해 width 를 wrap_content 로 지정하였고 parent 양 사이드와의 constraint 를 지정했었습니다.
(b) 에서는 parent 양 사이드와의 constraint 를 유지 한채 width 를 0dp (MATCH_CONSTRAINT) 로 지정 하였습니다.

이렇듯 MATCH_CONSTRAINT 와 side constraint 를 활용하여 MATCH_PARENT 와 유사하게 크기를 지정할 수 있는 것입니다.



마지막으로 (c) 입니다.
 

우리가 다른 레이아웃에서 child 의 width 를 MATCH_PARENT 로 지정하고 margin 을 적용하면, 
해당 margin 이 적용 된 나머지 부분이 MATCH_PARENT 로 되는 것을 알고 있습니다.

ConstraintLayout 도 마찬가지로, 
margin 이 적용 된 상태에서 MATCH_CONSTRAINT 을 적용하면 해당 여백이 적용 된 나머지 부분이 MATCH_CONSTRAINT 로 적용 됩니다.

<TextView
android:id="@+id/w_A"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:layout_marginLeft="100dp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />





우선적으로 parent 와의 MATCH_CONSTRAINT 예시만 들고있는데, 
특정 위젯 간의 side constraint 를 지정하여 MATCH_CONSTRAINT 를 적용 할 수도 있습니다.
하나의 예제를 더 보고, Ratio 에 대해 알아보겠습니다.


 

ConstraintLayout 에서 위와같이 위젯의 width 를 특정 dp 로 지정하지 않고 
Widget Three 가 Widget One 과 Widget Two 에 너비를 합친 만큼의 너비를 갖으려면 어떻게 해야 할까요?
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A" />

<TextView
android:id="@+id/w_C"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="@id/w_A"
app:layout_constraintRight_toRightOf="@id/w_B"
app:layout_constraintTop_toBottomOf="@id/w_A" />

</android.support.constraint.ConstraintLayout>

바로 Widget Three 의 width 를 0dp (MATCH_CONSTRAINT) 로 지정 한뒤 
left constraint 를 Widget One , right constraint 를 Widget Two 로 설정 하면 됩니다.
더 나아가서 widget three 의 width 를 wrap_content 로 지정하면 center positioning 에서 알아본 내용처럼 
Widget One 과 widget Two 너비 기준 center 에 위치 하겠죠?

이렇듯 MATCH_CONSTRAINT 와 side constraint 의 관계를 유념하시면 좋을 것 같습니다.




다음은 Ratio 에 대한 내용입니다.

ConstraintLayout 에서는 위젯의 width, height 를 비율로 지정 할 수 있는 기능이 있습니다.
비율로 지정하고 싶은 width/height 에 0dp (MATCH_CONSTRAINT) 로 지정 한 후 layout_constraintDimensionRatio 속성을 사용하는 것인데요.

layout_constraintDimensionRatio="width:height" 형식의 비율로 사용 할 수 있습니다.

예를들어, 특정 TextView 의 width 는 text 크기 만큼만 지정하도록 wrap_content 로 놓고
height 는 width 에 지정 된 크기 만큼 비율로 설정하고 싶다면 아래와 같이 코드를 작성하면 됩니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="0dp"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintDimensionRatio="1:1" />

 

여담이긴한데, 위 예제 코드에서 TextView 의 left side constraint 를 따로 지정해줬는데요. 
(이 예제에서는 굳이 left constraint 속성이 필요하지 않은데 말이죠)
Developer 사이트 에서는 side constraint 없이 layout_constraintDimensionRatio 만 적용해도 ratio 가 적용 되는 것처럼 예제를 제시해놨는데
실제로는 side constraint 가 없으면 layout_constraintDimensionRatio 가 적용되지 않더라구요. 버그인지 의도 된 것인진 모르겠어서..
ConstraintLayout 코드를 분석중에 있습니다.

아무튼, side constraint 과 같이 써주세요.


다시 돌아와서, width 와 height 를 둘다 0dp (MATCH_CONSTRAINT) 로 지정한 뒤 ratio 를 적용하는 방법도 있습니다.
예제를 한번 볼게요.
<TextView
android:id="@+id/w_A"
android:layout_width="0dp"
android:layout_height="0dp"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="16:9"
android:textSize="15sp"
app:layout_constraintTop_toTopOf="parent"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintDimensionRatio="h,16:9" />

width 와 height 모두 0dp (MATCH_CONSTRAINT) 로 지정 하였고,
세로축 parent 양 사이드와의 constraint 를 지정 하였습니다
마지막으로 layout_constraintDimensionRatio 가 적용 되어있네요.

그런데 위에서 사용했던 layout_constraintDimensionRatio="1:1" 과는 약간 다른모습이죠?
app:layout_constraintDimensionRatio="h 혹은 w, width:height" 
이 포맷은 w (width) 또는 h (height) 를 constraint 시키고 지정 종횡비율을 적용 한다는 의미 입니다.

위 예제에서는, 세로축 parent 양 사이드와의 constraint 가 정의 되어있으므로
height 를 match_constraint 시키고 16:9 종횡비율을 적용 하겠다는 의미입니다.

그러면 결과 화면은 이렇게 나타납니다.

 

이러한 ConstraintLayout 에 Dimension Ratio 특성으로 여러 해상도에 대해 좀더 유연한 대응을 할 수 있게 되었습니다.






Dimension Constraints 에서 내용이 꽤 길어졌네요.
ConstraintLayout 에는 또 하나의 강력한 특성인 Chains 가 있습니다.

Chians 특성은 가로축/세로축 한축에 대해 특정 그룹을 짓는 것과 유사한 특성인데요.
Chain 을 설정하면 각 위젯이 서로 연결 되어 한 덩어리로 유연하게 배치시킬수 있는 장점이 있습니다.

일단 Chain 를 구성하는 방법부터 알아볼게요.

 

A, B 위젯이 있을 때 서로 쌍방향 constraint 가 정의 될 경우 두 위젯은 chain 관계에 있다고 간주합니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A"
app:layout_constraintRight_toRightOf="parent" />

첫번째 TextView 와 두번째 TextView 코드를 보면 서로 side 부분이 constraint 되있는 것을 볼 수 있습니다.
(XML 에서는 눈에 들어오지 않지만 레이아웃 에디터에서 두 위젯을 보면 서로 사이드가 연결 되어있는 것을 볼 수 있습니다.)

이 상태가 두 위젯이 chain 관계에 있다고 볼 수 있는 것입니다.



다음은 chain head 입니다.

 

각 chain 에는 head 가 되는 기준 위젯이 있습니다.
가로축 기준일 경우 chain 가장 왼쪽에 있는 위젯이 head 가 되고 세로축 기준일 경우 chain 가장 위쪽에 있는 위젯이 head 가 됩니다.

이 head 가 하는 역할은 chain 에 대한 내용을 계속 살펴보면서 언급하겠습니다.



이, chain 에는 특정 style 을 지정 할 수 있습니다.

 


CHAIN_SPREAD , CHIAN_SPREAD_INSIDE , CHAIN_PACKED  총 3개의 chain style 을 지원 합니다.
각각의 chain style 에 대해 살펴보겠습니다.




  • CHAIN_SPREAD -- the elements will be spread out  (default style)


spread 속성은 chain 으로 연결 된 widget 을 균일하게 퍼뜨리는 속성 입니다. 
기본 속성이며, chain 연결 후 별도의 style 를 지정하지 않으면 spread 속성으로 적용 됩니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

<TextView
android:id="@+id/w_B"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_A"
app:layout_constraintRight_toLeftOf="@+id/w_C" />

<TextView
android:id="@+id/w_C"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintLeft_toRightOf="@id/w_B"
app:layout_constraintRight_toRightOf="parent" />



세개의 위젯을 chain 으로 설정 하였습니다. 별도의 chain style 은 지정하지 않았으니 기본 속성인 spread 속성이 적용 됩니다.
spread 속성은 이와 같이 chain 관계에 있는 위젯들을 균일한 여백을 가지고 배치시키는 옵션 입니다.


  • Weighted chain -- in CHAIN_SPREAD mode, if some widgets are set to MATCH_CONSTRAINT, they will split the available space


spread 속성에서는 특정 위젯을 MATCH_CONSTRAINT 로 설정 하면 가용 공간의 크기로 지정 할 수도 있는데요.
위 예제코드에서 세번째 위젯만 width 를 0dp(MATCH_CONSTRAINT) 로 설정 해보겠습니다.



이렇게, 두번째 위젯 까지 배치 되고 남은 영역을 세번째 위젯의 width 로 지정 됩니다.

또한, spread 속성일 경우 weight 를 지정 할 수도 있습니다.
weight 로 지정할 위젯의 width 를 0dp (MATCH_CONSTRAINT) 로 지정 하고 weight 속성을 추가 하면 됩니다.
app:layout_constraintHorizontal_weight="1"



두번째와 세번째 위젯에 weight 를 각각 1로 적용해보겠습니다.
<?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">

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

<TextView
android:id="@+id/w_B"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_orange_dark"
android:gravity="center"
android:padding="5dp"
android:text="Widget Two"
android:textSize="15sp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/w_A"
app:layout_constraintRight_toLeftOf="@+id/w_C" />

<TextView
android:id="@+id/w_C"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:background="@android:color/holo_purple"
android:gravity="center"
android:padding="5dp"
android:text="Widget Three"
android:textSize="15sp"
app:layout_constraintHorizontal_weight="1"
app:layout_constraintLeft_toRightOf="@id/w_B"
app:layout_constraintRight_toRightOf="parent" />

</android.support.constraint.ConstraintLayout>


이렇게 weight 설정 된 두번째 세번째 위젯의 width 가 각각 1:1 로 배치 되었습니다.





  • CHAIN_SPREAD_INSIDE -- similar, but the endpoints of the chain will not be spread out


다음은 SPREAD_INSIDE 속성인데요.
기본 원리는 SPREAD 속성과 같지만 차이점은 Chain 의 양끝 side 부분은 spread 되지 않는 다는 점입니다.

그럼, chain style 를 한번 SPREAD_INSIDE 로 바꿔 보겠습니다.
chain style 은 chain 의 head 가 되는 위젯에 설정 하면 됩니다.
각 chain 의 head 가 하는 역할은 이렇게 해당 chain 의 특성을 정의 할때 사용 되어 집니다.

위 에제코드에서는 가로축 chain 이 지정 되어 있고 가장 왼쪽 위젯이 head 가 됩니다.
그러므로 head widget 에서 chain style 을 설정해보겠습니다.

가로축 chain 일 경우
app:layout_constraintHorizontal_chainStyle=""
세로축 chain 일 경우
app:layout_constraintVertical_chainStyle=""
속성을 사용 하면 됩니다.

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintHorizontal_chainStyle="spread_inside"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />



이렇게 균등하게 배치 되지만 chain 의 양 사이드는 spread 되지 않는 것을 볼 수 있습니다.




  • CHAIN_PACKED -- the elements of the chain will be packed together. The horizontal or vertical bias attribute of the child will then affect the positioning of the packed elements

마지막으로 PACKED 속성 입니다.
PACKED 속성은 chain 으로 연결 된 위젯을 하나로 묶어서 center 로 배치 시킵니다. 

head 위젯에서 chain style 을 PACKED 으로 바꿔 보겠습니다.

<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

 

이때,  Center positioning 에서 알아보았던 bias 속성을 지정 할 수 있는데요.
head 위젯에 bias 를 적용하면, chain 단위에서 bias 특성이 적용 됩니다.
bias 의 기본 값은 0.5 라고 하였으니, 0.2 로 지정 해보겠습니다.
<TextView
android:id="@+id/w_A"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:background="@android:color/holo_blue_bright"
android:gravity="center"
android:padding="5dp"
android:text="Widget One"
android:textSize="15sp"
app:layout_constraintHorizontal_chainStyle="packed"
app:layout_constraintHorizontal_bias="0.2"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toLeftOf="@+id/w_B" />

 

이렇게 chain 의 bias 가 적용 된 것을 확인 할 수 있겠습니다.





Chain 속성에 대해 알아 보았고, 마지막 내용으로 Guideline 에 대해 알아보겠습니다.
ConstraintLayout 에는 레이아웃 작업을 돕기 위한 Guideline 객체를 지원 합니다.
이 또한 Chain 연결 처럼 XML 상으로 눈에 보이지 않지만 레이아웃 에디터에서 지정 된 Guideline 이 나타나는 것을 볼 수 있죠.
Guideline 은 기본적으로 gone 처리가 되어있기 때문에 실제로 화면에 나타나지 않습니다.
<android.support.constraint.Guideline
android:id="@+id/guideline1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
app:layout_constraintGuide_percent=".15" />
 
이런 식으로 Guideline 을 추가 하면 레이아웃 에디터에서 추가 된 Guideline 을 볼 수 있습니다.

 

그리고 배치 하고자 하는 위젯을 먼저 잡아놓은 Guideline 에 Constraint 시켜서 작업을 진행 할 수 있습니다.
Guideline 이 사용 된 예시는 Developer 사이트에 있는 좋은 예시를 첨부 합니다.
<android.support.constraint.Guideline
android:id="@+id/left_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".15" />

<android.support.constraint.Guideline
android:id="@+id/right_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="vertical"
app:layout_constraintGuide_percent=".85" />

<android.support.constraint.Guideline
android:id="@+id/top_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".15" />

<android.support.constraint.Guideline
android:id="@+id/bottom_guideline"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:orientation="horizontal"
app:layout_constraintGuide_percent=".85" />

<Button
android:id="@+id/button"
android:layout_width="0dp"
android:layout_height="0dp"
android:text="Button"
app:layout_constraintBottom_toBottomOf="@+id/bottom_guideline"
app:layout_constraintLeft_toLeftOf="@+id/left_guideline"
app:layout_constraintRight_toRightOf="@+id/right_guideline"
app:layout_constraintTop_toTopOf="@+id/top_guideline" />

 

support library 였던 PercentRelativeLayout 이 ConstraintLayout 이 나오면서 Deperecated 되었는데, 
이 예제가 Developer 사이트에서 PrecenetRelativeLayout 대신에 이렇게 사용하도록 가이드 되고 있네요.
참고하시면 좋을 듯 합니다.




이렇게 해서 ConstraintLayout 에 대해 알아 보았습니다.
특성이 많아서 이해하는데 시간이 좀 걸렸는데, 앞으로 레이아웃 작업에 많은 이점이 있을 것 같습니다.
잘못 된 부분이 있으면 알려주시기 바랍니다. 
이상 마치겠습니다. 
반응형

댓글