RecyclerView 项目大小在滚动时发生变化

Posted

技术标签:

【中文标题】RecyclerView 项目大小在滚动时发生变化【英文标题】:RecyclerView Item Size changing while scrolling 【发布时间】:2021-01-03 05:02:10 【问题描述】:

当第一次recyclerView 加载时,它会正确显示。但滚动后,布局项大小发生了变化。

这是我的item_layout

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_
    android:layout_
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:background="@drawable/item_border"
    android:layout_margin="@dimen/item_margin_2">
    <ImageView
        android:id="@+id/imageProduct"
        android:layout_
        android:layout_
        android:contentDescription="@string/app_name"
        android:scaleType="centerInside"
        android:src="@drawable/ic_launcher_foreground"
        app:layout_constraintTop_toTopOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
         />

    <TextView
        android:id="@+id/textProductTitle"
        android:layout_
        android:layout_
        android:textColor="@android:color/black"
        android:textSize="@dimen/title_textSize"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/imageProduct"
        tools:text="TubeLight" />

    <TextView
        android:id="@+id/textProductDetailSort"
        android:layout_
        android:layout_
        android:layout_marginTop="4dp"
        android:textColor="@android:color/black"
        android:textSize="@dimen/detail_textSize"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textProductTitle"
        tools:text="warranty: 100 days" />


    <LinearLayout
        android:id="@+id/linerCartItem"
        android:layout_
        android:layout_
        android:orientation="horizontal"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/textProductDetailSort">

        <ImageButton
            android:id="@+id/buttonRemove"
            android:layout_
            android:layout_
            android:background="@drawable/item_border_small"
            android:src="@drawable/ic_outline_remove_24"/>

        <TextView
            android:id="@+id/textNumberItem"
            android:layout_
            android:layout_
            android:background="@color/colorPrimaryLight"
            android:textSize="@dimen/detail_small_textSize"
            android:padding="@dimen/item_padding"
            android:textColor="@color/black"
            android:layout_margin="@dimen/item_margin_3"
            android:text="0"/>

        <ImageButton
            android:id="@+id/buttonAdd"
            android:layout_
            android:layout_
            android:background="@drawable/item_border_small"
            android:src="@drawable/ic_baseline_add_24"/>

    </LinearLayout>


    <TextView
        android:id="@+id/textViewProductPrice"
        android:layout_
        android:layout_
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toBottomOf="@id/linerCartItem"
        app:layout_constraintBottom_toBottomOf="parent"
        android:layout_marginStart="@dimen/item_margin"
        android:text="@string/title_price"/>


</androidx.constraintlayout.widget.ConstraintLayout>

这是adapter class

class ProductListAdapter(context: Context, private val cellClickListener: HomeFragment) : RecyclerView.Adapter<RecyclerView.ViewHolder>() 

    interface CellClickListener 
        fun onCellClickListener(productModel: ProductModel)
        fun onNextClicked()
        fun onPrevClicked()
        fun onAddClicked(productId: String): Int
        fun onRemoveClicked(productId: String): Int
    

    val FOOTER_TYPE : Int = 1
    val HEADER_TYPE : Int = 2
    var context : Context = context

    private var listOfProducts = listOf<ProductModel>()


    override fun getItemViewType(position: Int): Int 

         if (position ==  listOfProducts.size) 

             return FOOTER_TYPE
         
//         else if(position == 0)
//            return HEADER_TYPE
//         
        return 0

    
    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder 

        if (viewType == FOOTER_TYPE)
            return ProductListViewHolderFooter(
                LayoutInflater.from(parent.context).inflate(
                    R.layout.item_product_footer,
                    parent, false
                )
            )
        else if(viewType == HEADER_TYPE)
            return ProductListViewHolderHeader(
                LayoutInflater.from(parent.context).inflate(
                    R.layout.item_product_header,
                    parent, false
                )
            )
        
        else
            return ProductListViewHolder(
                context,
                LayoutInflater.from(parent.context).inflate(
                    R.layout.item_product,
                    parent,
                    false
                )
            )
        

    

    override fun getItemCount(): Int = listOfProducts.size + 1

    override fun onBindViewHolder(viewHolder: RecyclerView.ViewHolder, position: Int) 
        try 
            if (viewHolder is ProductListViewHolder) 
                val vh: ProductListViewHolder = viewHolder as ProductListViewHolder
                vh.bindView(listOfProducts[position], cellClickListener)

             else if (viewHolder is ProductListViewHolderFooter) 
                val vh: ProductListViewHolderFooter = viewHolder as ProductListViewHolderFooter
                vh.bindViewFooter(listOfProducts[position], cellClickListener)
            
         catch (e: Exception) 
            e.printStackTrace()
        


    

    fun setProductList(listOfProducts: List<ProductModel>) 

        this.listOfProducts = listOfProducts
        notifyDataSetChanged()
    

