Search code examples
androidkotlindata-bindingtouch-event

BindingAdapter annotation is ignored in kotlin project. How can I change this code to work?


I'm working on an android project in kotlin and while trying to add an OnTouchListener to several buttons, I have run into a problem: it cannot be done from XML and I want to keep my backing code clean. After a bit of research, I found out that I could add the XML support by using a method with the @BindingAdapter annotation:

@BindingAdapter("onTouch")
fun Button.setXMLTouchListener(listener : View.OnTouchListener)
{
  this.setOnTouchListener(listener);
}

to this method:

class MainActivity : AppCompatActivity()
{
  ...
  ...

  fun goLeft(v : View, event : MotionEvent) : Boolean
  {
    // my code
  }
}

and in the XML:

<layout
  ...>
  <data>
    <variable name="main_activity" type="my.path.to.MainActivity" />
  </data>
  <androidx.constraintLayout.widget.ConstraintLayout
    ...>
    <Button
      ...
      app:onTouch="@{main_activity.goLeft}" />
    ...
  </androidx.constraintLayout.widget.ConstraintLayout>
</layout>

and enabled data binding in the build.gradle:

apply plugin: 'kotlin.kapt'

and

android {
  ...
  dataBinding {
    enabled = true
  }
}

This obviously didn't work, these are the solutions I have tried:

  • move the @Bindingadapter function from companion object to top level, so it's compiled static
  • try the app:onTouch contents as "main_activity.goLeft" (seen in a tutorial), "main_activity.goLeft()" (original try), and "main_activity::goLeft" (suggested by the compiler as the first is deprecated)
  • add logging to the click event to ensure the button receives events at all
  • change the value of the annotation to "app:onTouch" to be absolutely sure it's in the right xml namespace
  • move the touch listener function to a class that is non-activity and implements View.OnTouchListener (and renamed function accordingly)

After a bit of debugging, I also found out that the binding function doesn't run at all.

What could be the problem, and how can I solve it?


Solution

  • first write your data binding adapter like this.

    @BindingAdapter("app:onTouch")
    fun setXMLTouchListener(btn : Button , listener : View.OnTouchListener)
    {
        btn.setOnTouchListener(listener)
    }
    

    then chenge the goLeft() fun to it

    val goLeftListener = View.OnTouchListener { v, event ->
    
            Log.d("goLeftListener " , "it Worked !")
            return@goLeftListener true
        }
    

    and don't forget to set activity on your binding object in onCreate fun

    override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
    
    val binding: mainActivityBinding =
                DataBindingUtil.setContentView(this, R.layout.main_activity)
    
            binding.main_activity = this
    }
    

    and for the last step write onTouch attribute of Button in your xml layout like this

    <Button
    .
    .
    app:onTouch="@{main_activity.goLeftListener}"
    .
    />