[Java & Kotlin] Erstellen Sie eine RecyclerView mit mehreren Auswahlen

RecyclerView hat keine Funktion

Ich selbst bin seit ungefähr einem Jahr ein ListView-Anhänger, seit ich mit der Entwicklung von Android begonnen habe. Ich dachte: "Weil ** RecyclerView keine Funktion hat **, ** es ist eine verschlechterte Version von ListView? ** Es scheint schwierig und schwierig zu sein, ** physiologisch unmöglich **". ListView verfügt über Divider, FastScroll und ChoiceMode. Und doch hat der Nachfolger ** RecyclerView nichts **! Ich denke, es gab eine Zeit, in der alle das dachten.

In der Realität ist RecyclerView jedoch einfacher zu handhaben. Deshalb blüht es. Auch wenn ListView einfacher zu implementieren ist, werde ich es mit RecyclerView implementieren. Es mag das Ergebnis des Übens sein, ** RecyclerAdapter die ganze Nacht über verzweifelt zu machen, aber angesichts der späteren Erweiterbarkeit ist es besser, es mit RecyclerView zu implementieren. Er hat ListView verraten und ist jetzt ein RecyclerView-Gläubiger.

Nehmen wir an, dass die Bequemlichkeit von RecyclerView hier vorhanden ist und sich mit dem Hauptthema befasst. Es gibt viele gute Artikel, die von RecyclerView-Followern geschrieben wurden. Bitte lesen Sie sie auch (entschuldigen Sie, dass Sie sie ohne Erlaubnis zu Followern gemacht haben).

Grundlagen von RecyclerViewIch habe gerade die Grundlagen von RecyclerView zusammengefasst

Ich möchte auch in RecyclerView auswählen

Dies bedeutet, dass Sie auswählbare Elemente erstellen möchten. Es ist eine RecyclerView, die keine Funktionen hat, aber ** ändern wir sie in eine SelectableRecyclerView, die ich direkt auswählen kann **. Das ist der Inhalt dieses Artikels. Diese Funktion ist mit ziemlicher Sicherheit in neueren Apps implementiert, aber überraschenderweise gibt es nur wenige Artikel, die dies erklären. Deshalb habe ich diesen Artikel geschrieben.

Auswählbare Funktionen der Recycler-Ansicht

Da es in verschiedenen Apps implementiert ist, wissen Sie wahrscheinlich, um welche Art von Funktion es sich handelt, aber ich werde vorerst eine Liste der Funktionen erstellen.

・ Verhält sich normalerweise wie eine normale Recycler-Ansicht ・ Halten Sie ein Element gedrückt, um den Auswahlmodus aufzurufen ・ Im Auswahlmodus können Sie auch mit NormalClick auswählen (Sie können auch mit langem Drücken auswählen). -Klicken Sie auf das ausgewählte Element, um die Auswahl aufzuheben ・ Wenn alle Elemente abgewählt sind, wird der Auswahlmodus automatisch deaktiviert. ・ Sie können das ausgewählte Element erhalten ・ In einigen Fällen können Sie jederzeit in den Auswahlmodus wechseln.

Geht es darum? Ich denke, dass diese Funktionen gemeinsam sind, auch wenn es je nach Anwendung Unterschiede in den Funktionen gibt. Wenn Sie etwas anderes benötigen, implementieren Sie es bitte selbst. Diese Erweiterbarkeit ist auch ein guter Punkt von RecyclerView.

Umgebung

Es heißt SelectableRecyclerView, daher dachte ich, ich würde es zu einer Ansicht machen, aber angesichts der Erweiterbarkeit ist dies nicht der Fall. Unterschiedliche Menschen brauchen unterschiedliche Funktionen. Also dieses Mal werde ich es mit Adapter implementieren. Vorher werde ich über diese Umgebung schreiben. Ich werde basierend auf dem grundlegenden Kotlin schreiben, aber da es in Java Nachfrage zu geben scheint, werde ich auch die Implementierung in Java für den Adapter selbst schreiben. (Da ich ein Anfänger in Java bin, sagen Sie mir bitte, wenn Sie einen Fehler machen.)

