Einfaches Android-Grid-Beispiel mit RecyclerView mit GridLayoutManager (wie das alte GridView)


227

Ich weiß, dass RecyclerViewdie Funktionalität der alten ListViewund ersetzt hat GridView. Ich suche ein sehr einfaches Beispiel, das ein minimales Raster-Setup mit zeigt RecyclerView. Ich suche keine langen Erklärungen im Tutorial-Stil, nur ein minimales Beispiel. Ich stelle mir vor, dass das einfachste Raster, das das alte GridView nachahmt, aus folgenden Funktionen besteht:

  • mehrere Zellen pro Zeile
  • Einzelansicht in jeder Zelle
  • reagiert auf Klickereignisse

Antworten:


556

Kurze Antwort

Für diejenigen , die bereits vertraut sind mit der Einrichtung ein RecyclerVieweine Liste zu machen , ist die gute Nachricht , dass ein Gitter zu machen ist weitgehend gleich. Sie verwenden beim Einrichten einfach a GridLayoutManageranstelle von a .LinearLayoutManagerRecyclerView

recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));

Wenn Sie mehr Hilfe benötigen, sehen Sie sich das folgende Beispiel an.

Vollständiges Beispiel

Das Folgende ist ein minimales Beispiel, das wie im Bild unten aussieht.

Geben Sie hier die Bildbeschreibung ein

Beginnen Sie mit einer leeren Aktivität. Sie werden die folgenden Aufgaben ausführen , die hinzuzufügen RecyclerViewRaster. Sie müssen lediglich den Code in jeden Abschnitt kopieren und einfügen. Später können Sie es an Ihre Bedürfnisse anpassen.

  • Fügen Sie dem Gradle Abhängigkeiten hinzu
  • Fügen Sie die XML-Layoutdateien für die Aktivität und für die Rasterzelle hinzu
  • Stellen Sie den RecyclerView-Adapter her
  • Initialisieren Sie die RecyclerView in Ihrer Aktivität

Aktualisieren Sie Gradle-Abhängigkeiten

Stellen Sie sicher, dass die folgenden Abhängigkeiten in Ihrer App- gradle.buildDatei enthalten sind:

compile 'com.android.support:appcompat-v7:27.1.1'
compile 'com.android.support:recyclerview-v7:27.1.1'

Sie können die Versionsnummern auf die aktuellsten aktualisieren .

Aktivitätslayout erstellen

Fügen Sie das RecyclerViewIhrem XML-Layout hinzu.

activity_main.xml

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <android.support.v7.widget.RecyclerView
        android:id="@+id/rvNumbers"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</RelativeLayout>

Erstellen Sie ein Rasterzellenlayout

Jede Zelle in unserem RecyclerViewRaster wird nur eine einzige haben TextView. Erstellen Sie eine neue Layoutressourcendatei.

recyclerview_item.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
    xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="horizontal"
    android:padding="5dp"
    android:layout_width="50dp"
    android:layout_height="50dp">

        <TextView
            android:id="@+id/info_text"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:gravity="center"
            android:background="@color/colorAccent"/>

</LinearLayout>

Erstellen Sie den Adapter

Sie RecyclerViewbenötigen einen Adapter, um die Ansichten in jeder Zelle mit Ihren Daten zu füllen. Erstellen Sie eine neue Java-Datei.

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {

    private String[] mData;
    private LayoutInflater mInflater;
    private ItemClickListener mClickListener;

    // data is passed into the constructor
    MyRecyclerViewAdapter(Context context, String[] data) {
        this.mInflater = LayoutInflater.from(context);
        this.mData = data;
    }

    // inflates the cell layout from xml when needed
    @Override
    @NonNull 
    public ViewHolder onCreateViewHolder(@NonNull ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
        return new ViewHolder(view);
    }

    // binds the data to the TextView in each cell
    @Override
    public void onBindViewHolder(@NonNull ViewHolder holder, int position) {
        holder.myTextView.setText(mData[position]);
    }

    // total number of cells
    @Override
    public int getItemCount() {
        return mData.length;
    }


    // stores and recycles views as they are scrolled off screen
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        TextView myTextView;

        ViewHolder(View itemView) {
            super(itemView);
            myTextView = itemView.findViewById(R.id.info_text);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            if (mClickListener != null) mClickListener.onItemClick(view, getAdapterPosition());
        }
    }

    // convenience method for getting data at click position
    String getItem(int id) {
        return mData[id];
    }

    // allows clicks events to be caught
    void setClickListener(ItemClickListener itemClickListener) {
        this.mClickListener = itemClickListener;
    }

    // parent activity will implement this method to respond to click events
    public interface ItemClickListener {
        void onItemClick(View view, int position);
    }
}

