수학적 접근

[Android/Kotlin] XML Data Binding 본문

개발/Android

[Android/Kotlin] XML Data Binding

평등수렴 2022. 3. 3. 20:51
반응형

Android에서 레이아웃을 만들 때, 똑같은 모양을 반복해서 그려야 할 때가 있습니다.

 

그럴 때는 보통 반복되는 부분을 따로 레이아웃을 만든 다음(child),

 

원 파일(parent)에 이 child를 <include>를 사용하여 가져오는 방식으로 코드의 재사용성을 높여주는 것이 바람직합니다.

 

 

그런데 똑같은 모양이 반복되기는 하지만, child 안에 들어가는 세부적인 내용이 조금씩 다르다면 어떻게 할까요?

 

예를 들어 텍스트 글자 하나만, 배경색 하나만 다르다면?

 

이 정도 차이 때문에 일일이 따로 만들기에는 꽤 시간낭비라고 느껴질 수 있습니다.

 

 

그래서 이렇게 차이나는 부분만을 변수로 만들어서, parent 단에서 값을 지정해주는 방법이 있습니다.

 

아래에서는 이 방법을 사용하는 예제를 볼 것입니다.

 

 

이 예제에서 구현할 모양은 아래와 같습니다.

 

하나의 child 요소를 만들어서 총 세 번 재사용을 하며,

 

달라지는 요소는

 

1. 과일 이름

2. 과일 이미지

3. 과일 색

4. 배경색

 

네 가지입니다.

 

 

이를 구현하기 위해서

 

1. 텍스트 (String)

2. 그림 (Drawable)

3. 색 (ColorInt)

 

세 가지 종류의 데이터를 전달해야 합니다.

 

참고로 이외 다른 종류의 데이터도, 이 예제에서 사용하는 방법과 비슷한 방법을 사용한다면 전달할 수 있습니다.

(이를테면, 직접 정의한 클래스도 사용할 수 있습니다)

 

 

그럼 전체 코드를 보면서 설명하겠습니다.

 

 

---- 들어가기 전에 ----

 

* 이 방법을 적용하기 위해서는 아래 설정이 필요합니다.

 

app 수준의 build.gradle 파일에서 아래 내용을 추가합니다.

android {
	. . .
    
    dataBinding {
    	enabled = true
    }
}

작성 후 Sync 를 해줍니다.

 

 

 

* 여기에서 사용된 과일 svg 파일입니다.

fruit_svg_files.zip
0.01MB

----------------

 

 

element_fruit.xml (child)

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>
        <variable name="backgroundColor" type="Integer" />
        <variable name="fruitIcon" type="android.graphics.drawable.Drawable" />
        <variable name="fruitColor" type="Integer" />
        <variable name="fruitName" type="java.lang.String" />
    </data>

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="60dp"
        android:padding="8dp"
        android:background="@{backgroundColor}"
        android:orientation="horizontal">

        <ImageView
            android:id="@+id/icon"
            android:layout_width="35dp"
            android:layout_height="35dp"
            android:layout_marginEnd="8dp"
            android:layout_gravity="center"
            app:colorFilter="@{fruitColor}"
            android:src="@{fruitIcon}" />

        <TextView
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_gravity="center"
            android:layout_weight="1"
            android:textSize="16sp"
            android:textColor="@color/black"
            android:text="@{fruitName}"/>

    </LinearLayout>

</layout>

child 요소에 대한 xml 코드입니다.

 

 

전체를 <layout /> 요소로 감싸주었고, <data /> 요소를 이용하여 필요한 변수 4개 및

 

각각의 데이터 타입을 정의해주었습니다.

 

 

평소 구현할 때와 한 가지 다른 점이 있는데,

 

평소에는 svg 파일의 색상을 변경할 때 app:tint 라는 필드를 사용합니다.

 

그런데 이렇게 데이터 전달을 할 때에는 app:colorFilter 라는 것을 사용하여야

 

정수 값을 이용하여 간단하게 색상 값을 전달할 수 있습니다.

 

app:tint 가 받을 수 있는 데이터 타입이 정확하게 어떤 것인지 파악이 되지 않는데, 정수나 문자열을 받지 못하는 것으로 보아

 

app:tint 필드를 그대로 사용하려면 복잡한 과정을 거쳐야 할 것으로 보입니다.

 

 

이를 이용하여 parent를 구현하면 아래와 같습니다.

 

activity_main.xml (parent)

<?xml version="1.0" encoding="utf-8"?>
<layout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:bind="http://schemas.android.com/apk/res-auto">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical">

        <include
            layout="@layout/element_fruit"
            bind:backgroundColor="@{@color/apple_background}"
            bind:fruitIcon="@{@drawable/ic_apple}"
            bind:fruitColor="@{@color/apple}"
            bind:fruitName="@{@string/apple}"
            />

        <include
            layout="@layout/element_fruit"
            bind:backgroundColor="@{@color/banana_background}"
            bind:fruitIcon="@{@drawable/ic_banana}"
            bind:fruitColor="@{@color/banana}"
            bind:fruitName="@{@string/banana}"
            />

        <include
            layout="@layout/element_fruit"
            bind:backgroundColor="@{@color/grape_background}"
            bind:fruitIcon="@{@drawable/ic_grape}"
            bind:fruitColor="@{@color/grape}"
            bind:fruitName="@{@string/grape}"
            />

    </LinearLayout>
</layout>

 

변수에 대입될 값들은

 

values/strings.xml

values/colors.xml

 

에 각각 정의하여 적용하였습니다.

 

 

그리고 값을 전달할 때 기존에 ConstraintLayout 등에서 볼 수 있는 app 이란 xml namespace와 동일한 것을

 

bind라는 namespace를 굳이 다시 정의해서 사용하는데,

 

저는 기존의 app과 제가 직접 정의한 변수를 구분지어주는 것을 선호하기 때문에 이런 짓을 합니다.

 

원래는

app:backgroundColor
app:fruitIcon

...

으로 작성해도 무방합니다.

 

 

이렇게 두 파일을 작성해주면 앞에서 보여드렸던 모양을 구현할 수 있습니다.

 

 

이상 구현한 내용을 github에 올려두었습니다.

 

GitHub - dmseo1/dm-tistory-android-include-databinding

Contribute to dmseo1/dm-tistory-android-include-databinding development by creating an account on GitHub.

github.com

 

만약 values/strings.xml, values/colors.xml 파일이 필요하시다면 git을 확인해보시기 바랍니다.

 

 

 

참고

 

1. 만약 @string/apple 과 같이 미리 정의된 값을 사용하지 않고 직접 "사과" 와 같이 대입하고자 하는 경우,

@string/apple"사과"로 대체하는 것은 성공하지만, @color/apple 을 "#ff0000"로 대체하는 것은 실패합니다.

약간의 추가 작업이 필요한데, 이에 대한 글을 작성할 예정입니다.

 

2. 이렇게 정의한 4개의 변수들은 코틀린 코드에서도 활용할 수 있습니다.

직접 정의한 변수를 코틀린 코드에서 활용하는 방법에 대한 글을 작성할 예정입니다.

 

 

 

 

 

 

 

 

 

 

 

반응형

'개발 > Android' 카테고리의 다른 글

[Android/Kotlin] Custom Dialog 만들기 (NEW)  (1) 2022.03.03
[Android/Kotlin] Custom Dialog 만들기  (3) 2020.02.07
Comments