如何将我的自定义 ImageView 与 DataBinding 一起使用?

How can I use my custom ImageView with DataBinding?

所以我检查了此 codelab by Google 以创建自定义视图 RatioImageView。它只是扩展 ImageView 并根据设备视口的宽高比覆盖 OnMeasure() 方法。相同的代码是:

class RatioImageView @JvmOverloads constructor(
    context: Context,
    attrs: AttributeSet? = null,
    defStyleAttr: Int = 0
): ImageView(context, attrs, defStyleAttr) {

    private val VP_HEIGHT = Resources.getSystem().displayMetrics.heightPixels
    private val VP_WIDTH = Resources.getSystem().displayMetrics.widthPixels
    private val HWR: Float = VP_HEIGHT.toFloat()/VP_WIDTH.toFloat() //height to width ratio


    override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec)
        setMeasuredDimension(MeasureSpec.getSize(widthMeasureSpec),(MeasureSpec.getSize(widthMeasureSpec)*HWR).toInt())
    }
}

然后我在 ListItem 视图中将其用作:

<?xml version="1.0" encoding="utf-8"?>
<layout xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">

    <data>

    </data>

    <androidx.constraintlayout.widget.ConstraintLayout
        android:orientation="vertical"
        android:layout_width="match_parent"
        android:layout_height="0dp">

        <com.example.myapp.RatioImageView
            android:id="@+id/target"
            android:layout_width="match_parent"
            android:layout_height="0dp"
            android:contentDescription="image holder"
            android:scaleType="centerCrop"
            android:background="#757575"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintDimensionRatio="9:16" />

    </androidx.constraintlayout.widget.ConstraintLayout>
</layout>

然后在适配器中,我使用 DataBinding 更新视图内容如下:

override fun onBindViewHolder(holder: HomeItemHolder, position: Int) {
        holder.binding.apply {

              //loadImage() is an extension function added to ImageView class
              target.loadImage(UiUtil.getCustomUrl(photos[position].urls.fullImage, height, width))
       
            root.setOnClickListener {
                handleClick(position)
            }
        }
}

构建过程中出现如下错误:

Cannot access class 'RatioImageView'. Check your module classpath for missing or conflicting dependencies

即对于在 OnBindViewHolder()

中写入 target.loadImage(...) 的行

此外,如果我不为根布局使用 DataBinding,那么它工作正常。

所以问题是RatioImageView需要添加什么?考虑到这里我不需要 XML 布局与视图 class.

相关联,以使其与 DataBinding 一起使用

这是onCreateViewHolder()

override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeItemHolder {
        return HomeItemHolder(ItemPhotoListLayoutBinding.inflate(LayoutInflater.from(parent.context)))
}

下面是 ViewHolder class:

inner class HomeItemHolder (val binding: ItemPhotoListLayoutBinding):
        RecyclerView.ViewHolder(binding.root) {
}

如果我的代码在这里遗漏了一些东西,这里还有回购协议:https://github.com/prafullmishra/CustomImageView

您要将数据绑定到 xml 中的哪个属性? 也许您想将图像绑定到 android:src 属性? 在那种情况下:

  1. <data> 标签内添加 <variable name="image" type="Drawable"/>
  2. src 属性添加一个 binding expression,例如 android:id="@{image}"
  3. 尝试以下操作:

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    holder.binding.apply {
    
        this.image = loadImage(UiUtil.getCustomUrl(photos[position].urls.fullImage, height, width))
    
        root.setOnClickListener {
            handleClick(position)
        }
    }
    

任何自定义视图都应该至少有 3 种不同的构造函数实现,您需要提供这些实现才能方便地访问它:

  1. 有 1 个参数的那个:RatioImageView(context)
  2. 有 2 个参数的那个:RatioImageView(context, attrs)
  3. 有 3 个参数的那个:RatioImageView(context, attrs, defStyleAttr)

RatioImageView只有3个参数实现了ImageView(context, attrs, defStyleAttr)。这就是你得到那个错误的原因。您还需要定义其他 2 个构造函数。

我在您发布在 Github 上的代码示例中发现了问题。实际上,根据您发布的代码片段很难解决这个问题,但错误正确地表明 class 名称存在问题。

您的 XML 提到了 class com.example.bindingcustomimageview.CustomImage.RatioImageView。在一无所知的情况下,RatioView 看起来像是包 com.example.bindingcustomimageviewCustomImage 的 public 内部 class。

但事实并非如此。它是包 com.example.bindingcustomimageview.CustomImage 中的 class RatioImageView(其中 "CustomImage" 是大写的包名称)。您可以通过将 RatioImageView 拖到与 MainActivity 相同的包中来快速修复它,一切都会正常工作。

为避免将来出现此类混淆,请不要使用大写名称来命名您的包。