* 출처
: http://dktfrmaster.blogspot.kr/2016/09/constraintlayout.html
: https://recipes4dev.tistory.com/158
* 참고할만한 자료
: http://blog.naver.com/pistolcaffe/221010983726 (Android ConstraintLayout 분석 - 1)
: http://blog.naver.com/pistolcaffe/221290283458 (Android ConstraintLayout 분석 - 2)
ConstraintLayout
현재로써는, 다음과 같은 제약조건을 이용할 수 있다.
- Relative Positioning
- Margins
- Centering Positioning
- Visibility Behavior
- Dimension Constraint
- Virtual Helpers Objects
참고로, 제약조건은 순환관계를 가질 수 없다.
API 9(진저브레드) 이상
부터 이용할 수 있다. 안드로이드 팀은 이 레이아웃에 더 많은 기능을 추가할 예정이며, 바뀐 내용은 이 문서에 반영될 것이다.
개발 가이드
Relative Positioning (기존의 RelativeLayout과 유사)
이 제약조건은 어떤 위젯을 다른 위젯에 상대적으로 배치할 수 있도록 한다.
이 제약조건은 위젯의 수직,수평을 기준으로 추가한다.
- 수직 : Left, Right, Start, End
- 수평 : Top, Bottom
<Button android:id="@+id/buttonA" ... />
<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toRightOf="@+id/buttonA" />
위치 제약조건은 시스템이 각 위젯의 사이드를 같은 위치가 되도록 배치할 것이다.
- layout_constraintLeft_toLeftOf
- layout_constraintLeft_toRightOf
- layout_constraintRight_toLeftOf
- layout_constraintRight_toRightOf
- layout_constraintTop_toTopOf
- layout_constraintTop_toBottomOf
- layout_constraintBottom_toTopOf
- layout_constraintBottom_toBottomOf
- layout_constraintBaseline_toBaselineOf
- layout_constraintStart_toEndOf
- layout_constraintStart_toStartOf
- layout_constraintEnd_toStartOf
- layout_constraintEnd_toEndOf
기준이 될 위젯의 id가 필요
하다. 혹은 부모를 의미하는 parent
를 입력한다.<Button android:id="@+id/buttonB" ...
app:layout_constraintLeft_toLeftOf="parent" />
Margins
기존에 사용했던 마진을 주는 방법으로 제약조건을 추가할 수 있다.
- android:layout_marginStart
- android:layout_marginEnd
- android:layout_marginLeft
- android:layout_marginTop
- android:layout_marginRight
- android:layout_marginBottom
Gone 상태의 위젯에 연결되었을때의 Margin
위치 제약조건의 대상이 View.GONE 상태일 때, 기존의 마진과는 다른 마진값을 적용할 수 있다.
이 값을 적용하려면 다음의 속성들을 이용한다.
- layout_goneMarginStart
- layout_goneMarginEnd
- layout_goneMarginLeft
- layout_goneMarginTop
- layout_goneMarginRight
- layout_goneMarginBottom
Centering positioning and bias
ConstraintLayout은
불가능한
제약조건을 잘 처리할 수 있기 때문에 유용하다. 예를 들어, 다음과 같은 상황이 있을 수 있다.<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>
(버튼의 양 사이드는 우리가 의도한 곳에 놓이지 않는다) 이런 경우에, 제약조건은 다음 그림과 같이 버튼을 양쪽 끝에서 같은 힘으로 당기는 것처럼
동작한다. 결과적으로, 버튼은 부모 컨테이너의 중앙에 놓이게 된다. 이는 수직의 제약조건에서도 유사하게 적용된다.
Bias
위에서 살펴본 바와 같이, 기본적으로 상반되는 두 제약조건의 결과는 위젯을 중앙에 배치시킨다.
하지만,
bias
라는 속성을 이용해 어느 한쪽에 더 가깝도록 위젯을 배치할 수 있다. 그 속성은 다음과 같다.- layout_constraintHorizontal_bias
- layout_constraintVertical_bias
다음의 예제는 A 위젯을 기존의 50% 중앙 위치 대신, 30%인 왼쪽으로 기울도록 배치할 것이다.
<android.support.constraint.ConstraintLayout ...>
<Button android:id="@+id/button" ...
app:layout_constraintHorizontal_bias="0.3"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent/>
</>
Visibility Behavior
GONE
위젯은 화면에 보여지지 않고, 레이아웃의 일부가 아니다.(즉, 실제 Dimension이 변하지 않는다.)
그러나, 레이아웃의 제약조건 관점에서,
GONE
위젯은 여전히 레이아웃의 일부이다.(이는 중요한 특징이 있다.)GONE
위젯의 크기는 0으로 처리된다.- 다른 위젯이
GONE
위젯에 제약조건을 걸었을 때, 그 제약조건은 여전히 유효하지만,GONE
된 위젯의 마진은 0으로 처리된다.
그림처럼 B는 자신이 A에 걸었던 마진값만 남게 된다. 제약조건을 걸었던 위젯의 GONE 여부에 따라 대체하는 마진값을 주기 위해,
위에서 소개했던
Gone margin
값을 이용한다.Dimensions 제약조건
android:layout_width
, android:layout_height
속성을 이용해서, 다음의 3가지 방법으로 위젯의 크기를 지정할 수 있다.- 특정 크기(
123dp
,@dimen/height
) wrap_content
위젯 자신이 크기를 결정0dp
-match_constraint
와 동일
처음의 두 방법은 다른 레이아웃과 동일하게 동작한다. 마지막 방법은 위젯이 제약조건에 맞춰서 리사이징 될 것이다.
위의 그림에서, (a)는
wrap_content
, (b)는 0dp, (c)는 마진값이 있을 때의 0dp 이다.Ratio
위젯 크기는
수평:수직
의 비율로도 정할 수 있다. 비율로 크기를 정하려면, width/height를 0dp
(or match_constraint
)로 지정하고layout_constraintDimensionRatio
속성을 이용해 수평:수직 비율값을 준다. 다음의 예시는 수평:수직 비율을 1:1로 준 것이다.<Button android:layout_width="wrap_content"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="1:1" />
비율은 다음과 같이 2가지 방법으로 표현될 수 있다.
- width와 height의 비율을 나타내는 소수값
width : height
비율
수평과 수직이 모두
match_constraint(0dp)
일 때도 비율로 나타낼 수 있다. 단, 이 때는
layout_constraintDimensionRatio
속성에 W
or H
를 명시하여 변경될 사이드를 지정해 주어야 한다. (
W
는 수평, H
는 수직) 사이드 구분자는 ,
쉼표로 비율과 구분한다.<Button android:layout_width="0dp"
android:layout_height="0dp"
app:layout_constraintDimensionRatio="H,16:9"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
Vertual Helper Object
지금까지 설명된 위의 내용 이외에도,
ConstraintLayout
에서 레이아웃을 쉽게 배치할 수 있도록 하는 헬퍼 클래스가 있다. Guideline
클래스는 ConstraintLayout 내에 상대적으로 배치됬을 때, 수평 or 수직적인 가이드 라인을 생성해준다. 개발자는 그 가이드라인의 제약조건대로 위젯을 배치하면 된다.
Guideline
ConstraintLayout의 제약조건을 쉽게 설정하도록 도와주는 헬퍼클래스로, 이 객체는 화면에 나타나지 않고,(이 객체들은 View.GONE 상태이다.)
오로지 레이아웃을 위해 사용된다. 이 객체들은 ConstraintLayout 안에서만 사용된다.
Guideline
객체는 수평, 수직이 될 수 있다.- 수직 Guideline은 width가 0이고, height는 ConstraintLayout과 같다.
- 수평 Guideline은 height가 0이고, width는 ConstraintLayout과 같다.
Guideline 객체의 위치는 다음의 3가지가 가능하다.
- Left(수평일 경우) or Top(수직일 경우) 로부터 고정된 거리 -
layout_constraintGuide_begin
- Right(수평일 경우) or Bottom(수직일 경우) 로부터 고정된 거리 -
layout_constraintGuide_end
- ConstraintLayout의 width or height에 대한 퍼센트 위치 -
layout_constraintGuide_percent
Guideline
객체를 이용하여 다른 위젯을 쉽게 배치할 수 있고, 위젯이 Guideline
객체에 제약조건을 추가할 수 있다. xml에서는 다음의 예시와 같이 사용할 수 있다.
<android.support.constraint.ConstraintLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent">
<android.support.constraint.Guideline
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/guideline"
app:layout_constraintGuide_begin="100dp"
android:orientation="vertical"/>
<Button
android:text="Button"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/button"
app:layout_constraintLeft_toLeftOf="@+id/guideline"
android:layout_marginTop="16dp"
app:layout_constraintTop_toTopOf="parent" />
</android.support.constraint.ConstraintLayout>
ConstraintSet
위에 소개된 방법들은, 모두 xml에서의 적용방법이다.
ConstraintSet
클래스의 객체를 이용하면 제약조건을 소스코드에서 변경할 수 있다. 이 클래스는 몇가지의 생성 방법이 있다.
- Manually
ConstraintSet c = new ConstraintSet();
c.connect(...);
- R.layout.* 로부터
ConstraintSet c = c.clone(context, R.layout.some_layout);
- ConstraintLayout 으로부터
c.clone(cLayout);
안드로이드 컨스트레인트레이아웃. (Android ConstraintLayout)
1. 안드로이드 레이아웃 작성.
안드로이드 앱을 개발할 때, UI 화면을 구성하는 작업은 보기만큼(?) 마냥 쉬운 일이 아닙니다. 특히 앱 개발 경험이 상대적으로 부족한 초보 개발자들에겐, 앱의 탐색 메뉴 구성과 컨테이너 선택, 그리고 각 화면에 들어갈 레이아웃과 뷰 위젯 등을 결정하는 일이, 비즈니스 로직(business logic)을 구현하는 작업보다 우선적으로 해결해야 할 과제로 여겨지기도 하죠. 게다가, 요구사항의 변경으로 인해 화면 요소의 배치를 빈번하게 수정해야 하는 일이 발생하면 UI 화면을 수정하는데에만 전체 개발 시간의 상당 부분을 소비하게 될지도 모릅니다.
그러므로 안드로이드 UI 컴포넌트의 종류와 특성, 사용법을 정확히 이해하고 사용하는 것은 매우 중요한 일입니다. 특히, 뷰 위젯을 화면에 배치하기 위해 사용하는 레이아웃(Layout)은, 화면 구성이 복잡할수록, 또, 사용되는 뷰 위젯의 갯수가 많을수록, 어떤 종류의 레이아웃(들)을 선택하는지가 화면 구성 시간, 동작 성능, 유지보수 등에 영향을 줄 수 있습니다.
과거, "UI 구성의 유연함"보다 "배치의 직관성"이 중요시되던 시기에는, 여러 종류의 레이아웃을 중첩(nested)하여 UI를 구성하는 경우가 많았습니다. 사용하기 쉽고, 설계에 따른 화면 구성이 용이했기 때문인데요. 하지만 레이아웃을 중첩해서 사용하는 방법은 성능과 유지보수 측면에서 그다지 효율적이지 못한 단점이 있습니다.
그래서, 레이아웃을 중첩(nested)하지 않고 유연한 방법으로 뷰 위젯들을 배치할 수 있는 레이아웃이 만들어지게 되었습니다. 렐러티브레이아웃(RelativeLayout)의 "상대적 위치 관계에 따른 배치" 특성에 리니어레이아웃(LinearLayout)의 "가중치(weight)가 가진 장점"을 적용하고, 체인(chain) 사용으로 다른 레이아웃 없이 "요소들을 그룹화"할 수 있는, 그리고 그 동안 유명무실(?)했던 레이아웃 에디터를 적극 활용하여 좀 더 쉽고 빠르게 화면을 구성할 수 있게 만들어주는 레이아웃. 바로 컨스트레인트레이아웃(ConstraintLayout)입니다.
2. 안드로이드 컨스트레인트레이아웃(ConstraintLayout) 클래스
컨스트레인트레이아웃(ConstraintLayout)은 레이아웃 구성 시, 뷰 위젯의 위치와 크기를 유연하게 조절할 수 있게 만들어주는 레이아웃입니다. 음.. 너무 추상적인 표현이죠? 조금 더 구체적인 내용부터 차근차근 알아보겠습니다.
컨스트레인트레이아웃이 어떠한 방식으로 레이아웃 배치의 유연함을 제공하는지는, "컨스트레인트(Constraint)"라는 단어의 의미를 통해 유추할 수 있습니다. 바로 Constraint, "제약(또는 조건)"이죠.
컨스트레인트레이아웃는 레이아웃에 배치되는 뷰들에 여러 제약(Constraint)을 적용하여 각 뷰의 위치와 크기를 결정합니다. 여기서 말하는 "제약(Constraint)"이란, 각 요소들의 최종 위치와 크기를 결정하게 될 조건, 예를 들어, 특정 뷰 왼쪽 사이드를 지정된 뷰의 오른쪽 사이드에 맞추거나, 뷰의 왼쪽,오른쪽 사이드를 각각 부모 레이아웃의 왼쪽,오른쪽 사이드에 맞추는 것 등을 말하며, 이러한 각각의 제약(Constraint)은 컨스트레인트레이아웃이 가지는 하나의 레이아웃 속성으로 매핑됩니다. (이런 이유로, 본문과 이후 컨스트레인트레이아웃 관련 글에서는 제약(Constraint)과 속성이라는 용어를 섞어서 사용한다는 점 참고하시기 바랍니다.)
3. 컨스트레인트레이아웃 속성 기본 사용법.
컨스트레인트레이아웃이 제공하는 "제약(Constraint)"들, 즉, 컨스트레인트레이아웃 속성의 이름은 기본적으로 "layout_constraint"로 시작하며, 바로 뒤에 구체적인 제약 조건이 명시됩니다.
예를 들어, 뷰의 "왼쪽 사이드를 대상 뷰의 오른쪽 사이드에 배치"하는 속성은 "layout_constraintLeft_toRightOf"입니다. "layout_constraint"에 "Left_toRightOf"라는 제약 조건을 결합하여, 뷰의 왼쪽 사이드(Left)를 속성 값으로 지정된 ID 뷰의(Of) 오른쪽 사이드(ToRight)에 맞추라는 제약을 지정할 수 있습니다.
앱 개발 시, 레이아웃을 구성할 때는, 아래와 같이 XML 코드를 작성합니다.
<?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"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".MainActivity"
tools:showIn="@layout/activity_main">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="48sp"
android:background="#FF0000"
android:id="@+id/text1"
android:text="TEXT1" />
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:textSize="48sp"
android:background="#00FF00"
android:id="@+id/text2"
android:text="TEXT2"
app:layout_constraintLeft_toRightOf="@id/text1" />
</android.support.constraint.ConstraintLayout>
4. 컨스트레인트레이아웃이 제공하는 제약(Constraint).
컨스트레인트레이아웃이 제공하는 제약(Constraint)은 그 종류가 매우 많으며, 사용 목적과 방법에 따라 몇 가지 카테고리로 분류됩니다, 물론, 컨스트레인트레이아웃을 사용하는데 있어, 하나의 속성 또는 하나의 카테고리에 속한 속성들만 사용할 수 있는 것은 아니며, 필요에 따라, 여러 카테고리의 제약들을 다양하게 조합하여 사용합니다.
아래 그림은 컨스트레인트레이아웃에서 사용할 수 있는 제약(Constraint)들을 카테고리로 구분하여 정리한 내용인데요, 카테고리에 대한 분류와 기본적인 설명은 [안드로이드 개발 참조문서. ConstraintLayout]에서 참고할 수 있습니다.
아래 표의 항목을 클릭하면, 각 항목에 대한 좀 더 상세한 설명과 예제를 확인할 수 있습니다.
카테고리 | 설명 |
---|---|
Relative positioning | 요소 간 상대 위치 지정. (left, right, top, bottom, start, end, baseline) |
Margins | 요소 간 여백(Margin) 설정을 위한 제약. |
Centering positioning | 뷰를 부모 레이아웃 또는 제약 영역의 중앙에 배치. |
Circular positioning | 대상 뷰를 기준으로 각도(angle)와 반지름(radius)으로 상대 위치 지정. |
Visibility behavior | 뷰의 Visibility 상태에 따른 최종 위치 결정 및 여백. |
Dimension constraints | 뷰에 적용된 제약에 따른 뷰의 크기(Dimension) 결정. |
Chains | 수평 또는 수직 방향(Axis)으로 나열된 뷰에 대한 그룹화. 배치 스타일 지정. |
Virtual Helpers objects | 레이아웃 내 효율적인 뷰 배치에 사용 가능한 몇 가지 Helper 객체들. (Guideline, Barrier, Group) |
Optimizer | 제약 카테고리에 대한 최적화. |
아래 표는 컨스트레인트레이아웃에서 제공하는 속성을 나열한 것입니다. 각 속성 이름을 클릭하면, 해당 속성에 대한 자세한 설명을 확인할 수 있습니다.
ConstraintLayout 속성 | 설명 |
---|---|
layout_constraintLeft_toLeftOf | 뷰의 왼쪽 사이드(Side)를 대상 뷰의 왼쪽 사이드(Side)에 맞춤. |
layout_constraintLeft_toRightOf | 뷰의 왼쪽 사이드(Side)를 대상 뷰의 오른쪽 사이드(Side)에 맞춤. |
layout_constraintRight_toLeftOf | 뷰의 오른쪽 사이드(Side)를 대상 뷰의 왼쪽 사이드(Side)에 맞춤. |
layout_constraintRight_toRightOf | 뷰의 오른쪽 사이드(Side)를 대상 뷰의 오른쪽 사이드(Side)에 맞춤. |
layout_constraintTop_toTopOf | 뷰의 위쪽 사이드(Side)를 대상 뷰의 위쪽 사이드(Side)에 맞춤. |
layout_constraintTop_toBottomOf | 뷰의 위쪽 사이드(Side)를 대상 뷰의 아래쪽 사이드(Side)에 맞춤. |
layout_constraintBottom_toTopOf | 뷰의 아래쪽 사이드(Side)를 대상 뷰의 위쪽 사이드(Side)에 맞춤. |
layout_constraintBottom_toBottomOf | 뷰의 아래쪽 사이드(Side)를 대상 뷰의 아래쪽 사이드(Side)에 맞춤. |
layout_constraintBaseline_toBaselineOf | 뷰의 텍스트 Baseline을 대상 뷰의 텍스트 Baseline에 맞춤. |
layout_constraintStart_toEndOf | 뷰의 시작 사이드(Side)를 대상 뷰의 끝 사이드(Side)에 맞춤. |
layout_constraintStart_toStartOf | 뷰의 시작 사이드(Side)를 대상 뷰의 시작 사이드(Side)에 맞춤. |
layout_constraintEnd_toStartOf | 뷰의 끝 사이드(Side)를 대상 뷰의 시작 사이드(Side)에 맞춤. |
layout_constraintEnd_toEndOf | 뷰의 끝 사이드(Side)를 대상 뷰의 끝 사이드(Side)에 맞춤. |
layout_goneMarginLeft | 뷰 위젯의 왼쪽(Left) 사이드 대상 뷰가 View.GONE 상태일 때 여백 설정. |
layout_goneMarginTop | 뷰 위젯의 위(Top) 사이드 대상 뷰가 View.GONE 상태일 때 여백 설정. |
layout_goneMarginRight | 뷰 위젯의 오른쪽(Right) 사이드 대상 뷰가 View.GONE 상태일 때 여백 설정. |
layout_goneMarginBottom | 뷰 위젯의 아래(Bottom) 사이드 대상 뷰가 View.GONE 상태일 때 여백 설정. |
layout_goneMarginStart | 뷰 위젯의 시작(Start) 사이드 대상 뷰가 View.GONE 상태일 때 여백 설정. |
layout_goneMarginEnd | 뷰 위젯의 끝(Start) 사이드 대상 뷰가 View.GONE 상태일 때 여백 설정. |
layout_constraintHorizontal_bias | 수평 방향(Left/Right 또는 Start/End) 사이드 제약 시, 양 사이드 간 위치 비율. |
layout_constraintVertical_bias | 수직 방향(Top/Bottom) 사이드 제약 시, 양 사이드 간 위치 비율. |
layout_constraintCircle | 원형 위치 지정에 사용될 대상 뷰 ID 지정. |
layout_constraintCircleRadius | 원형 위치 지정 시, 뷰 위젯과 대상 뷰 위젯 중심 사이의 거리. |
layout_constraintCircleAngle | 원형 위치 지정 시, 원 둘레에서 뷰 위젯이 배치될 각도. |
5. 참고.
- ConstraintLayout에 대한 자세한 도움말.
- [안드로이드 개발 참조문서 ConstraintLayout]을 참고하세요.
- [안드로이드 개발 참조문서 ConstraintLayout.LayoutParams]을 참고하세요.
- Build a Responsive UI with ConstraintLayout.
- [Build a Responsive UI with ConstraintLayout ]을 참고하세요.
- 개발자 레시피 - 레이아웃 관련 항목
- [안드로이드 레이아웃 (Android Layout)]을 참고하세요.
- [안드로이드 레이아웃 공통사항 (Android Layout Common)]을 참고하세요.
- [안드로이드 리니어레이아웃 (Android LinearLayout)]을 참고하세요.
- [안드로이드 렐러티브레이아웃 (Android RelativeLayout)]을 참고하세요.
- 레이아웃에 대한 자세한 도움말.
- [안드로이드 개발 참조문서 레이아웃 항목]을 참고하세요.
.END.
'IT_Programming > Android_Java' 카테고리의 다른 글
[펌] Android Support Annotations 라이브러리를 활용한 결함 탐지 (0) | 2016.11.02 |
---|---|
[펌] 안드로이드 웹뷰 CookieSyncManager 정확한 사용법 (0) | 2016.10.24 |
[펌] Android Support Library 24.2.0의 버그 (0) | 2016.09.28 |
Android 7.0(Nougat)에서 DatePickerDialog 예외사항 (0) | 2016.09.01 |
[펌] AsyncQueryHandler를 이용한 콘텐트 프로바이더(ContentProvider) 접근 (0) | 2016.08.31 |