· Java 8 ・ Kotlin 1.4 ・ Android Studio 4.0.1 ・ Ziel-SDK 30 ・ Min. SDK 24 ・ Tools erstellen 30.0.1

Versuchen Sie, es auswählbar zu machen

Adapter und Halter

Kotlin-Version (zum Vergrößern anklicken)
Da ich es zuerst in Java geschrieben habe, verwendet Holder Java. Kotlin ist ein Gott, der Java so verwenden kann, wie es ist.

SelectableAdapterWithKotlin.kt


class SelectableAdapterWithKotlin(private val context: Context, private val itemDataList: List<String>, private val isAlwaysSelectable: Boolean): RecyclerView.Adapter<SelectableHolder>(){

    //Wenn isAlwaysSelectable aktiviert ist, wählen Sie den Modus von Anfang an aus
    private var isSelectableMode = isAlwaysSelectable
    private val selectedItemPositions = mutableSetOf<Int>()

    override fun onCreateViewHolder(parent: ViewGroup, viewType: Int): SelectableHolder {
        return SelectableHolder(LayoutInflater.from(parent.context).inflate(R.layout.view_multi_url_card, parent, false))
    }

    @SuppressLint("SetTextI18n")
    override fun onBindViewHolder(holder: SelectableHolder, position: Int) {
        with(holder) {
            mainTextView.text = itemDataList[position]
            subTextView.text = "position $position"

            //Wenn dieses Element ausgewählt ist, überprüfen Sie es (Bild von ✓ anzeigen)
            checkLayout.visibility = if (isSelectedItem(position)) View.VISIBLE else View.GONE

            cardView.setOnClickListener {

                //Als normalen Klick behandeln, wenn Sie sich nicht im Auswahlmodus befinden
                if (!isSelectableMode && !isAlwaysSelectable) Toast.makeText(context, "Normal click", Toast.LENGTH_SHORT).show()
                else {
                    if (isSelectedItem(position)) removeSelectedItem(position)
                    else addSelectedItem(position)

                    onBindViewHolder(holder, position)
                }
            }
            cardView.setOnLongClickListener {

                //Langer Klick, um den Auswahlmodus aufzurufen
                if (isSelectedItem(position)) removeSelectedItem(position)
                else addSelectedItem(position)

                onBindViewHolder(holder, position)

                return@setOnLongClickListener true
            }
        }
    }

    override fun getItemCount(): Int = itemDataList.size

    //Übergeben Sie das Set, das die Position des ausgewählten Elements aufzeichnet, nach außen
    fun getSelectedItemPositions() = selectedItemPositions.toSet()
    
    //Überprüfen Sie, ob das Element der angegebenen Position ausgewählt ist
    private fun isSelectedItem(position: Int): Boolean = (selectedItemPositions.contains(position))

    //Aktivieren Sie den Auswahlmodus, wenn Sie sich nicht im Auswahlmodus befinden
    private fun addSelectedItem(position: Int){
        if(selectedItemPositions.isEmpty() && !isAlwaysSelectable){
            isSelectableMode = true
            Toast.makeText(context, "Selectable Mode ON", Toast.LENGTH_SHORT).show()
        }
        selectedItemPositions.add(position)
    }

    //Wenn der letzte im Auswahlmodus abgewählt ist, deaktivieren Sie den Auswahlmodus
    private fun removeSelectedItem(position: Int){
        selectedItemPositions.remove(position)
        if(selectedItemPositions.isEmpty() && !isAlwaysSelectable){
            isSelectableMode = false
            Toast.makeText(context, "Selectable Mode OFF", Toast.LENGTH_SHORT).show()
        }
    }
}
Java-Version (zum Erweitern klicken)

SelectableHolder.java


public class SelectableHolder extends RecyclerView.ViewHolder {

    public TextView mainTextView;
    public TextView subTextView;
    public CardView cardView;
    public ConstraintLayout checkLayout;

