프로그래밍/Android

[Android] ConstraintLayout 에 대해

전에 회사 세미나 때 만들어 뒀던 ppt

 

안드로이드를 1년 반 정도 하면서 느낀 점은 ConstraintLayout을 정말 많이 쓴다는 것이다..!

 

그래서 안드로이드 첫 글을 뭘 쓸까 생각하다가 안드로이드의 xml 뷰에 관해 쓰자 생각하고 꺼낸게 이거다.


ConstraintLayout은 ViewGroup을 상속받아 확장시킨 라이브러리다. 기존에 쓰던 LinearLayout, RelativeLayout의 업글 버전이라고 생각한다.

 

요오즘 새 프로젝트 생성하고 activity_main.xml 생성하면 요로코롬 나온다 (Button으로 수정해둠)

최상단 부모 레이아웃이 ConstraintLayout이여야 하며 

xmlns:app="http://schemas.android.com/apk/res-auto"

를 추가해줘야 자식 뷰들에 관련 속성을 추가할 수 있다.

app:layout_constraintTop_toTopOf="parent"
app:layout_constraintLeft_toLeftOf="parent"
app:layout_constraintRight_toRightOf="parent"
app:layout_constraintBottom_toBottomOf="parent"

얘네는 상대적 배치라고 한다. RelativeLayout에 썼던거랑 비슷하다고 보면 된다. 그리고 자식 뷰에 저렇게 속성을 넣으면 뷰의 가운데로 온다.

 

  • 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

기존꺼 복붙 개꿀

 

요로코롬 각종 상대적 배치 속성이 있다. 이중에 예제로 만들어 본 뷰를 보자.

xml 코드
View

A 버튼 기준으로 B 버튼이 A의 오른쪽에 붙었다. 이것은 코드에 밑줄 친 속성 때문이다.

해당 버튼 (B 버튼)의 왼쪽(Left)을 A 버튼의 오른쪽(Right)에 붙게끔 하겠다는 속성이다.

 

layout_constraintLeft_toRightOf


그리고 상대적 배치 중에 원형 배치가 가능하기도 하다.

 

xml 코드
View

이거슨 B 버튼이 A 버튼을 기준으로 45º, 200dp가 떨어진 것이다. 속성들은

 

layout_constraintCircle : 기준으로 참조할 ViewID

layout_constraintCircleRadius : 참조한 View와의 반지름 거리

layout_constraintCircleAngle : 참조한 View로부터의 각도

 

들이 있다. 나는 이 속성을 ImageView에 썼던 기억이 있다. 은근 괜춘하지만 잘 쓰진 않는다.


다음은 Bias다. 이것은 상대적 배치에서 추가적으로 사용하는 것이다. 가끔 비율로 디자인을 정해서 받을 때가 있는데 그때 사용하면 정말 좋다.

 

xml 코드
View

이렇게 속성 두개만 추가해 준다면 가운데로 오던 버튼이 가로와 세로가 특정 퍼센트에 맞춰지게 된다.

 

layout_constraintVertical_bias : Bias 세로 속성. 0부터 1까지 넣을 수 있다.

layout_constraintHorizontal_bias : Bias 가로 속성. 마찬가지로 0부터 1까지 넣을 수 있다.

 

둘다 마찬가지로 0~1까지의 값을 넣어주면 된다. 0은 0%, 1은 100%이고
Vertical에 0을 넣으면 Top(0%)에 붙고, 1을 넣으면 Bottom(100%)에 붙는다.

Horizontal은 0을 넣으면 Left(0%)에 붙고, 1을 넣어주면 Right(100%)에 붙는다.

 

실무 때는 RecyclerView의 Item View들 디자인에 맞추기위해 쓴 기억이 있다...


다음은 Chain이다. 이것은 View와 View끼리 연결을 해서 묶을 수 있다.

체체체체이닝

 

체인을 걸어준 View

코드를 보면 Button 3개가 있는데, 각각의 View들이 맞물리도록 의존성을 부여했다. 이렇게 의존성을 부여해주면 쫀쫀한 관계가 되어서 A든 B든 C든 MarginLeft, MarginRight 속성을 추가하면 위치가 다같이 변한다.

(이거슨 Left, Right로 묶었기 때문에 MarginTop, MarginBottom 속성을 추가해주면 바뀌지는 않는다)

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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="wrap_content"
    android:layout_margin="8dp"
    android:background="@drawable/box_round_3dp_white"
    android:minHeight="90dp"
    android:translationZ="8dp">

    <TextView
        android:id="@+id/t_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/margin_horizontal_default"
        android:ellipsize="end"
        android:letterSpacing="0.03"
        android:textColor="@color/txt_dark_color"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@+id/t_content"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/img_bucket_right"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="RtlHardcoded"
        tools:text="500만원 모으기" />

    <TextView
        android:id="@+id/t_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/margin_horizontal_default"
        android:ellipsize="end"
        android:letterSpacing="0.03"
        android:textColor="@color/txt_black_color"
        android:textSize="14sp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/t_title"
        tools:ignore="RtlHardcoded"
        tools:text="돈을 열심히 모아보자" />

    <ImageView
        android:id="@+id/img_bucket_right"
        android:layout_width="8dp"
        android:layout_height="8dp"
        android:layout_marginTop="12dp"
        android:layout_marginRight="12dp"
        android:contentDescription="@string/description_bucket_right"
        android:src="@drawable/circle_right"
        app:layout_constraintRight_toRightOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="RtlHardcoded" />

