Constraint Layout 의 Flow

chapter5 프로젝트를 생성하자.

계산기를 만들 때, 많은 reference 들이 Table Layout 을 사용한다.

 

그러나 이 챕터에서는 Constraint Layout 의 Flow 를 사용할 것이다.

인터넷에 검색할 때, 안드로이드 Flow 를 키워드로 하면

데이터 흐름을 관리하는 Flow 에 대한 설명을 찾을 수도 있다.

 

우리는 Constraint Layout의 Flow 에 대해서 이야기하고 있는 것이다.

안드로이드 공식문서에서 Flow 를 찾아보자.

키워드는 다음과 같다.

Virtual Layout

similar to chain

배치를 할 때, constraint_referenced_ids 를 사용


1) VirtualLayout 의 장점

hierarchy 가 flat 하다.

뷰 구조를 flat 하게 만들 수 있다.

 

뷰의 레이아웃 계층 구조가 flat 할 수록

렌더링하는 속도 ( UI를 그리는 속도 ) 가 빨라진다.

 

Linear Layout 을 사용하면, UI 를 편하게 그릴 수 있다.

Constraint Layout 처럼 Constraint 관계를 따로 가지지 않아서

특히 쌓는 구조를 그릴 때 편리하다.

 

단, flat 한 계층구조 권장사항에 위배되기 때문에

유혹을 떨치고 Constraint Layout 으로 돌아오게 된다.

 

그런데 Constraint Layout 의 Flow 를 사용하면

Linear Layout 의 장점을 가져갈 수 있다.


2) Three Buttons 배치

Flow 가 무엇인지 알아보기 위해

3개의 버튼을 만들어보자.

 

버튼 스타일 통일을 위해

res 우클릭 > New > Android Resource File 에서

styles.xml 를 만들자.

 

styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="numKeyPad">
        <item name="android:textSize">40sp</item>
        <item name="android:layout_width">wrap_content</item>
        <item name="android:layout_height">wrap_content</item>
    </style>
</resources>

 

 

activity_main.xml

    <Button
        android:id="@+id/button1"
        style="@style/numKeyPad"
        android:text="1" />

    <Button
        android:id="@+id/button2"
        style="@style/numKeyPad"
        android:text="2" />

    <Button
        android:id="@+id/button3"
        style="@style/numKeyPad"
        android:text="3" />

Button 배치할 때, Expand 또는 Chain Mode 를 사용할 수 있다.


2-1) [배치] Expand

Organize > Expand Horizontally

 

결과

각 Button 내부에 constraint 관련 코드가 몇 줄 추가된다.

 


2-2) [배치] Chains

요소들 드래그 > Chains > Create Horizontal Chain

 

결과

각 Button 내부에 constraint 관련 코드가 몇 줄 추가된다.


horizontal 로만 constraint 를 지정해주었기 때문에,

vertical constraint 도 지정을 해주어야 한다.

 

이런식으로 쌓게되는 구조임에도 불구하고

복잡한 UI 를 constraint 으로 만들 수 밖에 없다.

 

이때 유용하게 사용할 수 있는 것이 Flow 이다.

내부 값을 최대한 사용하기 위해서

layout_width 와 layout_height 를 0dp 로 지정했다.

 

3) Flow 코드 추가 ( constraint_referenced_ids )

<!-- Flow -->
<androidx.constraintlayout.helper.widget.Flow
    android:layout_width="0dp"
    android:layout_height="0dp"
    app:layout_constraintStart_toStartOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintBottom_toBottomOf="parent"
    app:layout_constraintTop_toTopOf="parent"
    app:constraint_referenced_ids="button1, button2, button3"
    />
    
    <Button
    android:id="@+id/button1"
    style="@style/numKeyPad"
    android:text="1" />

 

결과

Button 에서 constraint 를 따로 지정해주지 않았는데

Flow 코드 추가를 하였더니, Button 들이 배치가 되었고

각 Button 내부에 constraint 관련 코드가 없다.

 

코드가 간결해진 것이다.

 

Flow 를 사용하므로 constraint 를 추가하지 않아도 된다는 것을 알려주는

missing constraints 무시하는 코드를 추가하자.

tools:ignore="MissingConstraints"


✽ styles.xml 수정

버튼이 떨어져있지 않고 붙어있었으면 좋겠으므로

styles.xml 에서 layout_width 와 layout_height 를

각각 parent 에서 0dp 로 변경하자.

 

styles.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
    <style name="numKeyPad">
        <item name="android:textSize">40sp</item>
        <item name="android:layout_width">0dp</item>
        <item name="android:layout_height">0dp</item>
    </style>
</resources>

✽456 / 789 추가 ( flow_maxElementsWrap, flow_wrapMode )

이전에 버튼 1, 버튼 2, 버튼 3을 복사/붙이기 해서

456/789 버튼들을 만들어보자.

 

이렇게 버튼을 만들게 되면 우려스러운 점이

계속 가로로 쌓을 수 있으려면

Flow 가 줄(행) 별로 있어야 한다.

 

Flow 는 순서에 따라 배치가 된다.

app:constraint_referenced_ids="button1, button3, button2"

이렇다면 버튼 순서는 1, 3, 2

 

이전에 버튼 1, 2, 3 만 flow 에 있었다면

버튼 4, 5, 6, 7, 8, 9 모두 flow 에 추가해준다.

 

