WISHY
WISHY

Reputation: 11999

Image gets replaced in recylerview while scrolling, android?

I am displaying a list of countries along with their flags in recylerview The 1st element does not have a image and uses a default image which is visible on launch of page But when I scroll and come back to it the image gets changed to some random from the list which should not happen

This is my adapter

class CountryAdapter(private val list: MutableList<Data?>?) :
RecyclerView.Adapter<CountryAdapter.ViewHolder>() {


override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
    val inflater = LayoutInflater.from(parent.context)
    val binding = ElementCountryBinding.inflate(inflater)
    return ViewHolder(binding)
}

override fun onBindViewHolder(holder: ViewHolder, position: Int) {
    val country: Data? = list?.get(position)
    if (country != null) {
        holder.bind(country)
    }
    holder.itemView.setOnClickListener {

    }
}

override fun getItemCount(): Int = list!!.size

inner class ViewHolder(val binding: ElementCountryBinding) :
    RecyclerView.ViewHolder(binding.root) {
    fun bind(country: Data) {
        binding.data = country
        if (country.filePath != null)
            Glide.with(binding.root.context)
            .load(country.filePath!!.trim()).into(binding.ivFlag)
    }
}
}

This is the xml layout

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


    <variable
        name="data"
        type="com.mountmeru.model.Data" />
</data>

<RelativeLayout
    android:layout_width="match_parent"
    android:layout_height="wrap_content">

    <androidx.cardview.widget.CardView
        android:id="@+id/main_cardview"
        android:layout_width="match_parent"
        android:layout_height="80dp"
        android:layout_marginBottom="5dp">

        <androidx.constraintlayout.widget.ConstraintLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent">

            <androidx.appcompat.widget.AppCompatImageView
                android:id="@+id/iv_flag"
                android:layout_width="100dp"
                android:layout_height="70dp"
                android:layout_marginStart="10dp"
                android:adjustViewBounds="true"
                android:src="@drawable/ic_share"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintLeft_toLeftOf="parent"
                app:layout_constraintTop_toTopOf="parent" />

            <androidx.appcompat.widget.AppCompatTextView
                android:id="@+id/tvCountryName"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_marginStart="10dp"
                android:text="@{data.countryName}"
                app:layout_constraintBottom_toBottomOf="@+id/iv_flag"
                app:layout_constraintLeft_toRightOf="@+id/iv_flag"
                app:layout_constraintTop_toTopOf="@+id/iv_flag" />
        </androidx.constraintlayout.widget.ConstraintLayout>


    </androidx.cardview.widget.CardView>
    < /RelativeLayout>
 </layout>

screenshot

Without scrolling

After scrolling.

Upvotes: 1

Views: 60

Answers (4)

WISHY
WISHY

Reputation: 11999

Having the function getItemViewType also solves the problem

override fun getItemViewType(position: Int): Int {
    return position
}

Upvotes: 0

sgtpotatoe
sgtpotatoe

Reputation: 430

So the default image you specified in your XML layout is the ic_share, this means that when onBindViewHolder is called, the image gets substituted by:

.load(country.filePath!!.trim()).into(binding.ivFlag)

However, you never specified that at position 0, the icon must be ic_share, so because of RecyclerView's nature, when you scroll downwards and upwards and the first itemHolder is created (again) it uses a recycled view from further down, and as you're not setting ic_share to iv_flag at position 0 it just uses the recycled view image.

If you just add a line of code like @ADM suggested in your bind method like this:

if(adapterPosition==0){
            binding.ivFlag.setImageResource(R.drawable.ic_share)
        }

With the ic_share, I think that should make it work

Upvotes: 1

SpiritCrusher
SpiritCrusher

Reputation: 21043

This is happening because you never set ic_share during bind View.

inner class ViewHolder(val binding: ElementCountryBinding) :
    RecyclerView.ViewHolder(binding.root) {
    fun bind(country: Data) {
        binding.data = country
        if(adapterPosition==0){
            binding.ivFlag.setImageResource(R.drawable.binding.ivFlag)
        }else {
            if (country.filePath != null)
                Glide.with(binding.root.context)
                    .load(country.filePath!!.trim()).into(binding.ivFlag)
        }
    }
}

Upvotes: 1

Blackbelt
Blackbelt

Reputation: 157457

That's normal due to the recycling mechanism of views in RV/LV. To avoid that set it to null

 if (country.filePath != null)
     Glide.with(binding.root.context)
       .load(country.filePath!!.trim()).into(binding.ivFlag)
else
     binding.ivFlag.setImageDrawable(null)

assuming ivFlag is an ImageView, or a default/placeholder if you have it

Upvotes: 1

Related Questions