정상에서 IT를 외치다

[Android, Databinding] 데이터 바인딩 이벤트 처리 본문

안드로이드

[Android, Databinding] 데이터 바인딩 이벤트 처리

Black-Jin 2018. 12. 17. 15:02
반응형


안녕하세요. 블랙진입니다.


데이터바인딩에 관한 3번째 포스팅으로 이벤트 처리 방법에 대해 알아보겠습니다. 데이터 바인딩에 관한 기본적인 내용 및 사용법은 데이터바인딩 사용기에서 확인하시면 됩니다.


1. 데이터바인딩 사용기

2.BindingAdapter 사용기




이벤트 처리


데이터 바인딩을 사용하여 뷰에 발송되는 이벤트를 처리하는 식으로 onClick 을 예로 들 수 있습니다. 이벤트 처리 방법은 두 가지가 있습니다.



1. 메서드 참조


이벤트를 핸들러 메서드에 직접 바인딩 하는 방법입니다. 



MainActivity.kt


class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

binding.activity = this@MainActivity

}

fun btnClick(view: View) {
Toast.makeText(this, "btnClick",Toast.LENGTH_SHORT).show()
}
}

메서드 참조 식일 경우 btnClick()에 View 파라미터를 꼭 지정해 주어야 합니다. 이벤트 처리 방법의 또 하나인 리스너 바인딩에서는 반대로 View 파라미터를 빼 주어야 정상적으로 동작합니다.



activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="activity"
type="com.tistory.black_jin0427.mydatabindingexample.MainActivity"/>
</data>

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">

<Button
android:text="activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{activity::btnClick}"/>

</LinearLayout>
</layout>

acitivity 라는 variable 을 <layout> 안에 선언해줍니다. 

button 의 onClick 에 actvitiy:btnClick 라고 입력해 주면 원하는 동작이 이뤄 집니다.




2. 리스너 바인딩


이벤트 발생 시 실행되는 바인딩 식입니다. 메서드 참조와 비슷하지만, 리스너 바인딩을 사용하면 임의의 데이터 바인딩 식을 실행할 수 있습니다. 이 기능은 Android Gradle Plugin for Gradle 버전 2,0 이상에서 사용할 수 있습니다.



-2.1 데이터가 없는 경우


MainActivity.kt

fun btnClick() {
Toast.makeText(this, "btnClick",Toast.LENGTH_SHORT).show()
}

메서드 참조와 달리 View 파라미터를 제거해 주어야 합니다.



activity_main.xml

<Button
android:text="activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> activity.btnClick()}"/>



-2.1 데이터가 있는 경우


SimaplModel.kt

class SampleModel(mTitle: String) {

val title = ObservableField<String>()

init {
title.set(mTitle)
}
}

데이터를 넣어주기 위해서는 model 을 생성해 주어야 합니다. title 변수 1개를 가지는 모델을 위와 같이 만들어 줍니다.



MainAcitivty.kt

val simpleModel = SampleModel("Android DataBinding")

binding.model = simpleModel

SimpleModel 의 mTitle 파라미터에 "Android DataBinding" 변수를 넣어 선언 후 바인딩 연결


fun btnClick(title: String) {
Toast.makeText(this, "title : $title",Toast.LENGTH_SHORT).show()
}

btnClick 에 title 변수를 추가해 줍니다.



activity_main.xml

<variable
name="model"
type="com.tistory.black_jin0427.mydatabindingexample.SampleModel"/>

<data></data> 사이에 SampleModel 을 추가해 줍니다.


<Button
android:text="activity"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> activity.btnClick(model.title)}"/>

activity.btnClick 변수에 model.title 을 설정해 주면 SampleModel 을 선언할 때 설정해 둔 "Android DataBinding" 을 출력하게 됩니다.




3. 심화과정


이벤트 처리와 바인딩 어댑터를 이용한 재밌는 예제를 작업해 보겠습니다.


Title 과 SubTitle 을 화면에 보여주고 버튼을 눌렀을 때 애니메이션 효과와 함께 visible 되거나 inVisible 이 되는 예제를 만들어 보겠습니다.




3-1. activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<layout>
<data>
<variable
name="model"
type="com.tistory.black_jin0427.mydatabindingexample.SampleModel"/>
</data>

