Я создаю приложение для чата на Android с Kotlin.
Я использую recyclerview, и предметы имеют один из 8 фонов в зависимости от того, являются ли они вашими или чужими, и являются ли они первым / последним / средним / единственным во временной группе.
В recyclerview adapter есть обычный метод onBindViewHolder () с установкой этих фонов.
Когда код такой:
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val message = ...
...
textTV.background = ContextCompat.getDrawable(
context,
when {
msg.isLastInTimeGroup() && !msg.sentByMe -> R.drawable.chat_message_in_last_bg
msg.isFirstInTimeGroup() && !msg.sentByMe -> R.drawable.chat_message_in_first_bg
msg.isMiddleInTimeGroup() && !msg.sentByMe -> R.drawable.chat_message_in_middle_bg
msg.isLastInTimeGroup() && msg.sentByMe -> R.drawable.chat_message_out_last_bg
msg.isFirstInTimeGroup() && msg.sentByMe -> R.drawable.chat_message_out_first_bg
msg.isMiddleInTimeGroup() && msg.sentByMe -> R.drawable.chat_message_out_middle_bg
else -> if (msg.sentByMe) R.drawable.chat_message_out_bg else R.drawable.chat_message_in_bg
}
)
}
... он работает и выглядит как первое изображение ниже. Однако неэффективно использовать getDrawable () для каждого элемента. Итак, я извлек из функции чертежи следующим образом:
private val inFirstBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageInFirstBg)
private val inMiddleBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageInMiddleBg)
private val inLastBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageInLastBg)
private val inAloneBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageInBg)
private val outFirstBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageOutFirstBg)
private val outMiddleBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageOutMiddleBg)
private val outLastBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageOutLastBg)
private val outAloneBg: Drawable? = ContextCompat.getDrawable(ctx, R.drawable.chatMessageOutBg)
override fun onBindViewHolder(holder: RecyclerView.ViewHolder, position: Int) {
val message = ...
...
textTV.background = when {
msg.isLastInTimeGroup() && !msg.sentByMe -> inLastBg
msg.isFirstInTimeGroup() && !msg.sentByMe -> inFirstBg
msg.isMiddleInTimeGroup() && !msg.sentByMe -> inMiddleBg
msg.isLastInTimeGroup() && msg.sentByMe -> outLastBg
msg.isFirstInTimeGroup() && msg.sentByMe -> outFirstBg
msg.isMiddleInTimeGroup() && msg.sentByMe -> outMiddleBg
else -> if (msg.sentByMe) outAloneBg else inAloneBg
}
}
... и он начинает выполнять задачи рисования, как на втором рисунке ниже.
Некоторые углы вообще не закруглены, текст выходит за пределы фона и т. д.
Фоновые ресурсы выглядят типично (out_middle):
<shape xmlns:android = "http://schemas.android.com/apk/res/android"
android:shape = "rectangle">
<solid android:color = "@color/blue" />
<corners android:radius = "24dp"
android:topRightRadius = "4dp"
android:bottomRightRadius = "4dp"/>
</shape>
Почему? В чем проблема?
Проблема в том, что рисование настраивается в соответствии с текстом, который вы впервые установили, вы не должны устанавливать одно и то же рисование для каждого элемента, так как ваш размер текста не фиксирован.
Получение предыстории для каждого ресурса не является неэффективным. Я уверен, что ваш первый метод не задержится. Чтобы проверить неэффективность, проверьте время, которое требуется для выполнения фрагмента кода, а также проверьте память, прокрутив минимум 100 элементов, и посмотрите, как он себя ведет. Сообщите мне, если у вас возникнут проблемы.
Почему бы не использовать несколько типов itemView? Таким образом, drawable будет загружаться один раз для каждого ViewHolder и будет повторно использоваться соответствующим образом при прокрутке. Для простоты вы можете использовать свой идентификатор ресурса с возможностью рисования как itemViewType, попробуйте следующее:
override fun getItemViewType(position: Int): Int {
val msg = ... // retrieve msg for [position] from dataset
return when {
msg.isLastInTimeGroup() && !msg.sentByMe -> R.drawable.chat_message_in_last_bg
msg.isFirstInTimeGroup() && !msg.sentByMe -> R.drawable.chat_message_in_first_bg
msg.isMiddleInTimeGroup() && !msg.sentByMe -> R.drawable.chat_message_in_middle_bg
msg.isLastInTimeGroup() && msg.sentByMe -> R.drawable.chat_message_out_last_bg
msg.isFirstInTimeGroup() && msg.sentByMe -> R.drawable.chat_message_out_first_bg
msg.isMiddleInTimeGroup() && msg.sentByMe -> R.drawable.chat_message_out_middle_bg
else -> if (msg.sentByMe) R.drawable.chat_message_out_bg else R.drawable.chat_message_in_bg
}
}
Затем используйте это значение в onCreateViewHolder:
override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): RecyclerView.ViewHolder {
val holder = ... // your viewholder creation
holder.textTV.background = ContextCompat.getDrawable(context, viewType)
}
И полностью удалите код изменения фона из onBindViewHolder.