요소들을 묶는 방법 : Chain

주효은·2024년 5월 16일
1

내가 이번에 맡은 뷰의 모습이다.

목표: 덤벨, 타이머, 불꽃의 이미지가 한 라인에 똑같은 위치에 동일 간격을 두고 있게 하자!

그냥 margin으로 주면 안돼?

chain을 알기 전에 나는 "그러면 그냥 Constraint Layout에서 서로의 start랑 end를 연결해서 같은 값의 margin을 주면 안되나?"라고 생각했다

만약 카드뷰 내부에서 dumbell을 start에서 41dp, 그리고 각각의 요소들 사이는 55dp의 간격을 두고 화면을 구성해봤다고 가정해보자.

이렇게 보면 내가 지금 만들고 있는 화면에서는 모든 요소들이 잘 배치되어 있어보인다.

그런데 만약, 가로 화면이 더 큰 기기에서 내가 만든 화면을 본다면?

화면이 가로로 길어졌지만, 내가 cardview의 start에서 margin 41dp를 주고 각각의 요소 사이에 margin 55dp 주었기 때문에 그에 따라 요소들이 자리를 잡을 것이다.

그러면 위의 그림과 같이 모든 이미지들이 왼쪽으로 치우친 형태를 보인다.

그러면 화면의 비율이 달라질때마다 동적으로 크기를 알아서 계산해서 같은 비율만큼 이미지들이 있기를 원한다면..?

Chains란?

ConstraintLayout의 특성들 중 하나이다.

Chain 설정하면 각 위젯들이 하나의 덩어리가 되어 유연하게 배치시킬 수 있다.

chain style

chain들을 엮을 때 여러가지 스타일이 있다.

수평으로 묶고 싶을 때는

app:layout_constraintHorizontal_chainStyle="위에 있는 chain style 적기"

수직으로 묶고 싶을 때는

app:layout_constraintVertical_chainStyle="위에 있는 chain style 적기"

이 중에서, 오늘은 모두 같은 비율로 묶어주는 Spread Chain을 알아보자

chain을 묶는 방법 1

옆의 그림처럼 A,C를 양 끝에 붙여주고

A의 End(끝)를 B의 Start(시작)와, B의 Start(시작)를 A의 End(끝)와 엮어주는 방식이다.

진짜 말 그대로 사슬처럼 엮어주는 것!

그 뒤에 한 쪽 (A라면 End에, B라면 Start에 주면 된다)에 띄우고 싶은 간격을 적어준다.

Bold체 : 각 요소들을 chain으로 묶는 과정

Italic체 : chain의 양 끝을 parent로 연결하는 과정

로 표시했는데.. 안보이네요 그냥 주석을 봐주세요!!

 <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:paddingTop="21dp"
            android:paddingBottom="28dp">

            <TextView
                android:id="@+id/tv_exercise_body_part_explain"
                style="@style/Typography.PlanFit.body01"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="8dp"
                android:text="등,가슴,어깨,하체,이두,유산소"
                android:textColor="@color/gray02"
                app:layout_constraintStart_toEndOf="@id/tv_exercise_body_part"
                app:layout_constraintTop_toTopOf="parent" />

            <ImageView

_                **android:id="@+id/iv_dumbell" //chain의 head 부분**_
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                **android:layout_marginStart="41dp" //카드뷰(parent)로부터 41dp (끝 연결)**
                android:layout_marginTop="23dp"
                android:src="@drawable/ic_dumbbell_40"
                **app:layout_constraintHorizontal_chainStyle="spread" //체인 스타일 정의**
                app:layout_constraintStart_toStartOf="parent"
               *** app:layout_constraintEnd_toStartOf="@id/iv_set" // 뒤의 타이머와 연결***
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />

            <ImageView
                android:id="@+id/iv_set"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="23dp"
                **android:layout_marginStart="55dp" //앞의 타이머와의 간격 55dp**
                ***app:layout_constraintStart_toEndOf="@id/iv_dumbell" //앞의 덤벨과 연결***
                android:src="@drawable/ic_set_40"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain"
                tools:layout_editor_absoluteX="118dp"
                ***app:layout_constraintEnd_toStartOf="@id/fire" //뒤의 타이머와 연결***
                />

            <ImageView
                android:id="@+id/fire"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="23dp"
                **android:layout_marginEnd="43dp"//카드뷰(parent)로부터 43dp (끝연결)**
                android:src="@drawable/ic_fire_40"
                app:layout_constraintEnd_toEndOf="parent"
                android:layout_marginStart="55dp"
                ***app:layout_constraintStart_toEndOf="@id/iv_set"***
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />
        </androidx.constraintlayout.widget.ConstraintLayout>

    </androidx.cardview.widget.CardView>

