bugfix> android > 投稿

Kotlinを使用してAndroidでチャットアプリを作成しています。

私は recyclerview を使用していますアイテムには、自分のものか他人のものか、およびタイムグループの最初/最後/中間/一人かによって、8つのバックグラウンドのうち1つがあります。

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

...そして、下の2番目の図のように描画の問題が発生し始めます。

一部の角がまったく丸くない、テキストが背景をオーバーフローするなど。

バックグラウンドリソースは典型的に見えます(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>

どうして?問題はどこにありますか?

回答 2 件
  • 問題は、最初に設定したテキストに従ってドロアブルが調整されることです。テキストサイズが固定されていないため、すべてのアイテムに同じドロアブルを設定しないでください。

    すべてのリソースのバックグラウンドを取得することは非効率的ではありません。あなたの最初の方法が遅れることはないと確信しています。非効率について確認するには、コードの実行にかかる時間を確認し、少なくとも100項目をスクロールしてメモリを確認し、動作を確認します。問題が発生した場合はお知らせください。

  • 複数のitemViewタイプを使用しないのはなぜですか?この方法で、DrawableはViewHolderごとに1回ロードされ、スクロール時に適切に再利用されます。単純化するために、ドロアブルリソースIDを 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 から削除します  完全に。

あなたの答え