Binding Adapter, 즉 결합 어댑터는 적절한 프레임워크를 호출하여 XML에 사용자가 지정하는 값을 설정하는 작업을 담당한다.
사전정의된 예로는 android:text 와 같이 속성 값을 설정하는 것 또는 android:onclick 처럼 메서드를 지정하는 것과 같이 이벤트 리스너를 설정하는 작업이 있다.
<TextView
android:id="@+id/text_email"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="@{viewModel.userEmailLD}"
/>
사용자가 원하는 작업을 XML에서 지정하고 싶을 때가 있다. 이럴때는 @BindingAdpater 어노테이션을 사용하여
이처럼 BindingAdpater 어노테이션을 선언하고 이름을 넣어주게 되면 해당 이름으로 선언된 함수를 bind 하여 사용할 수 있게 된다.
다음은 클릭시 Navigator의 popBaskStack을 실행하는 예제이다.
@JvmStatic
@BindingAdapter("onBackPressed")
fun bindOnBackPressed(view: View, onBackPress: Boolean) {
if (onBackPress) {
view.setOnClickListener {
view.findNavController().popBackStack()
}
}
}
// In XML
<ImageView
android:id="@+id/leftarrow_iv"
...
app:onBackPressed="@{true}" />
매개변수 중 첫 번째 매개변수는 속성과 연결된 뷰의 유형을 결정한다.
두 번째 매개변수는 지정된 속성의 Binding Adapter에서 허용되는 유형을 결정한다.
개발자가 정의하는 Binding Adapter는 충돌이 발생하면 Android 프레임워크에서 제공하는 기본 어댑터보다 우선 적용된다.
// 기존에 프래그먼트마다 이렇게 달아줘야 했다.
binding.leftarrowIv.setOnClickListener {
findNavController().popBackStack()
}
두개이상의 속성을 받는 어댑터도 설정 가능하다.
@BindingAdapter("imageUrl", "error")
fun loadImage(view: ImageView, url: String, error: Drawable) {
Picasso.get().load(url).error(error).into(view)
}
<ImageView app:imageUrl="@{venue.imageUrl}" app:error="@{@drawable/venueError}" />
imageUrl이 문자열이 error가 Drawable이면 해당 어댑터가 호출된다.
속성 중 하나라도 설정될 때 설정하려면 requireAll 플래그를 사용한다.
@BindingAdapter(value = ["imageUrl", "placeholder"], requireAll = false)
fun setImageUrl(imageView: ImageView, url: String?, placeHolder: Drawable?) {
if (url == null) {
imageView.setImageDrawable(placeholder);
} else {
MyImageLoader.loadInto(imageView, url, placeholder);
}
}
requireAll의 값을 조정하여 모든 변수가 필요할지 정할 수 있다.
특정 유형간에 밪춤 변환을 제공한다.
예를들어 android:background 속성에 Drawable이 필요하지만 지정된 color 값이 Int형(Id값)으로 제공되는 상황일 때,
@BindingConversion 어노테이션을 활용하여 color Id 값을 ColorDrawable로 변활 할 수 있다.
@BindingConversion
fun convertColorToDrawable(color: Int) = ColorDrawable(color)
그러나 다음과 같이 동일한 표현식에 서로 다른 유형은 사용할 수 없다.
<View
android:background="@{isError ? @drawable/error : @color/white}"
android:layout_width="wrap_content"
android:layout_height="wrap_content"/>
객체변환, 이전값 사용하기
DataBinding 및 BindingAdapter를 사용하면 기존의 Fragment.kt 내에서 따로 뷰바인딩을 진행하고 UI를 수정하는 코드가 최적화되어 줄어들 것 이다.
참고 자료
https://developer.android.com/topic/libraries/data-binding/binding-adapters?hl=ko