chain을 묶는 방법 2

원하는 요소들을 shift 누른 채로 모두 클릭 후 마우스 우클릭을 하면 Chains가 나옴

Horizontal/Vertical 중에 원하는 것을 선택하면 됨

이렇게 되면 알아서 비율이 맞춰진다.

            <ImageView
                android:id="@+id/iv_dumbell"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="41dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_dumbbell_40"
                app:layout_constraintEnd_toStartOf="@+id/iv_set"
                app:layout_constraintHorizontal_bias="0.5"
                app:layout_constraintHorizontal_chainStyle="spread"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />

            <ImageView
                android:id="@+id/iv_set"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:layout_marginStart="55dp"
                android:src="@drawable/ic_set_40"
                app:layout_constraintEnd_toStartOf="@+id/fire"
                app:layout_constraintHorizontal_bias="0.5"
                app:layout_constraintStart_toEndOf="@+id/iv_dumbell"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />

            <ImageView
                android:id="@+id/fire"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginTop="20dp"
                android:layout_marginStart="55dp"
                android:layout_marginEnd="43dp"
                android:src="@drawable/ic_fire_40"
                app:layout_constraintStart_toEndOf="@+id/iv_set"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="0.5" />

이렇게 만든 경우에는, 위의 방법과는 다르게

   app:layout_constraintHorizontal_bias="0.5"

부분이 자동으로 생기게 되는데

수평 방향 Start/End 사이드 제약 시, 양 사이드 간의 위치 비율을 나타낸다.

뷰의 왼쪽(Start) 사이드 제약 위치 0이 기준.
뷰의 오른쪽(End) 사이드 제약 위치 1이 기준.
가운데 위치는 0.5가 기준 (기본)

위의 경우에서는 chain style이 spread이기 때문에, bias를 움직여도 변화가 없다.

그러면 chain style이 bias에 따라 달라지는 packed를 쓴다면?

            <ImageView
                android:id="@+id/iv_dumbell"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="41dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_dumbbell_40"
                app:layout_constraintEnd_toStartOf="@+id/iv_set"
                app:layout_constraintHorizontal_bias="0" //0으로 설정
                app:layout_constraintHorizontal_chainStyle="packed" //chain style 변경
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />

            <ImageView
                android:id="@+id/iv_set"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="55dp"
                android:layout_marginTop="20dp"
                android:src="@drawable/ic_set_40"
                app:layout_constraintEnd_toStartOf="@+id/fire"
                app:layout_constraintHorizontal_bias="0.5"
                app:layout_constraintStart_toEndOf="@+id/iv_dumbell"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />

            <ImageView
                android:id="@+id/fire"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_marginStart="55dp"
                android:layout_marginTop="20dp"
                android:layout_marginEnd="43dp"
                android:src="@drawable/ic_fire_40"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintHorizontal_bias="1"
                app:layout_constraintStart_toEndOf="@+id/iv_set"
                app:layout_constraintTop_toBottomOf="@+id/tv_exercise_body_part_explain" />

bias를 0으로 설정했으니, 왼쪽 start부분에 치우쳐야한다! 그런지 확인해보면??

이렇게 된다 ㅎㅎ

0개의 댓글