Anmerkungen

  • Obwohl dies nicht unbedingt erforderlich ist, habe ich die Funktionalität zum Abhören von Klickereignissen in den Zellen hinzugefügt. Dies war in der alten verfügbar GridViewund ist ein allgemeines Bedürfnis. Sie können diesen Code entfernen, wenn Sie ihn nicht benötigen.

Initialisieren Sie RecyclerView in Aktivität

Fügen Sie Ihrer Hauptaktivität den folgenden Code hinzu.

MainActivity.java

public class MainActivity extends AppCompatActivity implements MyRecyclerViewAdapter.ItemClickListener {

    MyRecyclerViewAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // data to populate the RecyclerView with
        String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48"};

        // set up the RecyclerView
        RecyclerView recyclerView = findViewById(R.id.rvNumbers);
        int numberOfColumns = 6;
        recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
        adapter = new MyRecyclerViewAdapter(this, data);
        adapter.setClickListener(this);
        recyclerView.setAdapter(adapter);
    }

    @Override
    public void onItemClick(View view, int position) {
        Log.i("TAG", "You clicked number " + adapter.getItem(position) + ", which is at cell position " + position);
    }
}

Anmerkungen

  • Beachten Sie, dass die Aktivität das implementiert ItemClickListener, was wir in unserem Adapter definiert haben. Dies ermöglicht es uns, Zellklickereignisse in zu verarbeiten onItemClick.

Fertig

Das ist es. Sie sollten jetzt in der Lage sein, Ihr Projekt auszuführen und etwas Ähnliches wie das Bild oben zu erhalten.

Weiter geht's

Abgerundete Ecken

Automatisch passende Säulen

Weitere Studie


2
@ MarianPaździoch, Ja, ich habe dies nur als minimales Beispiel gemacht. Es könnte definitiv einige Verschönerungsarbeiten gebrauchen. Ich werde versuchen, diese Antwort irgendwann in der Zukunft zu aktualisieren.
Suragch

1
Ich habe mich nur angemeldet, um darauf hinzuweisen, dass Leute wie Sie dieses Portal am Leben erhalten haben. Ich habe zwei Tage lang daran festgehalten, bevor ich diese Lösung gesehen habe.
Vielen

1
@androiddeveloper, Die Rasterelemente werden von links nach rechts und von oben nach unten angeordnet. Das Scrollen erfolgt vertikal, wenn mehr Elemente vorhanden sind, als auf den Bildschirm passen.
Suragch

13
Zukünftige Leser, lassen Sie mich Ihnen etwas Zeit sparen, der Schlüssel istrecyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
Daka

1
@ Daka, guter Punkt. Ich habe meine Antwort so bearbeitet, dass sie am Anfang enthalten ist.
Suragch

7

Obwohl ich Suragchs Antwort mag und schätze , möchte ich eine Notiz hinterlassen, da ich festgestellt habe, dass das Codieren des Adapters ( MyRecyclerViewAdapter) zum Definieren und Offenlegen der Listener-Methode onItemClicknicht der beste Weg ist, da keine Klassenkapselung verwendet wird korrekt. Mein Vorschlag ist daher, den Adapter nur die Abhörvorgänge ausführen zu lassen (das ist sein Zweck!) Und diese von der Aktivität zu trennen, die den Adapter verwendet ( MainActivity). So würde ich die Adapterklasse einstellen:

MyRecyclerViewAdapter.java

public class MyRecyclerViewAdapter extends RecyclerView.Adapter<MyRecyclerViewAdapter.ViewHolder> {

    private String[] mData = new String[0];
    private LayoutInflater mInflater;

    // Data is passed into the constructor
    public MyRecyclerViewAdapter(Context context, String[] data) {
        this.mInflater = LayoutInflater.from(context);
        this.mData = data;
    }

