ViewPager2 при установки offscreenPageLimit неверно отрисовываются элементы
Есть ViewPager2 в котором отображаются карточки. В качестве адаптера используется RecyclerView.Adapter. В адаптер поступает список моделей, в которых содержатся коды цветов для градиента фона карточек. Для ViewPager2 установлен offscreenPageLimit, чтобы были видны соседние карточки. Проблема заключается в том, что первые offscreenPageLimit + 1 карточкам устанавливается одинаковый цвет, хотя во ViewHolder приходят разные модели с разными цветами. Аналогичная ситуация при использовании RecyclerView вместо ViewPager2.
Демонстрация проблемы.
class MainActivity : AppCompatActivity() {
private val adapter: Adapter by lazy { Adapter() }
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val pager = findViewById<ViewPager2>(R.id.pager)
val pageMarginPx = resources.getDimension(R.dimen.dim8).toInt()
pager.offscreenPageLimit = 2
pager.setPageTransformer(MarginPageTransformer(pageMarginPx))
pager.adapter = adapter
val items = listOf(
Model("CARD 1","#000000", "#FFFFFF"),
Model("CARD 2","#FFF0EB", "#FFC1AF"),
Model("CARD 3","#BF559B", "#DE7ECB"),
Model("CARD 4","#FFEEC2", "#F8C33D")
)
adapter.setItems(items)
}
class Adapter : RecyclerView.Adapter<Adapter.ViewHolder>() {
private var items: List<Model> = emptyList()
fun setItems(items: List<Model>) {
this.items = items
notifyDataSetChanged()
}
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
val binding = ItemBinding.inflate(LayoutInflater.from(parent.context), parent, false)
return ViewHolder(binding)
}
override fun onBindViewHolder(holder: ViewHolder, position: Int) {
holder.bind(items[position])
}
override fun getItemCount(): Int = items.size
class ViewHolder(private val binding: ItemBinding) : RecyclerView.ViewHolder(binding.root) {
fun bind(item: Model) {
Log.d("TAG", "$item")
val background =
itemView.context.getDrawable(R.drawable.gradient) as GradientDrawable
val colorList = intArrayOf(Color.parseColor(item.start), Color.parseColor(item.end))
background.colors = colorList
binding.container.background = background
binding.txt.text = item.text
}
}
}
}
Ответы (1 шт):
Drawable могут использовать общий, так называемый ConstantState для переиспользования различных данных. Поэтому изменение одного drawable может затронуть сразу несколько.

Чтобы всё такие отвязаться от этого общего состояния, то нужно вызвать метод mutate() и дальше уже менять drawable.
После вызова mutate():

(background.mutate() as GradientDrawable).colors = colorList
https://android-developers.googleblog.com/2009/05/drawable-mutations.html