    public SelectableHolder(View itemView) {
        super(itemView);

        mainTextView = itemView.findViewById(R.id.VMU_MainText);
        subTextView = itemView.findViewById(R.id.VMU_SubText);
        cardView = itemView.findViewById(R.id.VMU_CardView);
        checkLayout = itemView.findViewById(R.id.VMU_CheckLayout);
    }
}

SelectableAdapter.java


public class SelectableAdapter extends RecyclerView.Adapter<SelectableHolder> {

    private Context context;
    private List<String> itemDataList;

    private Boolean isSelectableMode;
    private Boolean isAlwaysSelectable;
    private Set<Integer> selectedItemPositionsSet = new ArraySet<>();

    public SelectableAdapter(Context context, List<String> itemDataList, Boolean isAlwaysSelectable){
        this.context = context;
        this.itemDataList = itemDataList;
        this.isAlwaysSelectable = isAlwaysSelectable;

        //Wenn isAlwaysSelectable aktiviert ist, wählen Sie den Modus von Anfang an aus
        isSelectableMode = isAlwaysSelectable;
    }

    @NonNull
    @Override
    public SelectableHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        return new SelectableHolder(LayoutInflater.from(parent.getContext()).inflate(R.layout.view_multi_url_card, parent, false));
    }

    @SuppressLint("SetTextI18n")
    @Override
    public void onBindViewHolder(@NonNull final SelectableHolder holder, final int position) {
        holder.mainTextView.setText(itemDataList.get(position));
        holder.subTextView.setText("position " + position);

        //Wenn dieses Element ausgewählt ist, überprüfen Sie es (Bild von ✓ anzeigen)
        if(isSelectedItem(position)){
            holder.checkLayout.setVisibility(View.VISIBLE);
        }
        else {
            holder.checkLayout.setVisibility(View.GONE);
        }

        holder.cardView.setOnClickListener(view -> {

            //Als normalen Klick behandeln, wenn Sie sich nicht im Auswahlmodus befinden
            if(!isSelectableMode && !isAlwaysSelectable) Toast.makeText(context, "Normal click", Toast.LENGTH_SHORT).show();
            else {
                if(isSelectedItem(position)) removeSelectedItem(position);
                else addSelectedItem(position);

                onBindViewHolder(holder, position);
            }
        });

        holder.cardView.setOnLongClickListener(view -> {

            //Langer Klick, um den Auswahlmodus aufzurufen
            if (isSelectedItem(position)) removeSelectedItem(position);
            else addSelectedItem(position);

            onBindViewHolder(holder, position);

            return true;
        });
    }

    @Override
    public int getItemCount() {
        return itemDataList.size();
    }

    //Übergeben Sie das Set, das die Position des ausgewählten Elements aufzeichnet, nach außen
    Set<Integer> getSelectedItemPositions(){
        return selectedItemPositionsSet;
    }

    //Überprüfen Sie, ob das Element der angegebenen Position ausgewählt ist
    private Boolean isSelectedItem(int position){
        return selectedItemPositionsSet.contains(position);
    }

    //Aktivieren Sie den Auswahlmodus, wenn Sie sich nicht im Auswahlmodus befinden
    private void addSelectedItem(int position){
        if(selectedItemPositionsSet.isEmpty() && !isAlwaysSelectable) {
            isSelectableMode = true;
            Toast.makeText(context, "Selectable Mode ON", Toast.LENGTH_SHORT).show();
        }
        selectedItemPositionsSet.add(position);
    }

    //Wenn der letzte im Auswahlmodus abgewählt ist, deaktivieren Sie den Auswahlmodus
    private void removeSelectedItem(int position){
        selectedItemPositionsSet.remove(position);
        if(selectedItemPositionsSet.isEmpty() && !isAlwaysSelectable){
            isSelectableMode = false;
            Toast.makeText(context, "Selectable Mode OFF", Toast.LENGTH_SHORT).show();
        }
    }
}