    // Inflates the cell layout from xml when needed
    @Override
    public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
        View view = mInflater.inflate(R.layout.recyclerview_item, parent, false);
        ViewHolder viewHolder = new ViewHolder(view);
        return viewHolder;
    }

    // Binds the data to the textview in each cell
    @Override
    public void onBindViewHolder(ViewHolder holder, int position) {
        String animal = mData[position];
        holder.myTextView.setText(animal);
    }

    // Total number of cells
    @Override
    public int getItemCount() {
        return mData.length;
    }

    // Stores and recycles views as they are scrolled off screen
    public class ViewHolder extends RecyclerView.ViewHolder implements View.OnClickListener {
        public TextView myTextView;

        public ViewHolder(View itemView) {
            super(itemView);
            myTextView = (TextView) itemView.findViewById(R.id.info_text);
            itemView.setOnClickListener(this);
        }

        @Override
        public void onClick(View view) {
            onItemClick(view, getAdapterPosition());
        }
    }

    // Convenience method for getting data at click position
    public String getItem(int id) {
        return mData[id];
    }

    // Method that executes your code for the action received
    public void onItemClick(View view, int position) {
        Log.i("TAG", "You clicked number " + getItem(position).toString() + ", which is at cell position " + position);
    }
}

Bitte beachten Sie, dass die onItemClickjetzt definierte Methode MyRecyclerViewAdapterder Ort ist, an dem Sie Ihre Aufgaben für das empfangene Ereignis / die empfangene Aktion codieren möchten.

Es ist nur eine kleine Änderung erforderlich, um diese Transformation abzuschließen: Die Aktivität muss nicht MyRecyclerViewAdapter.ItemClickListenermehr implementiert werden, da dies jetzt vollständig vom Adapter durchgeführt wird . Dies wäre dann die endgültige Änderung:

MainActivity.java

public class MainActivity extends AppCompatActivity {

    MyRecyclerViewAdapter adapter;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        // data to populate the RecyclerView with
        String[] data = {"1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "12", "13", "14", "15", "16", "17", "18", "19", "20", "21", "22", "23", "24", "25", "26", "27", "28", "29", "30", "31", "32", "33", "34", "35", "36", "37", "38", "39", "40", "41", "42", "43", "44", "45", "46", "47", "48"};

        // set up the RecyclerView
        RecyclerView recyclerView = (RecyclerView) findViewById(R.id.rvNumbers);
        int numberOfColumns = 6;
        recyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
        adapter = new MyRecyclerViewAdapter(this, data);
        adapter.setClickListener(this);
        recyclerView.setAdapter(adapter);
    }
}

3
Was ist, wenn die Aktivität die Klickereignisse abhören muss? zB Daten an den Präsentator weitergeben, eine Logik basierend auf dem angeklickten Element, der Verfolgung usw.
ausführen

Ich bin damit einverstanden, dass der Adapter Klickereignisse behandelt, da er die Elemente mit den Daten enthält. @AhmadFadli Wenn Sie auf dem Host des Adapters arbeiten müssen (ein Fragment oder eine Aktivität), sollten Sie eine Rückrufschnittstelle mit den von Ihnen benötigten Methoden erstellen. Ihr Host implementiert diese Schnittstelle. Anschließend übergeben Sie eine Instanz Ihres Hosts an den Konstruktor des Adapters. Wenn Sie die Instanz des Hosts haben, können Sie dessen Methoden bei Bedarf von Ihrem Adapter aus aufrufen. Und Ihr Gastgeber bekommen Rückrufe. Dies wird häufig verwendet, wenn Sie mit ActionMode arbeiten müssen. Wenn Sie longClick, um Elemente auszuwählen und ActionBar-Schaltflächen zu verwenden.
Kirill Karmazin

Ich bin anderer Meinung und denke, dass Klickereignisse im Hosting verarbeitet werden sollten Activity. Denn nur den es Klick Zuhörer über die wissen können , ActivityAnsichten und andere Fragments, Activitiesetc. Der Adapter sendet nur Ereignisse obere Ebene klicken. Es sollte die Schnittstelle ItemClickListener mit so vielen Ereignissen haben, wie viele Ansichten des Ereignisadapters erzeugen können. Diese Lösung wurde noch früher geschrieben: stackoverflow.com/a/40563598/2914140 .
CoolMind

4

Sie müssen Ihren recyclerview layoutmanager in den Gridlayout-Modus versetzen. Ändern Sie dazu einfach Ihren Code, wenn Sie Ihren RecyclerView LayoutManager einstellen möchten:

Hinweis: Ersetzen Sie die gewünschte Spaltenanzahl durch ### HELP ###

   recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),###HELP###));
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.