Alexander Suraphel
Alexander Suraphel

Reputation: 10613

error: <identifier> expecte when setting up binding adapters for two way data binding

I am trying to setup two way binding for TextInputEditText with Float variable.

Here is the entire content of my DataBindingAdapters class.

object DataBindingAdapters  {
    @BindingAdapter("android:text")
    @JvmStatic
    fun setText(view: TextInputEditText, value: Float) {
        if(value != view.text.toString().toFloat()) {
            view.setText(value.toString())
        }
    }


    @InverseBindingAdapter(attribute = "android:text")
    fun getText(view: TextInputEditText): Float  {

        return view.text.toString().toFloat()
    }

}

But I am getting:

error: <identifier> expected
            float callbackArg_0 = mBindingComponent.null.getText(inputFieldSize);

What am i missing?

Upvotes: 5

Views: 791

Answers (3)

Torben
Torben

Reputation: 6827

I had the same issue and was able to solve it by making the inverse binding adapter static like in the official documentation:

    @InverseBindingAdapter(attribute = "android:text")
    @JvmStatic fun getText(view: TextInputEditText): Float  {

        return view.text.toString().toFloat()
    }

Note the @JvmStatic right before fun getText(.... This is the only change from the code in your question.

BTW: Mohru's answer also mentions this in the edit-section, but at least for me it was not obvious enough to be found in the first place ;)

Upvotes: 2

William Hu
William Hu

Reputation: 16149

I have the same issue,

the fix is:

class MyView {
  companion object {
     @BindingAdapter("android:text")
    @JvmStatic
    fun setText(view: TextInputEditText, value: Float) {
        if(value != view.text.toString().toFloat()) {
            view.setText(value.toString())
        }
    }


    @InverseBindingAdapter(attribute = "android:text")
    fun getText(view: TextInputEditText): Float  {

        return view.text.toString().toFloat()
    }
  }
}

Besides this, you may/have to add textAttrChanged event also. If it needs then it will tell you xxx: textAttrChanged not found...... error. Then add below method just side the companion object body

@BindingAdapter(value = ["android:textAttrChanged"], requireAll = false)
        @JvmStatic fun setValue(view: MyView, textAttrChanged: InverseBindingListener) {
            val newValue = object : TextWatcher {
                override fun beforeTextChanged(s: CharSequence, start: Int, count: Int, after: Int) {}
                override fun onTextChanged(s: CharSequence, start: Int, before: Int, count: Int) {}
                override fun afterTextChanged(s: Editable) {
                    textAttrChanged.onChange()
                }
            }
            view.binding.editText.addTextChangedListener(newValue)
        }

Besides this, you might get warnings in above code.

Then you can use:

object XXXAdapter {
   //Put the binding methods here.
}

to silence the warnings.

Upvotes: 0

Mohru
Mohru

Reputation: 743

You miss one more binding adapter, as mentioned in the InverseBindingAdapter documentation:

@BindingAdapter(value = [ "android:textAttrChanged"], requireAll = false)
fun setTextWatcher( view: TextInputEditText, textAttrChanged: InverseBindingListener?) {
    val newValue =  object: TextWatcher {
        override fun afterTextChanged(s: Editable?) = Unit

        override fun beforeTextChanged(s: CharSequence?, start: Int, count: Int, after: Int) = Unit

        override fun onTextChanged( s:CharSequence,  start:Int,  before:Int,  count:Int) {
                textAttrChanged?.onChange()
        }
    }

    val  oldValue = ListenerUtil.trackListener(view, newValue, R.id.textWatcher)
    if (oldValue != null) {
        view.removeTextChangedListener(oldValue)
    }
    view.addTextChangedListener(newValue)
}

When you create @InverseBindingAdapter(attribute = "android:text"), an event android:textAttrChanged is created, and you have to add a binding adapter for it.

Calling textAttrChanged?.onChange() will trigger the InverseBindingAdapter that you created.


EDIT:
Also, you are using Kotlin so you don't need to put your binding adapters in an object. A separate file will suffice. Just remove wrapping object DataBindingAdapters {..} and @JvmStatic and you should be fine.

Upvotes: 3

Related Questions