Activity Die Aktivität ist in Kotlin geschrieben. Ich schreibe überhaupt keine große Sache, daher denke ich, dass sie leicht portiert werden kann. Wenn Sie die Taste drücken, wird die Position des ausgewählten Elements vom Adapter (getSelectedItemPositions) empfangen und der Wert wird durch Vergleichen mit der von der Aktivität gehaltenen Liste erhalten und angezeigt.

Code unten (zum Vergrößern anklicken)

MainActivity.kt


class MainActivity : AppCompatActivity(){

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.activity_main)

        val itemDataList = listOf("Pommern", "Zwergpudel", "Shiba Hund", "Bulldogge", "Daxfund", "Dobelman", "Beagle", "Labrador Retriever", "Golden Retriever", "Sibirischer Husky")
        val selectableAdapter = SelectableAdapterWithKotlin(this, itemDataList, false)

        AM_RecyclerView.apply {
            setHasFixedSize(false)
            adapter = selectableAdapter
            layoutManager = LinearLayoutManager(this@MainActivity)
        }

        AM_Button.setOnClickListener {
            MaterialAlertDialogBuilder(this)
                .setTitle("Ausgewähltes Objekt")
                .setMessage(selectableAdapter.getSelectedItemPositions().joinToString(separator = "\n") { itemDataList[it] })
                .setPositiveButton("OK", null)
                .show()
        }
    }
}

Layout

Es ist etwas kompliziert anzuzeigen, dass es ausgewählt ist. Dieses Mal wird der Auswahlstatus durch Ein- / Ausblenden der Ansicht angezeigt, aber ich denke, dass Sie das Kontrollkästchen aktivieren können.

Code unten (zum Vergrößern anklicken)

view_multi_url_card.xml


<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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="wrap_content">

    <androidx.cardview.widget.CardView
        android:id="@+id/VMU_CardView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_marginStart="16dp"
        android:layout_marginTop="8dp"
        android:layout_marginEnd="16dp"
        android:layout_marginBottom="8dp"
        android:foreground="?android:attr/selectableItemBackground"
        app:cardCornerRadius="8dp"
        app:cardBackgroundColor="@color/colorBackgroundZ4"
        app:layout_constraintBottom_toBottomOf="parent"
        app:layout_constraintEnd_toEndOf="parent"
        app:layout_constraintStart_toStartOf="parent"
        app:layout_constraintTop_toTopOf="parent">

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

            <androidx.cardview.widget.CardView
                android:id="@+id/cardView"
                android:layout_width="0dp"
                android:layout_height="0dp"
                app:cardBackgroundColor="@android:color/transparent"
                app:cardElevation="0dp"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintDimensionRatio="1:1"
                app:layout_constraintStart_toStartOf="parent"
                app:layout_constraintTop_toTopOf="parent">

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

                    <ImageView
                        android:id="@+id/VMU_Image"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:layout_gravity="center"
                        android:scaleType="centerCrop"
                        android:src="@drawable/im_dog"
                        app:layout_constraintBottom_toBottomOf="parent"
                        app:layout_constraintEnd_toEndOf="parent"
                        app:layout_constraintStart_toStartOf="parent"
                        app:layout_constraintTop_toTopOf="parent" />

                    <androidx.constraintlayout.widget.ConstraintLayout
                        android:id="@+id/VMU_CheckLayout"
                        android:layout_width="match_parent"
                        android:layout_height="match_parent"
                        android:alpha="0.9"
                        android:background="@color/colorAccent"
                        android:visibility="gone">

                        <ImageView
                            android:layout_width="match_parent"
                            android:layout_height="match_parent"
                            android:layout_gravity="center"
                            android:layout_marginStart="16dp"
                            android:layout_marginTop="16dp"
                            android:layout_marginEnd="16dp"
                            android:layout_marginBottom="16dp"
                            android:scaleType="fitCenter"
                            android:src="@drawable/ic_check"
                            app:layout_constraintBottom_toBottomOf="parent"
                            app:layout_constraintEnd_toEndOf="parent"
                            app:layout_constraintStart_toStartOf="parent"
                            app:layout_constraintTop_toTopOf="parent" />

                    </androidx.constraintlayout.widget.ConstraintLayout>

                </androidx.constraintlayout.widget.ConstraintLayout>
            </androidx.cardview.widget.CardView>

            <LinearLayout
                android:id="@+id/linearLayout"
                android:layout_width="0dp"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:layout_marginStart="16dp"
                android:layout_marginTop="16dp"
                android:layout_marginEnd="16dp"
                android:layout_marginBottom="16dp"
                android:orientation="vertical"
                app:layout_constraintBottom_toBottomOf="parent"
                app:layout_constraintEnd_toEndOf="parent"
                app:layout_constraintStart_toEndOf="@+id/cardView"
                app:layout_constraintTop_toTopOf="parent">

                <TextView
                    android:id="@+id/VMU_MainText"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:ellipsize="end"
                    android:singleLine="true"
                    android:text="Haupt Text"
                    android:textColor="@color/colorChar"
                    android:textSize="14sp" />

                <TextView
                    android:id="@+id/VMU_SubText"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:layout_marginTop="8dp"
                    android:ellipsize="end"
                    android:gravity="end"
                    android:singleLine="true"
                    android:text="Subtext"
                    android:textColor="@color/colorCharSec"
                    android:textSize="12sp" />

            </LinearLayout>
        </androidx.constraintlayout.widget.ConstraintLayout>
    </androidx.cardview.widget.CardView>
