위의 스킬 선택 화면에서, BindingAdapter를 통해서 한쪽 스킬을 클릭하면 반대 쪽 스킬은 흑백처리가 되도록 하고 싶었다.
동작 예시는 다음과 같다.
레벨 5때 선택 스킬 중 하나를 선택시, 반대편 스킬은 흑백화 되는 것을 확인할 수 있다. 해당 기능을 databinding 으로 구현하고 싶었고, 다음과 같이 구현하였다.
BindingAdapter
@BindingAdapter("isSkillSelected")
fun bindIsSkillSelected(view: ImageView, isSelected: Boolean?) {
val greymatrix = ColorMatrix().apply { setSaturation(0.0f) }
view.colorFilter = if (isSelected==false) {
ColorMatrixColorFilter(greymatrix)
} else {
null
}
}
layout(xml)
<?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:tools="http://schemas.android.com/tools"
tools:context=".Fragments.WritingFragment">
<data>
<variable
name="IsSelected"
type="boolean"/>
</data>
<ImageView
android:id="@+id/skill1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isSkillSelected="@{IsSelected}">
<ImageView
android:id="@+id/skill2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isSkillSelected="@{!IsSelected}">
.....
IsSelected 가 ! 로 서로 반대 값으로 배치되어 있는 것을 확인할 수 있다.
이로써 첫번째 스킬을 선택하면 두번째가 흑백이 되고, 두번째 스킬을 선택하면 첫번째가 흑백이 되도록 프래그먼트에서 다음과 같이 구현할 수 있다.
Fragment
binding.apply{
skill1.setOnClickListener { isSelected = true }
skill2.setOnClickListener { isSelected= false }
}
허나 문제가 있다. 위에서는 isSelected 변수를 layout xml 파일 안에서 <variable> 태그안에 boolean 타입으로 선언했는데,
데이터 바인딩에서 boolean 의 디폴트값은 무조건 false 기 때문에 첫 화면에 들어갔을 때 두번째 스킬이 선택된 상태로 시작하는 것이다. isSelected 의 디폴트값을 null 로 주면 해결이 되지만, 데이터 바인딩에서 저런 식으로 변수를 선언한 경우 불가능하다.
공식문서 에도 나와있듯이 databinding의 variable은 각 타입 별로 기본값은 null 이 아닌 다른 값을 가지고 있다.
예를 들어 boolean 은 false , Integer 은 0 이다.
첫 화면에 들어갔을 때 두번째 스킬이 선택된 상태로 시작하는 문제를 해결하고 싶었다.
문제 해결을 위해선 false, true 이지선다의 값이 아니라 null 까지 추가로 가질 수 있는 변수를 사용해야 했다.
그러기 위해 레이아웃안에서 variable 을 boolean 타입으로 선언하는 것이 아니라 ViewModel 안에서 MutableLiveData<Boolean?>타입의 변수를 하나 선언해 해당 변수를 사용하였다.
ViewModel
val isSelected = MutableLiveData<Boolean?>()
layout(xml)
<?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:tools="http://schemas.android.com/tools"
tools:context=".Fragments.WritingFragment">
<data>
<variable
name="viewModel"
type="com.app.unitewiki.viewmodels.WritingViewModel"/>
</data>
<ImageView
android:id="@+id/skill1"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isSkillSelected="@{viewModel.isSelected}">
<ImageView
android:id="@+id/skill2"
android:layout_width="match_parent"
android:layout_height="wrap_content"
app:isSkillSelected="@{!viewModel.isSelected}">
.....
Fragment
binding.apply{
skill1.setOnClickListener { viewmodel.isSelected.value = true }
skill2.setOnClickListener { viewmodel.isSelected.value= false }
}
위와 같이 하면 isSelected 의 디폴트값이 false 가 아닌 null 에서 시작하게 되고 첫 화면 진입시 아무 스킬도 선택되지 않은 화면에서 시작하게 할 수 있었다.