DataBinding – Two-way(양방향) Databinding with Custom View

2021. 3. 4. 21:06모바일/Android_Kotlin

DataBinding – Two-way(양방향) Databinding with Custom View

CustomView가 아닌 일반적인 방법

android:text="@={viewModel.mContent}

CustomView

  • CustomView에 양방향 데이터 바인딩을 적용하려면 꽤 복잡하다.
  1. customview에 적절한 변수값 선언하기
        <my.timer.custom.KeyboardView
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:textAlignment="center"
            android:textSize="20sp"
            app:content="@={dashboardViewModel.content}"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintBottom_toTopOf="@+id/ll_button"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent" />
  1. CustomView 클래스에 Databinding 연결하기
constructor(
        context: Context,
        attrs: AttributeSet?,
        defStyleAttr: Int
    ) : super(context, attrs, defStyleAttr) {
        initView()
    }

    /**
     * init View Here
     */
    private fun initView() {
        //*study*
        //아래 주석은 데이타 바인딩 사용 안할 때
//        val rootView = (context
//            .getSystemService(Context.LAYOUT_INFLATER_SERVICE) as LayoutInflater)
//            .inflate(R.layout.keyboard, this, true)

        val inflater = LayoutInflater.from(context)
        mBinding = DataBindingUtil.inflate(inflater,R.layout.keyboard,this,
            true)
        mBinding.view = this
  1. BindingAdapter 구현하기

@BindingAdapter("content")

  • @BindingAdapter("contentAttrChanged")

  • @BindingAdapter listener 에 들어갈 이름은 위에서 만든 메서드에 사용되었던 @BindingAdapter 의 이름에 AttrChanged 를 붙인 이름

  • 내부에서는 TextWatcher 를 새로 생성하고, EditText 에 설정하는 작업을 한다. 그리고 TextWatcher 의 afterTextChanged 옵션에서 listener.onChange 를 호출해준다. 이렇게 되면, EditText 의 afterTextChanged, 즉 텍스트가 변경 완료되었을 때 자동으로ViewModel 에 설정될 것이다.

@InverseBindingAdapter(attribute = "content",event = "contentAttrChanged")

object KeyboardViewReverseBinding  {

    //*study*
    //BindingAdapter는 데이터가 변경되었을 때 수행하고 싶은 작업을 작성
    @BindingAdapter("content")
    @JvmStatic
    fun setKeyboardViewContent(view: KeyboardView, content: String?) {
        val old = view.password_field.text.toString()
        if (old != content) {
            view.password_field.setText(content)
        }
    }
    @JvmStatic
    @BindingAdapter("contentAttrChanged")
    fun setKeyboardViewInverseBindingListener(view: KeyboardView, listener: InverseBindingListener?) {
        val watcher = object : TextWatcher {
            override fun beforeTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
            }
            override fun onTextChanged(charSequence: CharSequence, i: Int, i1: Int, i2: Int) {
            }
            override fun afterTextChanged(editable: Editable) {
                listener?.onChange()
            }
        }
        view.password_field.addTextChangedListener(watcher)
    }
    //*study*
    //InverseBindingAdpater 메서드는 역으로 레이아웃의 사용자 정의 속성값이 변경되었을 때 뷰 모델 등과 같은
    //레이아웃 변수에 변경 사항을 전달하여 양방향 바인딩이 구현될 수 있게 한다.
    @InverseBindingAdapter(attribute = "content",event = "contentAttrChanged")
    @JvmStatic
    fun getContent(view: KeyboardView): String {
        return view.password_field.text.toString()
    }
}

참고

https://pyxispub.uzuki.live/?p=917#XML_Code

https://medium.com/@douglas.iacovelli/custom-two-way-databinding-made-easy-f8b17a4507d2