</androidx.constraintlayout.widget.ConstraintLayout>

activity_main.xml


<?xml version="1.0" encoding="utf-8"?>
<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:background="@color/colorBackgroundZ3"
    android:orientation="vertical"
    tools:context=".MainActivity">

    <androidx.recyclerview.widget.RecyclerView
        android:id="@+id/AM_RecyclerView"
        android:layout_width="match_parent"
        android:layout_height="0dp"
        android:layout_weight="1"/>

    <com.google.android.material.button.MaterialButton
        android:id="@+id/AM_Button"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:layout_margin="8dp"
        android:text="Ausgewählte Elemente anzeigen" />

</LinearLayout>

Gradle Um RecyclerView verwenden zu können, müssen Sie Gradle hinzufügen. Dieses Mal benutze ich auch CardView usw., also muss ich sie auch schreiben.

Code unten (zum Vergrößern anklicken)

build.gradle(app)


dependencies {
    implementation 'androidx.recyclerview:recyclerview:1.1.0'
    implementation 'androidx.cardview:cardview:1.0.0'
    implementation 'com.google.android.material:material:1.2.0'
}

Ich versuchte mich zu bewegen

Ich habe es auf Pixel 3 (Android 11) versucht. Sowohl die Kotlin-Version als auch die Java-Version funktionieren gleich. 実機で動いているZIF

Schließlich

Diesmal habe ich eine auswählbare RecyclerView erstellt. Im obigen GIF ist isAlwaysSelectable falsch, aber wenn Sie es auf true setzen, ist es immer auswählbar. In Java können Fehler auftreten. Wenn Sie also einen finden, kommentieren Sie diesen bitte. Bitte machen Sie LGTM unabhängig davon, ob es hilfreich ist oder nicht (es ist eine Lüge. Bitte kommentieren Sie, wenn es nicht hilfreich ist. Ich werde Ihnen so viel wie möglich helfen)

Recommended Posts

[Java & Kotlin] Erstellen Sie eine RecyclerView mit mehreren Auswahlen
Mehrfacher Ersatz für Java-Zeichenfolgen
[Java, Kotlin] Typabweichung
Erstellen Sie JSON in Java
[Java] Erstellen Sie eine temporäre Datei
Erstellen Sie Azure-Funktionen in Java
Erstellen Sie Ihre eigenen Java-Anmerkungen
[Java] Mehrfach-ODER-Bedingungsbeurteilung
[Java] Mehrere Listen (Sammlungen) kombinieren