Kotlin自定义属性数据绑定

76

我正在尝试在我的 Kotlin 项目中使用Android DataBinding Library来设置自定义属性,如下所示:

布局

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

代码

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)}
    }
}

    

    

我得到的运行时错误是:

<package.Utils.Companion> 中的 BindingAdapter 不是静态的,需要使用对象从 DataBindingComponent 检索。 如果您不使用使用 DataBindingComponent 的膨胀方法,请使用 DataBindingUtil.setDefaultComponent 或使所有 BindingAdapter 方法为静态。

有什么提示可以解决它吗?

这仅适用于自定义属性。 其余的数据绑定工作正常。

7个回答

124

只需将函数保持在顶层,无需使用类或伴生对象,这样做可以工作,因为Kotlin中的顶级函数被翻译为名为FileNameKt的类的静态成员函数,除非通过@file:JvmName注释进行重写。

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

还有一种选择是将扩展函数标记为@BindingAdapter,它可以正常工作,因为字节码签名将与DataBindings所期望的签名完全匹配(生成的方法仍将接受扩展类的对象作为第一个参数),该函数应该保持为顶级函数。

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

还有一种选项是将BindingAdapter与扩展属性相结合,如下所示:

@set:BindingAdapter("visible")
var View.visible
    get() = visibility == VISIBLE
    set(value) {
        visibility = if (value) VISIBLE else GONE
    }

2
这个答案仍然给我错误。Lovis的答案对我有用。 - omerjerk
关于Lambda表达式呢?我如何在Kotlin中的自定义BindingAdapter的xml布局中分配Lambda函数? - Владимир Широков
@ВладимирШироков 是的,你可以这样做,就像XML中的视图onClick一样工作,你只需要正确的SAM类/接口即可。 https://developer.android.com/reference/android/databinding/BindingAdapter.html - Stepango
@JvmStatic 的使用怎么样? - IgorGanapolsky
1
@IgorGanapolsky 所有顶级函数都是“静态”的,因此您不需要将其声明为“@JvmStatic”。 - Stepango

43

尝试交换注释的顺序。这似乎可以解决问题:

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

问题在于数据绑定编译器使用getCompanion().loadImage,否则*
您可以在生成的com.your.package.databinding.*Binding类中验证此内容。

* 经过一番尝试,我注意到这与注释的顺序无关,似乎是随机的。每当我点击“重新构建”时,它似乎都会改变。 这可能是kapt或kotlin编译器中的一个错误。


同样的问题,改变顺序也没有帮助。 - luca992
4
我已经发布了一份 Kotlin 的错误报告,请查看 https://youtrack.jetbrains.com/issue/KT-14417 - luca992
4
查找静态方法时,可以在伴生对象内提供@JvmStatic来解决问题。 - Dharmendra Jadon
为什么我们需要拥有伴生对象 - IgorGanapolsky
@IgorGanapolsky 没有人说你_必须_(看已接受的答案),但这就是问题的提问方式。 - Lovis
@Lovis 那么就不需要使用 @JvmStatic 了。 - IgorGanapolsky

14
< p >在@BindingAdapter("imageUrl")后面添加@JvmStatic解决了我的问题。

例如:

    @BindingAdapter("android:visibility")
    @JvmStatic
    fun setVisibility(view: View, visible: Boolean) {
        view.visibility = if (visible) View.VISIBLE else View.GONE
    }
}

这对我有用,非常感谢。 - KGeeks

3

或者使用扩展:

@BindingAdapter("imageUrl")
fun ImageView.setImageUrl(url: String?) {
    Picasso.with(context).load(url).into(this)
}

现在您可以在任何其他地方使用此函数


你需要使用@JvmStatic。 - IgorGanapolsky
3
只有当你需要从Java代码中调用它时,才需要使用"@JvmStatic"。这仅用于交互操作。https://kotlinlang.org/docs/reference/java-to-kotlin-interop.html - Yazazzello

3
这对我来说是可行的。请看下面的内容。 在gradle中添加:
apply plugin: 'kotlin-kapt'

dependencies {
 kapt "com.android.databinding:compiler:3.1.4"
}

在POJO中添加:
companion object {
  @BindingAdapter("image")
    @JvmStatic
         fun loadImage(view: ImageView, imageUrl: String) {

             //am Using Glide
Glide.with(view.context).setDefaultRequestOptions(RequestOptions().circleCrop())
                 .load(imageUrl).into(view)
         }
     }

在布局中:

添加绑定:image="@{movies.imageUrl}"

<ImageView 
  android:id="@+id/imageView"
  android:layout_width="100dp"
  android:layout_height="100dp"
  bind:image="@{movies.imageUrl}/>

为什么在@BindingAdapter周围有反引号? - IgorGanapolsky
@igorganapolsky 抱歉.. 打错字了。 - Dhanalakshmi
使用BindingAdapter时完全不需要伴生对象。 - IgorGanapolsky
我们应该提供伴生对象,因为我们使用了@JvmStatic。否则会出现错误。 - Dhanalakshmi
@JvmStatic 不是必需的。 - IgorGanapolsky
必须使用JVMStatic。如果没有@JvmStatic,会出现“使所有BindingAdapter方法静态”的错误,请查看。 - Dhanalakshmi

2
"最初的回答"对我很有帮助。
这个对我有用。
object ImageUtils {

        @JvmStatic @BindingAdapter("imageUrl")
        fun ImageView.loadImage(url: String?){
                GlideHelper.loadImage(url,this)
        }
}

in xml like this:

imageUrl="@{file.thumbnailLink}"

2

需要将函数(loadImage)放在对象(Singleton in java)中,而不是类中,并在@BindingAdapter("imageUrl")前设置@JvmStatic,像这样:

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

   @JvmStatic
   @BindingAdapter("bind:imageUrl")
   fun ImageView.loadImage( url:String) {
Picasso.with(this.context).load(url).error(R.drawable.error).into(this)
}

这需要伴生对象。 - IgorGanapolsky
1
'@JvmStatic' 处理它, '@JvmStatic' 就像伴生对象! - Fidan Bacaj

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接