app:constraint_referenced_ids="button1, button2, button3, button4, button5, button6, button7, button8, button9"

그럼 한 행에 최대 몇 개의 UI 요소를 배치할 지

지정하지 않았기 때문에 아래와 같이 보인다.

 

 

이제 한 행에 배치할 뷰의 최대 개수인 flow_maxElementsWrap와

이를 적용하기 위해 반드시 지정해야하는 flow_wrapMode 를 지정하자.

flow_wrapMode 의 기본값은 none 이다.

app:flow_maxElementsWrap="3"

app:flow_wrapMode="aligned"

 


[flow_wrapMode ] aligned 와 chain, 그리고 chain2

aligned 와 chain 의 차이를 알기 위해서

1번 버튼을 지워보았다.


✽ gap

우리는 aligned 를 옵션으로 할 것이다.

가로로 뷰들 사이 간격을 주기 위해서 horizontal gap 을 지정하자.

app:flow_horizontalGap="8dp"

 

 

계산기 키패드 높이를 줄여보자.

app:layout_constraintHeight_percent="0.7"

 

 

또 계산기 키패드를 아래로 내리자.

app:layout_constraintVertical_bias="1"

 

 

숫자 키패드 색을 변경해보자.

styles.xml

<item name="backgroundTint">@color/teal_200</item>

 

backgroundTint 를 이용하면, 원래 있던 버튼의 색깔만 변경할 수 있다.

<item name="backgroundColor" 값이 아닌

backgroundTint 를 지정해주었다.

 


✽ 나머지 버튼 추가

0버튼과 =버튼도 추가해보자.

=버튼 가로길이가 0버튼의 가로길이의 2배가 되도록 아래와 같은 옵션 추가.

layout_constraintHorizontal_weight
    <Button
		    ...
		    android:text="0"
        app:layout_constraintHorizontal_weight="1"/>

    <Button
        android:id="@+id/buttonEqual"
        style="@style/numKeyPad"
        android:text="="
        app:layout_constraintHorizontal_weight="2"
        tools:ignore="MissingConstraints" />

이제 clear버튼과 +버튼, -버튼을 추가해야한다.

 

위 버튼은 3버튼, 6버튼, 9버튼 오른쪽에 추가하고 싶으므로,

행 최고 요소 개수를 4로 변경하자.

app:flow_maxElementsWrap="4"

app:constraint_referenced_ids= "button1, button2, button3, buttonClear, 
button4, button5, button6, buttonPlus, 
button7, button8, button9, buttonMinus
,button0, buttonEqual"

 

 

행 내 최대 4개 요소로 변경되었으므로

weight 를 1:3 으로 변경하자.

    <Button
		    ...
		    android:text="0"
        app:layout_constraintHorizontal_weight="1"/>

    <Button
        android:id="@+id/buttonEqual"
        style="@style/numKeyPad"
        android:text="="
        app:layout_constraintHorizontal_weight="3"
        tools:ignore="MissingConstraints" />

 

 

마지막으로 연산자 버튼들만 색을 변경해보자.

styles.xml

<style name="operatorKeypad" parent="numKeyPad">
    <item name="backgroundTint">@color/teal_700</item>
</style>


3) 전체 코드

activity_main.xml

<?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="match_parent"
    tools:context=".MainActivity">

    <!-- Flow -->
    <androidx.constraintlayout.helper.widget.Flow
        android:id="@+id/keyPadFlow"
        android:layout_width="0dp"
        android:layout_height="0dp"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintHeight_percent="0.7"
        app:layout_constraintVertical_bias="1"
        app:flow_maxElementsWrap="4"
        app:flow_wrapMode="chain"
        android:padding="8dp"
        app:flow_horizontalGap="8dp"
        app:constraint_referenced_ids="button1, button2, button3, buttonClear, button4, button5, button6, buttonPlus, button7, button8, button9, buttonMinus
        ,button0, buttonEqual"
        />


    <Button
        android:id="@+id/button1"
        style="@style/numKeyPad"
        android:text="1"
        tools:ignore="MissingConstraints"/>

    <Button
        android:id="@+id/button2"
        style="@style/numKeyPad"
        android:text="2"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button3"
        style="@style/numKeyPad"
        android:text="3"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button4"
        style="@style/numKeyPad"
        android:text="4"
        tools:ignore="MissingConstraints"/>

    <Button
        android:id="@+id/button5"
        style="@style/numKeyPad"
        android:text="5"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button6"
        style="@style/numKeyPad"
        android:text="6"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button7"
        style="@style/numKeyPad"
        android:text="7"
        tools:ignore="MissingConstraints"/>

    <Button
        android:id="@+id/button8"
        style="@style/numKeyPad"
        android:text="8"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button9"
        style="@style/numKeyPad"
        android:text="9"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/button0"
        style="@style/numKeyPad"
        android:text="0"
        app:layout_constraintHorizontal_weight="1"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/buttonEqual"
        style="@style/operatorKeypad"
        android:text="="
        app:layout_constraintHorizontal_weight="3"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/buttonClear"
        style="@style/operatorKeypad"
        android:text="C"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/buttonPlus"
        style="@style/operatorKeypad"
        android:text="+"
        tools:ignore="MissingConstraints" />

    <Button
        android:id="@+id/buttonMinus"
        style="@style/operatorKeypad"
        android:text="-"
        tools:ignore="MissingConstraints" />

</androidx.constraintlayout.widget.ConstraintLayout>

+ Recent posts