为什么 Android RecyclerView 将其行的 match_parent 变成 wrap_content?

Why Android RecyclerView turns match_parent into wrap_content for its rows?

我的屏幕上有回收站视图。它应该显示一个简单的项目列表和一个页脚。但是,我看到了一些不同的东西。 Recyclerview 缩小了行,尽管我明确提到我希望它们填满宽度。这是我的期待,也是我的所见。

这是我的片段中的内容:

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
        }

这是我的适配器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()
        }
    }
}

这是row_about_item.xml文件

<?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>

这是row_about_footer.xml文件

<?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>

最后 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>

在您的 onCreateViewHolder() 方法中,更改您的 inflate() 调用以指定父视图:

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

当您不指定父级时,指定视图的 LayoutParams(所有 layout_ 属性)将被忽略。