Reputation: 10613
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
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
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
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