Prosty przykład siatki systemu Android przy użyciu RecyclerView z GridLayoutManager (podobnie jak stary GridView)


227

Wiem, że RecyclerViewto zastąpiło funkcjonalność starego ListViewi GridView. Szukam bardzo podstawowego przykładu, który pokazuje minimalną konfigurację siatki przy użyciu RecyclerView. Nie szukam długich wyjaśnień w stylu samouczka, tylko minimalny przykład. Wyobrażam sobie, że najprostsza siatka naśladująca stary GridView składałaby się z następujących funkcji:

  • wiele komórek w wierszu
  • pojedynczy widok w każdej komórce
  • reaguje na zdarzenia kliknięcia

Odpowiedzi:


556

Krótka odpowiedź

Dla tych, którzy są już zaznajomieni z tworzeniem RecyclerViewlisty , dobrą wiadomością jest to, że tworzenie siatki jest w dużej mierze takie samo. Podczas konfigurowania używasz GridLayoutManagerzamiast zamiast .LinearLayoutManagerRecyclerView

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

Jeśli potrzebujesz więcej pomocy, sprawdź poniższy przykład.

Pełny przykład

Poniżej znajduje się minimalny przykład, który będzie wyglądał jak na poniższym obrazku.

wprowadź opis zdjęcia tutaj

Zacznij od pustej aktywności. Wykonasz następujące zadania, aby dodać RecyclerViewsiatkę. Wszystko, co musisz zrobić, to skopiować i wkleić kod w każdej sekcji. Później możesz dostosować go do swoich potrzeb.

  • Dodaj zależności do stopnia
  • Dodaj pliki układu xml dla działania i komórki siatki
  • Wykonaj adapter RecyclerView
  • Zainicjuj RecyclerView w swojej aktywności

Zaktualizuj zależności Gradle

Upewnij się, że w gradle.buildpliku aplikacji znajdują się następujące zależności :

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

Możesz zaktualizować numery wersji do najnowszej .

Utwórz układ aktywności

Dodaj RecyclerViewdo swojego układu xml.

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>

Utwórz układ komórek siatki

Każda komórka w naszej RecyclerViewsiatce będzie miała tylko jeden TextView. Utwórz nowy plik zasobów układu.

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>

Utwórz adapter

RecyclerViewWymaga adaptera do wypełnienia widoki w każdej komórce z danymi. Utwórz nowy plik Java.

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

Notatki

  • Chociaż nie jest to absolutnie konieczne, dołączyłem funkcję nasłuchiwania zdarzeń kliknięcia w komórkach. To było dostępne w dawnych czasach GridViewi jest powszechną potrzebą. Możesz usunąć ten kod, jeśli go nie potrzebujesz.

Zainicjuj RecyclerView w działaniu

Dodaj następujący kod do swojej głównej działalności.

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

Notatki

  • Zauważ, że działanie implementuje to ItemClickListener, co zdefiniowaliśmy w naszym adapterze. To pozwala nam obsługiwać zdarzenia kliknięcia komórki w onItemClick.

Skończone

Otóż ​​to. Powinieneś być teraz w stanie uruchomić swój projekt i uzyskać coś podobnego do obrazu na górze.

Dziać się

Zaokrąglone rogi

Automatyczne dopasowanie kolumn

Dalsze badanie


2
@ MarianPaździoch, Tak, właśnie to zrobiłem jako minimalny przykład. Na pewno przydałoby się trochę pracy upiększającej. Spróbuję zaktualizować tę odpowiedź w przyszłości.
Suragch

1
Zalogowałem się tylko po to, aby wskazać, że ludzie tacy jak ty utrzymywali ten portal przy życiu i kopali .i utknąłem na nim przez dwa dni, zanim zobaczyłem to rozwiązanie. wielkie dzięki
VarunJoshi129,

1
@ androiddeveloper, Elementy siatki są układane od lewej do prawej, od góry do dołu. Przewijanie odbywa się w pionie, gdy na ekranie jest więcej elementów, niż można zmieścić.
Suragch,

13
Przyszli czytelnicy, pozwólcie mi zaoszczędzić trochę czasu, najważniejsze jestrecyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
daka

1
@daka, dobra uwaga. Zredagowałem swoją odpowiedź, aby uwzględnić to na początku.
Suragch

7

Chociaż podoba mi się odpowiedź Suragcha i doceniam , chciałbym zostawić notatkę, ponieważ odkryłem, że kodowanie Adapter ( MyRecyclerViewAdapter) w celu zdefiniowania i ujawnienia metody Listener onItemClicknie jest najlepszym sposobem, aby to zrobić, ponieważ nie używa się enkapsulacji klas prawidłowo. Dlatego proponuję, aby Adapter mógł obsługiwać operacje Listening wyłącznie (to jest jego cel!) I oddzielać te od Działania, które korzysta z Adaptera ( MainActivity). Oto jak ustawiłbym klasę adaptera:

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

Pamiętaj, że onItemClickmetoda zdefiniowana w MyRecyclerViewAdaptertym miejscu to miejsce, w którym chcesz zakodować swoje zadania dla otrzymanego zdarzenia / akcji.

Aby dokończyć tę transformację, należy wprowadzić tylko niewielką zmianę: działanie nie musi MyRecyclerViewAdapter.ItemClickListenerjuż być wdrażane , ponieważ teraz jest to całkowicie wykonywane przez adapter . Byłaby to ostateczna modyfikacja:

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
Co się stanie, jeśli aktywność wymaga odsłuchania zdarzeń kliknięcia? np. przekazywanie danych prezenterowi, wykonywanie logiki na podstawie klikniętego elementu, śledzenie itp.
Ahmad Fadli

Zgadzam się, że Adapter powinien obsługiwać zdarzenia kliknięcia, ponieważ zawiera elementy zawierające dane. @AhmadFadli, jeśli chcesz popracować na hoście adaptera (Fragment lub Działanie), powinieneś utworzyć interfejs zwrotny z potrzebnymi metodami. Twój host implementuje ten interfejs. Następnie przekazujesz instancję swojego hosta do konstruktora Adaptera. Mając wystąpienie hosta, możesz nazywać go metodami, kiedy potrzebujesz z adaptera. A Twój host otrzyma połączenia zwrotne. Jest to często używane, gdy trzeba pracować z ActionMode. Po długim kliknięciu wybierz elementy i użyj przycisków ActionBar.
Kirill Karmazin

Nie zgadzam się i uważam, że zdarzenia związane z kliknięciami powinny być przetwarzane w hostingu Activity. Bo tylko to jest kliknięcie słuchacz może wiedzieć na temat Activitypoglądów i innych Fragments, Activitiesitp Adapter może tylko wysłać kliknij zdarzenia do górnego poziomu. Powinien mieć interfejs ItemClickListener z tyloma zdarzeniami, ile może wygenerować widok adaptera zdarzeń. To rozwiązanie zostało napisane jeszcze wcześniej: stackoverflow.com/a/40563598/2914140 .
CoolMind,

4

Musisz ustawić menedżera układu recyclinglerview na tryb Gridlayout, w tym celu Po prostu zmień kod, kiedy chcesz Ustaw swój menedżer układu RecyclerView:

Uwaga: zamień żądaną liczbę kolumn na ### HELP ###

   recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),###HELP###));
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.