<LinearLayout
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:orientation="vertical"
android:gravity="center"
android:layout_width="match_parent"
android:layout_height="match_parent">

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{model.visible}"
android:text="@{model.title}"
app:visibleAnimType="@{1}"
app:goneAnimType="@{2}"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{model.visible}"
android:text="@{model.subtitle}"
app:visibleAnimType="@{1}"
app:goneAnimType="@{2}"/>

<Button
android:text="model"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:onClick="@{() -> model.onButtonClick()}"
/>

</LinearLayout>
</layout>

model 1개를 데이터를 가지고 있는 xml 입니다.



3-2. MainActivity.kt

class MainActivity : AppCompatActivity() {

private lateinit var binding: ActivityMainBinding

override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)

binding = DataBindingUtil.setContentView(this, R.layout.activity_main)

val simpleModel = SampleModel("Android DataBinding","Simple Example", true)

binding.model = simpleModel

}

}

SampleModel 을 생성할 때 3가지 파라미터를 넣어줍니다. 각각 title, subtitle, visible 을 나타냅니다.



3-3.  SampleModel.kt

class SampleModel(
mTitle: String,
mSubtitle: String,
mVisible: Boolean
) {

val title = ObservableField<String>()
val subtitle = ObservableField<String>()
val visible = ObservableField<Boolean>()

init {

title.set(mTitle)
subtitle.set(mSubtitle)
visible.set(mVisible)

}

fun onButtonClick() {

val temp = visible.get() ?: true
visible.set(!temp)

}
}

모델은 3가지 변수과 1개의 이벤트 리스너를 가지고 있습니다.


onButtonClick 의 역활은 visible 값은 true 는 false 로 false 는 true 값으로 변경해 줍니다.



3-4. BindingAdapter.kt

@BindingAdapter(value = ["android:visibility", "visibleAnimType", "goneAnimType"], requireAll = true)
fun animationBindingMethod(view: View,
visible: Boolean,
visibleAnimType: Int,
goneAnimType: Int) {

if(visible) {

when(visibleAnimType) {

1 -> {
val anim = AlphaAnimation(0.0f, 1.0f).apply {
fillAfter = true
duration = 700
}

view.startAnimation(anim)
}
}

} else {

when(goneAnimType) {

2 -> {
val anim = AlphaAnimation(1.0f, 0.0f).apply {
fillAfter = true
duration = 700
}
view.startAnimation(anim)
}
}

}
}

BindingAdapter,kt 는 코틀린에서 사용하는 패키지 단위 함수입니다. 자바로 치면 싱글톤 객체나 함수를 만들 때 사용하는 방법입니다.

BindingAdapter() 에는 3가지 변수가 있고 requireAll = true 로 설정했습니다. 이를 통해 3가지 변수를 모두 xml 에 적어 주어야 컴파일 에러없이 작동됩니다. 


SampleModel 의 버튼 이벤트를 기억하시나요?

fun onButtonClick() {

val temp = visible.get() ?: true
visible.set(!temp)

}

버튼을 누르면 visible 변수의 Boolean 값이 변합니다. 이는 ObservableField 를 통해 xml 에 바인딩 되어있는 뷰에 변화를 줍니다.

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{model.visible}"
android:text="@{model.title}"
app:visibleAnimType="@{1}"
app:goneAnimType="@{2}"/>

<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:visibility="@{model.visible}"
android:text="@{model.subtitle}"
app:visibleAnimType="@{1}"
app:goneAnimType="@{2}"/>

xml 에서 2가지 TextView 에 android:visibility 에서 @{model.visible} 을 설정한게 보이시죠? 이 visible 값이 변하게 되면 BindingAdapter 에서 정의한 animationBindingMethod 가 실행됩니다. 이때 visibleAnimType 값과 goneAnimType 값은 각각 1과 2의 값이 설정되게 했습니다.


저는 visibleAnimType 과 goneAnimType 에 int 값을 주어 원하는 애니메이션 효과를 int 변수에 따라 동작할 수 있게 구성해보았습니다. 이런식으로 코드를 짜면 원하는 view 에 원하는 애니메이션 효과를 간편하게 정의할 수 있을 것 같습니다. 혹시 더 좋은 방법을 알고 있으시다면 댓글 및 공유 부탁드리겠습니다:)



<참고자료>


데이터 바인딩 문서


반응형
Comments