Как я могу использовать свой пользовательский вид изображения с привязкой данных в Android? - PullRequest
4 голосов
/ 05 февраля 2020

Итак, я проверил эту кодовую метку от Google для создания пользовательского представления RatioImageView в Android. Он просто расширяет 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

, т.е. для строки, в которой target.loadImage(...) записано в OnBindViewHolder ( )

Кроме того, если я не использую DataBinding для макета root, он работает нормально.

Поэтому вопрос в том, что нужно добавить в RatioImageView ? Чтобы заставить его работать с DataBinding, учитывая, что здесь мне не требуется, чтобы макет XML был связан с классом View.

Вот onCreateViewHolder()

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

И ниже класс ViewHolder:

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

Также здесь есть репозиторий на случай, если мой код чего-то не хватает здесь: https://github.com/prafullmishra/CustomImageView

Ответы [ 3 ]

1 голос
/ 22 февраля 2020

Я нашел проблему в примере кода, который вы разместили на Github. На самом деле, этот вопрос было непросто решить из размещенного вами фрагмента, но ошибка правильно указывала на проблему с именем класса.

Ваш XML относится к классу com.example.bindingcustomimageview.CustomImage.RatioImageView. Не зная ничего, RatioView выглядит так, как будто это внутренний c внутренний класс CustomImage в пакете com.example.bindingcustomimageview.

Но это не так. Это был класс RatioImageView в пакете com.example.bindingcustomimageview.CustomImage (где "CustomImage" - это имя пакета в верхнем регистре). Вы можете быстро исправить это, перетащив RatioImageView в тот же пакет, что и ваш MainActivity, и все будет работать правильно.

Чтобы избежать путаницы, подобной этой, в будущем, не называйте ваши пакеты именами в верхнем регистре.

0 голосов
/ 16 февраля 2020

Любое пользовательское представление должно иметь как минимум 3 различных типа реализаций конструктора, которые необходимо предоставить, прежде чем вы сможете получить к нему удобный доступ:

  1. Один с одним параметром: RatioImageView(context)
  2. Один с двумя параметрами: RatioImageView(context, attrs)
  3. Один с тремя параметрами: RatioImageView(context, attrs, defStyleAttr)

В то время как RatioImageView имеет только один с тремя параметрами, который реализует ImageView(context, attrs, defStyleAttr). Вот почему вы получаете эту ошибку. Вам также нужно определить 2 других конструктора.

0 голосов
/ 11 февраля 2020

С каким атрибутом в xml вы пытаетесь связать данные? Может быть, вы хотите привязать изображение к атрибуту android:src? В этом случае:

  1. Добавьте <variable name="image" type="Drawable"/> внутри <data> тегов
  2. Включите связывающее выражение для атрибута src, например 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)
        }
    }
    
...