</androidx.constraintlayout.widget.ConstraintLayout>

이것은 세미나 발표 자료가 부족해서 개인앱에 사용된 xml을 가져왔다.

 

지금 t_titlet_content는 쫀쫀하게 체인이 되어있다. 이렇게 체인을 걸어주면

쫀-쫀

 

이런 View가 만들어진다. ChainStyle 속성을 추가해주지 않아서 위, 아래, 가운데 여백이 동일하게 들어간 모습이다. 만약에 여기세 ChainStyle을 추가해준다면?!

 

서먹서먹해진 사이

이렇게 변하게 할 수 있다. (app:layout_constraintVertical_chainStyle="spread_inside"를 추가해준 모습)

또한 ChainStyle은 맨 상단 View에만 추가해주면 된다.

 

layout_constraintVertical_chainStyle : 세로로 묶인 View들의 ChainStyle을 바꿔줄 수 있다.

layout_constraintHorizontal_chainStyle : 가로로 묶인 View들의 ChainStyle을 바꿔줄 수 있다.

 

여기에 들어가는 값들은

  • spread : 기본값이며 View가 같은 여백을 가짐
  • spread_inside : 안쪽 View들만 여백을 가짐(부모 View의 여백이 사라짐)
  • packed : View들을 뭉치게 하고 부모 View의 여백만 가짐

총 3개다. Chain은 정말 자주 썼던 것 같다. 특히 높이 값이 자유자제로 바뀌는 View를 구현할 때 썼던 기억이 있다.


다음은 goneMargin 이다. xml로 View를 짤 때, 어쩔 때는 보여지고, 어쩔 때는 사라지는 View들이 있을 것이다. 그때 Chain되어 있는 View가 사라지게 되면 꼼짝없이 묶인 다른 View들이 위치가 바뀐다. 그것을 방지하기 위해 goneMargin을 추가해준다.

 

  • layout_goneMarginStart
  • layout_goneMarginEnd
  • layout_goneMarginLeft
  • layout_goneMarginTop
  • layout_goneMarginRight
  • layout_goneMarginBottom

뭐야 제 친구 돌려줘요

아까 코드에서 t_title의 visibility 속성의 값을 gone을 주었더니 이런 View가 되었다... 이때 t_content에 layout_gone_margintTop을 준다면?!

   <TextView
        android:id="@+id/t_title"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/margin_horizontal_default"
        android:ellipsize="end"
        android:letterSpacing="0.03"
        android:textColor="@color/txt_dark_color"
        android:textSize="18sp"
        app:layout_constraintBottom_toTopOf="@+id/t_content"
        app:layout_constraintHorizontal_bias="0"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintRight_toLeftOf="@+id/img_bucket_right"
        app:layout_constraintTop_toTopOf="parent"
        tools:ignore="RtlHardcoded"
        tools:text="500만원 모으기"
        android:visibility="gone"/>

    <TextView
        android:id="@+id/t_content"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_marginLeft="@dimen/margin_horizontal_default"
        android:ellipsize="end"
        android:letterSpacing="0.03"
        android:textColor="@color/txt_black_color"
        android:textSize="14sp"
        app:layout_goneMarginTop="30dp"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintLeft_toLeftOf="parent"
        app:layout_constraintTop_toBottomOf="@+id/t_title"
        tools:ignore="RtlHardcoded"
        tools:text="돈을 열심히 모아보자" />

만족스럽지는 않지만 그래도 선녀같다!

layout_goneMarginTop="30dp"을 준 결과다. 어느정도 공간이 떨어지기 때문에 그나마 보기 좋아진? 느낌이다. 실무에서는 가끔 아이콘이 없을 경우가 있어서 그때를 위해 사용했던 기억이 있다.


마지막으로 Guidline이다. 가이드라인은 말그대로 가이드를 해줄 수 있는 선이다. 가끔 디자인 여백 중에 특정 View만 제외하고 군대에서 각재듯 정렬되어 있는 것들이 있을 때, 각각의 View에 marginLeft="30dp"를 주었다고 가정하자.

그런데 갑자기 이변이 생긴다... 디자인이 바뀐다면 xml에 각각 걸어줬던 margin 값을 다 바꿔줘야한다. (끔----찍하다) 그걸 방지하려면 가이드라인을 사용하는걸 추천한다.

 

God-ideline
View

가이드라인을 걸어주고 View들에게 가이드라인을 의존하게 해준다면, 방금 말했던 디자인 수정 때문에 고통받는 일이 적어질 수 있다. 실제로 이걸 모르고 까먹고 있다가 디자인의 지속적인 수정 때문에 찾아서 쓰게 됐다.


Android 신입 때, 변변치 않은 지식으로 만든 세미나 내용을 갖고와서 풀어보았다. 그래도 어느정도 유익한 내용이기에 블로그에 글로 남겨본다.

 

설명이 부족한 부분은 댓글을 써주신다면 바로 반영해보겠습니다.