Ejemplo simple de cuadrícula de Android usando RecyclerView con GridLayoutManager (como el antiguo GridView)

227

Sé que RecyclerViewha reemplazado la funcionalidad de los viejos ListViewy GridView. Estoy buscando un ejemplo muy básico que muestre una configuración de cuadrícula mínima usando RecyclerView. No estoy buscando explicaciones largas de estilo tutorial, solo un ejemplo mínimo. Me imagino que la cuadrícula más simple que imita el antiguo GridView consistiría en las siguientes características:

  • múltiples celdas por fila
  • vista única en cada celda
  • responde a eventos de clic
Suragch
fuente

Respuestas:

556

Respuesta corta

Para aquellos que ya están familiarizados con la configuración de un RecyclerViewpara hacer una lista , la buena noticia es que hacer una cuadrícula es prácticamente lo mismo. Solo usa un en GridLayoutManagerlugar de un LinearLayoutManagercuando configura la RecyclerViewconfiguración.

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

Si necesita más ayuda que eso, consulte el siguiente ejemplo.

Ejemplo completo

El siguiente es un ejemplo mínimo que se verá como la imagen de abajo.

ingrese la descripción de la imagen aquí

Comience con una actividad vacía. Realizará las siguientes tareas para agregar la RecyclerViewcuadrícula. Todo lo que necesita hacer es copiar y pegar el código en cada sección. Más tarde, puede personalizarlo para satisfacer sus necesidades.

  • Agregar dependencias a gradle
  • Agregue los archivos de diseño xml para la actividad y para la celda de cuadrícula
  • Haga el adaptador RecyclerView
  • Inicialice RecyclerView en su actividad

Actualizar dependencias de Gradle

Asegúrese de que las siguientes dependencias estén en su gradle.buildarchivo de aplicación :

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

Puede actualizar los números de versión a lo que sea más actual .

Crear diseño de actividad

Agregue el RecyclerViewa su diseño 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>

Crear diseño de celda de cuadrícula

Cada celda de nuestra RecyclerViewcuadrícula solo tendrá una sola TextView. Cree un nuevo archivo de recursos de diseño.

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>

Crea el adaptador

El RecyclerViewnecesita un adaptador para poblar los puntos de vista de cada celda con sus datos. Crea un nuevo archivo 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);
    }
}

Notas

  • Aunque no es estrictamente necesario, incluí la funcionalidad para escuchar eventos de clic en las celdas. Esto estaba disponible en el antiguo GridViewy es una necesidad común. Puede eliminar este código si no lo necesita.

Inicializar RecyclerView en actividad

Agregue el siguiente código a su actividad principal.

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

Notas

  • Observe que la actividad implementa lo ItemClickListenerque definimos en nuestro adaptador. Esto nos permite manejar eventos de clic de celda en onItemClick.

Terminado

Eso es. Debería poder ejecutar su proyecto ahora y obtener algo similar a la imagen en la parte superior.

Continuando

Esquinas redondeadas

Columnas autoajustables

Estudio adicional

Suragch
fuente
2
@ MarianPaździoch, Sí, acabo de hacer esto como un ejemplo mínimo. Definitivamente podría usar algún trabajo de embellecimiento. Intentaré actualizar esta respuesta en algún momento en el futuro.
Suragch
1
Me conecté solo para señalar que personas como usted han mantenido vivo este portal y pateando .i estaba atrapado en esto durante dos días antes de ver esta solución. muchas gracias
VarunJoshi129
1
@androiddeveloper, los elementos de la cuadrícula se disponen de izquierda a derecha, de arriba a abajo. El desplazamiento es vertical cuando hay más elementos de los que caben en la pantalla.
Suragch
13
Futuros lectores, déjenme ahorrarles algo de tiempo, la clave esrecyclerView.setLayoutManager(new GridLayoutManager(this, numberOfColumns));
daka
1
@daka, buen punto. Edité mi respuesta para incluir esto al principio.
Suragch
7

Aunque me gusta y aprecio la respuesta de Suragch , me gustaría dejar una nota porque descubrí que codificar el Adaptador ( MyRecyclerViewAdapter) para definir y exponer el método Listener onItemClickno es la mejor manera de hacerlo, debido a que no utiliza la encapsulación de clase correctamente. Entonces, mi sugerencia es dejar que el Adaptador maneje las operaciones de Escucha únicamente (¡ese es su propósito!) Y separarlas de la Actividad que usa el Adaptador ( MainActivity). Así es como establecería la clase Adaptador:

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

Tenga en cuenta que el onItemClickmétodo ahora definido en MyRecyclerViewAdapterese es el lugar donde desea codificar sus tareas para el evento / acción recibido.

Solo hay que hacer un pequeño cambio para completar esta transformación: la Actividad ya no necesita implementarse MyRecyclerViewAdapter.ItemClickListener, porque ahora eso lo hace completamente el Adaptador . Esta sería entonces la modificación final:

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);
    }
}
jonypera
fuente
3
¿Qué sucede si la actividad necesita escuchar los eventos de clic? por ejemplo, pasar los datos al presentador, haciendo algo de lógica basada en el apartado hace clic, seguimiento, etc.
Ahmad Fadli
Estoy de acuerdo en que el Adaptador debe manejar los eventos de clic, ya que tiene los elementos con los datos. @AhmadFadli si necesita hacer algún trabajo en el host del adaptador (un Fragmento o Actividad), debe crear una interfaz de devolución de llamada con los métodos que necesita. Su anfitrión implementa esta interfaz. Y luego pasa una instancia de su host al constructor de Adapter. Al tener la instancia del host, puede llamar sus métodos cuando lo necesite desde su adaptador. Y a su host nos llaman las devoluciones de llamada. Esto se usa a menudo cuando necesita trabajar con ActionMode. Cuando haces clic largo para seleccionar elementos y usar los botones de la barra de acción.
Kirill Karmazin
No estoy de acuerdo y creo que los eventos de clic deben procesarse en el alojamiento Activity. Debido a que sólo se de clic oyente puede saber acerca de los Activitypuntos de vista y otros Fragments, Activitiesetc. El adaptador sólo puede enviar eventos de click a nivel superior. Debe tener la interfaz ItemClickListener con tantos eventos, como pueden producir muchas vistas del adaptador de eventos. Esta solución se escribió incluso antes: stackoverflow.com/a/40563598/2914140 .
CoolMind
4

Debe configurar su administrador de diseño de la vista del reciclador en el modo de cuadrícula, para ello, simplemente cambie su código cuando desee configurar su RecyclerView LayoutManager:

Nota: reemplace el recuento de columnas que desee con ### HELP ###

   recyclerView.setLayoutManager(new GridLayoutManager(getActivity(),###HELP###));
MR Coder
fuente