I have a recycler view on my screen. It supposed to display a simple list of items and a footer. However, I see something different. Recyclerview has shrunk the rows although I clearly mentioned I want them to fill the width. This is the expectation as well as what I see.
This is what I have in my fragment:
override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
super.onViewCreated(view, savedInstanceState)
context?.let {
val adapter = AboutAdapter(it) { url ->
openWebPageByUtl(url)
}
binding.recyclerView.setHasFixedSize(true)
binding.recyclerView.adapter = adapter
}
This is my adapter class:
import android.content.Context
import android.graphics.drawable.Drawable
import android.view.LayoutInflater
import android.view.ViewGroup
import androidx.recyclerview.widget.RecyclerView
import com.myCompany.myApp.BuildConfig
import com.myCompany.myApp.databinding.RowAboutFooterBinding
import com.myCompany.myApp.databinding.RowAboutItemBinding
data class AboutItem(
val title: String,
val icon: Drawable?,
val webUrl: String
)
data class AboutFooter(
val version: String
)
class AboutAdapter(
val context: Context,
val callback: (url: String) -> Unit
) : RecyclerView.Adapter<RecyclerView.ViewHolder>() {
private val items: List<AboutItem> = getAboutItems(context)
companion object {
const val TYPE_HEADER = 0
const val TYPE_FOOTER = 1
const val TYPE_ITEM = 2
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
TYPE_ITEM -> ItemViewHolder(RowAboutItemBinding.inflate(inflater))
TYPE_FOOTER -> FooterViewHolder(RowAboutFooterBinding.inflate(inflater))
else -> throw IllegalArgumentException("Invalid view type")
}
}
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
when (holder) {
is ItemViewHolder -> {
holder.bindItem(items[position])
}
is FooterViewHolder -> {
val version = getFormattedVersion(context, BuildConfig.VERSION_NAME)
val item = AboutFooter(version)
holder.bindItem(item)
}
else -> throw IllegalArgumentException()
}
}
override fun getItemCount(): Int {
return items.size + 1 // Because we need to append the Footer
}
override fun getItemViewType(position: Int): Int {
if (position == 0 && items.isEmpty()) return TYPE_FOOTER
if (position == items.size) return TYPE_FOOTER
return TYPE_ITEM
}
inner class ItemViewHolder(val binding: RowAboutItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindItem(item: AboutItem) {
binding.item = item
binding.root.setOnClickListener { callback(item.webUrl) }
binding.executePendingBindings()
}
}
inner class FooterViewHolder(val binding: RowAboutFooterBinding) : RecyclerView.ViewHolder(binding.root) {
fun bindItem(item: AboutFooter) {
binding.item = item
binding.executePendingBindings()
}
}
}
This is row_about_item.xml file
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.myCompany.myApp.scenes.tabs.about.AboutItem" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/about_action_click">
<TextView
android:id="@+id/textView"
style="@style/about_textView"
android:drawableStart="@{item.icon}"
android:drawablePadding="30dp"
android:text="@{item.title}"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
tools:text="This is the title" />
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
This is row_about_footer.xml file
<?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"
xmlns:tools="http://schemas.android.com/tools">
<data>
<variable
name="item"
type="com.myCompany.myApp.scenes.tabs.about.AboutFooter" />
</data>
<androidx.constraintlayout.widget.ConstraintLayout style="@style/about_action_click">
<TextView
android:id="@+id/textView"
style="@style/about_textView_footer"
android:layout_marginStart="60dp"
android:text="@{item.version}"
tools:text="Version 1.0"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"/>
</androidx.constraintlayout.widget.ConstraintLayout>
</layout>
and finally the styles.xml.
<?xml version="1.0" encoding="utf-8"?>
<resources>
<style name="about_action_click">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">50dp</item>
<item name="android:background">?android:attr/selectableItemBackground</item>
<item name="android:gravity">center_vertical</item>
<item name="android:orientation">horizontal</item>
<item name="android:paddingEnd">16dp</item>
<item name="android:paddingStart">16dp</item>
</style>
<style name="about_textView" parent="textViewMedium">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">wrap_content</item>
<item name="android:textColor">@color/textColorDark</item>
<item name="android:textSize">14sp</item>
<item name="android:gravity">center_vertical</item>
</style>
<style name="about_textView_footer" parent="textView">
<item name="android:layout_width">match_parent</item>
<item name="android:layout_height">match_parent</item>
<item name="android:textColor">@color/color_4E4E57</item>
<item name="android:textSize">12sp</item>
<item name="android:gravity">center_vertical</item>
</style>
</resources>
In your onCreateViewHolder()
method, change your inflate()
calls to specify the parent view:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val inflater = LayoutInflater.from(parent.context)
return when (viewType) {
TYPE_ITEM -> ItemViewHolder(RowAboutItemBinding.inflate(inflater, parent, false))
TYPE_FOOTER -> FooterViewHolder(RowAboutFooterBinding.inflate(inflater, parent, false))
else -> throw IllegalArgumentException("Invalid view type")
}
}
When you do not specify the parent, the LayoutParams
of the specified view (all the layout_
attributes) are ignored.