简体   繁体   中英

Allow selecting text from different textview items at once in android recyclerview

There are many Textviews in a Recyclerview, selecting the text content of each one with long click all right but selection pins don't allow to select test from next TextView, it allow selecting only inside current TextView. How to allow overflow text selection that contains different TextView items?

For exampe as seen on the picture below, TextView one is green, TextView two is purple, when selection start on green one the selection doesn't countinue to beyond the green one. So both green and purple TextViews should be selectable sometime.

(After that I should get the selected text and its TextViews.)

在此处输入图像描述

Solution

  • Since Selection can be done for 1 TextView not a multiple of them at the same time, I think to do what you want we kinda wanna mock that behavior using BackgroundColorSpan
  • Note that we will be able to show thee highlight like a selection but won't be able to show selection handlers

Preview

用户界面预览

Code

Activity.kt

import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.EditText
import android.widget.TextView
import androidx.recyclerview.widget.DividerItemDecoration
import androidx.recyclerview.widget.LinearLayoutManager
import com.maproductions.mohamedalaa.stackoverflow_solutions.R
import com.maproductions.mohamedalaa.stackoverflow_solutions.view.rv_adapter.RVAdapterRVTextViewsSeveralTextSelectionActivity
import kotlinx.android.synthetic.main.activity_r_v_text_views_several_text_selection.*
import mohamedalaa.mautils.core_android.extensions.toast

class RVTextViewsSeveralTextSelectionActivity : AppCompatActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_r_v_text_views_several_text_selection)

        val adapter = RVAdapterRVTextViewsSeveralTextSelectionActivity()
        recyclerView.addItemDecoration(DividerItemDecoration(this, DividerItemDecoration.VERTICAL))
        recyclerView.layoutManager = LinearLayoutManager(this)
        recyclerView.adapter = adapter

        toastAllMaterialButton.setOnClickListener {
            toast(adapter.getAllSelectedTexts().joinToString("\n"))
        }
    }
}

activity.xml

<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="match_parent"
    android:orientation="vertical"
    tools:context=".view.RVTextViewsSeveralTextSelectionActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/recyclerView"

        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/toastAllMaterialButton"

        android:layout_width="match_parent"
        android:layout_height="wrap_content"

        android:layout_margin="16dp"

        android:text="Toast all selected texts as several lines"
        android:textAllCaps="false"
        android:textSize="20sp"/>

</LinearLayout>

RecyclerViewAdapter.kt

import android.annotation.SuppressLint
import android.graphics.Color
import android.text.style.BackgroundColorSpan
import android.view.View
import android.view.ViewGroup
import android.widget.TextView
import androidx.core.text.buildSpannedString
import androidx.recyclerview.widget.RecyclerView
import com.maproductions.mohamedalaa.stackoverflow_solutions.R
import mohamedalaa.mautils.core_android.extensions.inflateLayout
import mohamedalaa.mautils.core_android.extensions.plusAssign

@SuppressLint("SetTextI18n")
class RVAdapterRVTextViewsSeveralTextSelectionActivity
    : RecyclerView.Adapter<RVAdapterRVTextViewsSeveralTextSelectionActivity.ViewHolder>() {

    // Set this color to whichever color you want.
    private val highlightingTextColor = Color.parseColor("#CBDCFF")

    private val selectedIndices = mutableListOf<Int>()

    override fun getItemCount(): Int = 20

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): ViewHolder {
        return ViewHolder(
            parent.context.inflateLayout(R.layout.rv_item_activity_r_v_text_views_several_text_selection)
        )
    }

    override fun onBindViewHolder(holder: ViewHolder, position: Int) {
        holder.textView.text = buildSpannedString {
            append(getTextAtIndex(position))

            if (position in selectedIndices) {
                this += BackgroundColorSpan(highlightingTextColor)
            }
        }

        holder.itemView.setOnLongClickListener {
            if (position in selectedIndices) {
                selectedIndices -= position
            }else {
                selectedIndices += position
            }

            notifyItemChanged(position)

            true
        }
    }

    fun getAllSelectedTexts(): List<String> {
        return selectedIndices.map { getTextAtIndex(it) }
    }

    // getTextAtIndex is instead of myData.get(position).name
    private fun getTextAtIndex(index: Int): String {
        return "I am a text with index -> $index"
    }

    class ViewHolder(itemView: View) : RecyclerView.ViewHolder(itemView) {
        val textView: TextView = itemView.findViewById(R.id.textView)
    }

}

recycler_view_item.xml

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    xmlns:tools="http://schemas.android.com/tools"

    android:id="@+id/textView"

    android:padding="16dp"

    android:textSize="24sp"
    android:textColor="@android:color/black"

    tools:text="I am a text with index -> 0" />

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM