So I checked this codelab by Google for creating a custom view RatioImageView
. It simply extends the ImageView and overrides the OnMeasure()
method according to device's viewport's aspect ratio. The code for the same is:
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())
}
}
Then I am using this in ListItem view as:
<?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>
Then in the Adapter, I am using DataBinding
to update the views with content as follows:
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)
}
}
}
During building, it shows the following error:
Cannot access class 'RatioImageView'. Check your module classpath for missing or conflicting dependencies
i.e. for the line in which target.loadImage(...)
is written in OnBindViewHolder()
Also, if I don't use DataBinding for the root layout, then it works fine.
So the question is what needs to be added to RatioImageView
? To make it work with DataBinding, considering that here I don't require an XML layout to be associated with the View class.
Here's the onCreateViewHolder()
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): HomeItemHolder {
return HomeItemHolder(ItemPhotoListLayoutBinding.inflate(LayoutInflater.from(parent.context)))
}
And below is the ViewHolder
class:
inner class HomeItemHolder (val binding: ItemPhotoListLayoutBinding):
RecyclerView.ViewHolder(binding.root) {
}
Also here is the repo in case my code is missing something over here: https://github.com/prafullmishra/CustomImageView
I found the problem in the code sample you posted on Github. Actually, this one was tricky to solve from the snippet you posted, but the error was correctly indicating a problem with the class name.
Your XML referred to the class
com.example.bindingcustomimageview.CustomImage.RatioImageView
. Without knowing anything more, RatioView
looks like it's a public inner class of CustomImage
in the package com.example.bindingcustomimageview
.
But it wasn't. It was the class RatioImageView
in the package com.example.bindingcustomimageview.CustomImage
(where "CustomImage" is an uppercase package name). You can fix it quickly by dragging RatioImageView
into the same package as your MainActivity, and everything will work correctly.
To avoid confusions like this in the future, don't name your packages with upper case names.