这是holder

class ProductListViewHolder(context: Context,itemView: View) : RecyclerView.ViewHolder(itemView)

   
    var sharedPreferences: SharedPreferences = context.getSharedPreferences(utils.PREFERENCE_FILE_NAME,
        Context.MODE_PRIVATE)
  

    fun bindView(productModel: ProductModel, cellClickListener: HomeFragment) 
        itemView.textProductTitle.text = productModel.productTitle
        itemView.textProductDetailSort.text = productModel.productDetailSort


        itemView.textViewProductPrice.text = context.getString(R.string.title_price) + ": " + productModel.price

       
        itemView.textNumberItem.text = cart

        Glide.with(itemView.context).load(productModel.productImageUrl!!).into(itemView.imageProduct)

         itemView.imageProduct.setOnClickListener
             cellClickListener.onCellClickListener(productModel)
         

         itemView.buttonRemove.setOnClickListener 
             val cart = cellClickListener.onRemoveClicked(productModel.productId)
             itemView.textNumberItem.text = cart.toString()
         

         itemView.buttonAdd.setOnClickListener 
             val cart = cellClickListener.onAddClicked(productModel.productId)
             itemView.textNumberItem.text = cart.toString()
         

    



【问题讨论】:

想要的是什么?在图像视图的顶部和底部有更多间隙的左侧项目还是右侧? 【参考方案1】:

由于无法控制ImageView 的高度而导致的问题,导致视图回收过程中的大小不同。要解决此问题,您需要对 imageProduct 属性进行一些更改。

首先,当您将imageProduct 的起点和终点绑定到父级的起点和终点时,您应该将视图宽度设置为0dp 以确保它填满整个空间。

其次,将adjustViewBounds属性设置为true。它会导致调整 ImageView 边界以保持其可绘制对象的纵横比。

第三,设置layout_constrainedHeight属性为true。它确保视图的高度保持受限,并让视图高度保持为wrap_content

<ImageView
    android:id="@+id/imageProduct"
    android:layout_                      // 1
    android:layout_
    android:contentDescription="@string/app_name"
    android:scaleType="centerInside"
    android:src="@drawable/ic_launcher_foreground"
    android:adjustViewBounds="true"                 // 2
    app:layout_constrainedHeight="true"             // 3
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent" />

此外,如果您希望始终以特定的纵横比显示图像,您可以通过将高度更改为0dp 来实现它,同时使用layout_constraintDimensionRatio 属性定义比率,如下所示:

<ImageView
    android:id="@+id/imageProduct"
    android:layout_                     
    android:layout_                     // setting the height constrainted
    android:contentDescription="@string/app_name"
    android:scaleType="centerInside"
    android:src="@drawable/ic_launcher_foreground"
    android:adjustViewBounds="true"      
    app:layout_constraintDimensionRatio="1:1"       // to show as a square  
    app:layout_constrainedHeight="true"             
    app:layout_constraintTop_toTopOf="parent"
    app:layout_constraintEnd_toEndOf="parent"
    app:layout_constraintStart_toStartOf="parent" />

【讨论】:

谢谢..你拯救了我的一天..布局管理得很好。【参考方案2】:

尝试调用 glide clear Glide.with(itemView.context).clear(itemView.imageProduct) 在顶部 Glide.with(itemView.context).load(productModel.productImageUrl!!).into(itemView.imageProduct)

【讨论】:

以上是关于RecyclerView 项目大小在滚动时发生变化的主要内容,如果未能解决你的问题,请参考以下文章

改变方向recyclerview卡大小变化

RecyclerView 中心项目比其他项目大,滚动时大小不一

当 Kotlin 中的数据发生变化时,如何在 RecyclerView 中重新绑定项目?

Recyclerview 在滚动期间更改项目

当外部 div 的大小发生变化时,可滚动的 div 会粘在底部

向下滚动时 RecyclerView 项目之间的间隙较大