Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Kotlin custom attribute databinding

I am trying to set custom attribute using the Android DataBinding Library in my Kotlin project like this:

Layout

<ImageView
    android:id="@+id/imgView”
    android:layout_width="40dp"
    android:layout_height="40dp"
    android:layout_gravity="center"
    android:adjustViewBounds="true"
    app:imageUrl="@{segment.url}"/>
                            

Code

class Utils {
    companion object {
        @BindingAdapter("bind:imageUrl")
        @JvmStatic
        fun loadImage(view: ImageView, url:String) 
        {Picasso.with(view.context).load(url).error(R.drawable.error).into(view)}
    }
}

    

    

The runtime error I get is:

A BindingAdapter in in <package.Utils.Companion> is not static and requires an object to use, retrieved from the DataBindingComponent. If you don't use an inflation method taking a DataBindingComponent, use DataBindingUtil.setDefaultComponent or make all BindingAdapter methods static.

Any pointers to solve it?

This happens only for custom attributes. The rest of the databindings work fine

like image 302
Akshata Avatar asked Oct 17 '16 11:10

Akshata


People also ask

Can we use ViewBinding and Data Binding together?

You can't use them togheter in the same layout. ViewBinding is a subset of what DataBinding can do and should be used if you want to replace libraries like ButterKnife , KotterKnife or KAE (Kotlin Android Extensions) but don't want to invest in databinding refactoring.

How do you make a BindingAdapter?

To create a custom binding adapter, you need to create an extension function of the view that will use the adapter. Then, you add the @BindingAdapter annotation. You have to indicate the name of the view attribute that will execute this adapter as a parameter in the annotation.


2 Answers

Just keep function on the top level, no class or companion object needed, it will work since top-level functions in Kotlin translated to static member functions of Class named as FileNameKt unless overridden by @file:JvmName annotation

@BindingAdapter("imageUrl")
fun loadImage(view: ImageView, url:String) { ... }

One more option is to annotate Extension Function as @BindingAdapter, it will work since in bytecode signature will exactly match signature expected by DataBindings(generated method will still accept an object of the extended class as the first argument), the function should remain top level as well

@BindingAdapter("imageUrl")
fun ImageView.loadImage(url:String) { ... }

One more option is to combine BindingAdapter with the extension property like following:

@set:BindingAdapter("visible")
var View.visible
    get() = visibility == VISIBLE
    set(value) {
        visibility = if (value) VISIBLE else GONE
    }
like image 128
Stepango Avatar answered Nov 04 '22 01:11

Stepango


Try switching the order of the annotations. It seems to fix the issue:

class Utils {
    companion object {
        @JvmStatic @BindingAdapter("imageUrl")
        fun loadImage(view: ImageView, url:String) { ... } 
    }
} 

The problem is that the databindng compiler uses getCompanion().loadImage otherwise*.
You can verify this in the generated com.your.package.databinding.*Binding class

* After playing around a bit I noticed that this has nothing to do with the order of the annotations, but seems to be random. It seems to change whenever I hit "rebuild". It might be a bug in kapt or in the kotlin compiler

like image 42
Lovis Avatar answered Nov 04 '22 01:11

Lovis