💡 Intro
우테코에 들어오면서 ContraintLayout을 처음 써봤고, 지금까지도 적응중이다. 많이 익숙해졌지만 아직까지도 실수하는 부분들이 많다. 그리고 더 깊게 알아보기 전까지 0dp == match_parent 이지만 ConstraintLayout에서는 0dp를 쓰는 것이 맞구나 했다. (아님)
❓ ConstaintLayout
아주 간단하게 ConstraintLayout이 무엇인지 알아보자.
Constraint과 Layout을 합친 단어다. Constraint는 '제약 조건'을 뜻하는 단어이며 이에따라 뷰를 정렬하고 배치하는 레이아웃이다.
여기서 말하는 제약에는 어떤 것들이 있을까?
Relative Positioning, Margins, Centering positioning, Circular positioning, Visibility behavior, Dimension constraints,, Chains, Virtual Helpers objects, Optimizer등이 있다. 더 자세한건 나중에 다루기로 하고 어쨌든 뷰마다 제약을 걸 수 있고 UI를 조금 더 유연하게 구성할 수 있도록 도와준다. 또 뷰의 중첩 구조를 줄일 수 있다라고 알고 넘어가자.
❗️ 리뷰
쇼핑 장바구니 미션을 진행하면서 ConstraintLayout의 자식뷰의 width 혹은 height에 match_parent를 썼다. 그리고 다음과 같은 리뷰를 받았다.
ConstraintLayout의 자식뷰는 match_parent 대신 0dp 사용을 권장합니다.
0dp가 뭐지..?
❓ 0dp
dp에 대해서는 알고있다. 그런데 0dp? 그럼 크기가 없는 것이 아닌가? 하고 생각했다. 하지만 공식문서에서는 다음과 같이 이야기한다.
0dp == match_constraint 를 의미하며 해당 위젯이 차지할 수 있는 모든 면적을 차지하도록 한다.
즉, ConstraintLayout에서의 0dp는 뷰가 제약 조건에 따라 동적으로 확장 혹은 축소될 수 있음을 의미하는 것이다. 뷰의 크기를 0dp로 설정하면 뷰의 크기가 제약 조건에 따라 자동으로 조정되며, 부모 요소에 맞게 확장 또는 축소된다. 이를 통해 UI를 더 유연하게 구성할 수 있다.
ConstraintLayout 에서는 match_parent를 사용하는 대신 0dp 사용을 권장한다.
❓ Why
공식문서를 잘 읽어봤지만 match_parent보다 0dp의 사용을 권장하는 이유에 대해 비교하여 설명하는 것을 찾지 못했다. 레벨 2동안 ConstraintLayout을 사용하면서 무의식적으로 match_parent를 사용하고, 0dp로 고치기를 반복하며 왜 0dp를 권장하는지 알게 되었다.
보통 ConstraintLayout에 ListView 혹은 RecyclerView를 추가할 때 width를 match_parent로 두는 실수를 했다. 보통 ListView 혹은 RecyclerView의 너비에 대한 제약은 부모에 맞게 설정한다. 다음과 같이 말이다.
app:layout_constraintEnd_toEndOf = "parent"
app:layout_constraintStart_toStartOf = "parent"
결국 이 상황에서는 width를 match_parent로 주나 0dp로 주나 보이는 것에 큰 차이가 없다. 어차피 화면의 너비를 꽉 채워서 보여줄 것이니까.
다음 상황을 보자.
붉은색 박스로 표시한 텍스트뷰를 나는 오른쪽에 붙이고 싶다. 이 텍스트뷰의 xml은 다음과 같다.
<TextView
android:id="@+id/test"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_medium"
android:text="원"
android:textColor="@color/black"
android:textSize="@dimen/product_detail_item_medium_text_size"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider" />
다른 attribute는 보지않아도 되고 width와 layout_constraint* 만 보도록하자. 해당 뷰를 오른쪽 끝에 붙이고 싶어서 layout_constraintEnd_toEndOf를 parent로 설정했다. 그런데도 왼쪽에 붙어있는데 이러한 이유가 width를 match_parent로 했기 때문이다.
match_parent는 말 그대로 부모 뷰의 크기와 동일한 크기를 가지도록 뷰의 크기를 설정하는 것이기 때문에 제약과 상관없이 화면에 꽉 차게 되고 왼쪽에 붙은 것처럼 보이는 것이다. 그럼 width를 0dp로 수정하면 어떤 일이 일어날까?
<TextView
android:id="@+id/test"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_margin="@dimen/margin_medium"
android:text="원"
android:textColor="@color/black"
android:textSize="@dimen/product_detail_item_medium_text_size"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/divider" />
원하는대로 오른쪽에 붙은 것을 볼 수 있다. 서두에서 말했던 0dp == match_parent 가 전혀 아니라는 말이다. (그냥 아예 관계없는 말임)
앞서 말한 것처럼 0dp는 match_constraint를 의미한다. 이 말은 즉 제약에 맞추겠다는 말이고, 현재 텍스트뷰에 걸려있는 제약은 layout_constraintEnd_toEndOf="parent" 다. 따라서 해당 제약에 맞게 뷰의 위치가 정해지는 것이다. (layout_constraintTop_toBottomOf="@id/divider" 이기 때문에 divider라는 id를 가진 뷰의 Bottom에 Top이 붙는다.)
❗️ 정리
- ConstraintLayout에서는 0dp의 사용을 권장한다.
- 0dp와 match_parent는 절대 같은 결과를 보여주는 것이 아니며 0dp는 match_constraint를 의미한다.
- match_parent는 자식 뷰를 부모 뷰의 크기에 맞게 채우는 역할을 한다.
- 0dp를 사용함으로써 뷰의 위치나 크기를 제약 조건에 맞게 자동으로 조정되도록 할 수 있다.
- 0dp를 사용함으로써 뷰의 위치나 크기를 유연하게 설정할 수 있다.
참고