GridView

De MediaWiki
Ir a la navegación Ir a la búsqueda

Introdución

  • A vista GridView ofrece a posibilidade de amosar ao usuario un conxunto de datos para ser seleccionados en forma tabular.

Gridview.png



Introdución

  • O RecyclerView ten como función amosar ao usuario en forma de lista con scroll.
A diferenza con respecto ao ListView ou GridView vistos ata o de agora, é que con cantidades altas de datos, este compoñente é moito máis eficiente que os dous anteriores.
  • O RecyclerView xera todos os elementos da lista que se manden inicialmente, pero se engadimos novos elementos ou borramos non ten que volver a recrear toda a lista, soamente recrea os que sufriran algún cambio.
  • En operacións de eliminación, o RecyclerView reutiliza os view´s que conforman cada un dos elementos da lista (de aí ven o seu nome 'recycler') de tal forma que ao engadir novos elementos 'reutiliza' os view´s creados previamente para engadir os novos datos.
  • Un ArrayAdapter xera os views de todos os elementos da lista estean visualmente ou non visibles na lista e se hai algún cambio ten que volver a recrealos todos.


  • Por outra banda, o compoñente CardView serve para deseñar a forma en como se presenta a información de cada compoñente de lista.
Por exemplo, podemos indicar que cada elemento da lista que se amosa facendo uso do RecyclerView estea formado por unha ImageView e un TextView.
Este compoñente permite presentar información en forma de grupos, empregando unha forma de 'tarxeta'.
PDM investigac 4.jpg


PDM CardView 1.jpg
Exemplo de cardview obtida deste enlace.



Engadindo as librerías

  • O primeiro que temas que facer é engadir as librerías que van permitir que fagamos uso de ditos compoñentes.
Se arrastrades graficamente os compoñentes, ditas librerías xa que engaden automaticamente ao arquivo build.gradle (nivel de módulo)
1     implementation 'com.android.support:recyclerview-v7:28.0.0'
2     implementation 'com.android.support:cardview-v7:28.0.0'



Caso Práctico

Se non o temos creado antes, crea un paquete de nome Adaptadores como un subpaquete do teu paquete principal.
Dentro do paquete Adaptadores, crearemos un novo paquete de nome: Checkboxes.


  • Imos crear a seguinte Activity:
PDM CardView 7.jpg


  • Podedes descargar as imaxes dos planetas:
Archivo:Planetas.zip



  • Dentro do paquete Adaptadores crear unha nova 'Empty Activity' de nome: UD04_01_RecycleViewCardView de tipo Launcher e sen compatibilidade.
Modifica o arquivo AndroidManifiest.xml e engade unha label á activity como xa vimos na creación do proxecto base.
O layout asociado a dita activity terá un RecycleView ocupando o 100% do espazo cun margin superior de 24dp´s:
 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 xmlns:app="http://schemas.android.com/apk/res-auto"
 4 xmlns:tools="http://schemas.android.com/tools"
 5 android:layout_width="match_parent"
 6 android:layout_height="match_parent"
 7 tools:context=".UD2.Adaptadores.UD04_01_RecycleViewCardView">
 8 
 9 <android.support.v7.widget.RecyclerView
10     android:id="@+id/rvwRecycleView"
11     android:layout_width="match_parent"
12     android:layout_height="match_parent"
13     android:layout_marginTop="24dp"
14     app:layout_constraintBottom_toBottomOf="parent"
15     app:layout_constraintEnd_toEndOf="parent"
16     app:layout_constraintStart_toStartOf="parent"
17     app:layout_constraintTop_toTopOf="parent" />
18 </android.support.constraint.ConstraintLayout>



Creando o deseño do CardView

  • O CardView ven ser coma un layout que representa como se van visualizar cada unha das filas que conforman o RecycleView.
Polo tanto creamos un arquivo en /res/layout, un arquivo de nome 'card_layout_ud04_01_recycleviewcardview'.
PDM CardView 3.jpg
Agora engadimos o layout que queremos que teña cada fila e os compoñentes que queiramos que aparezan.
Terá que engadirse o layout dentro da etiqueta <CardView>.
No exemplo imos facer que apareza unha imaxe e un texto asociado a dita imaxe e imos empregar un ContraintLayout para facelo (se podería empregar calquera dos que vimos).
Fixarse que:
  • Na altura do layout e do CardView, imos poñer 'wrap_content' para que soamente ocupe o alto do compoñente que sexa máis alto (neste exemplo a foto).
  • O ancho e alto da imaxe vai ser de 100x100 dp´s e desprazada á esquerda.
  • O texto ocupa todo o espazo restante e está centrado con respecto á foto. Ten unha separación esquerda con respecto á foto e un tamaño de texto grande.
  • O texto ten unha cor vermella defina por nos nun arquivo de recurso /res/values/


 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 3     xmlns:app="http://schemas.android.com/apk/res-auto"
 4     xmlns:tools="http://schemas.android.com/tools"
 5     android:layout_width="match_parent" android:layout_height="wrap_content">
 6 
 7     <android.support.constraint.ConstraintLayout
 8         android:id="@+id/ConstraintLayout"
 9         android:layout_width="match_parent"
10         android:layout_height="wrap_content">
11 
12         <ImageView
13             android:id="@+id/imgImaxe_UD04_01_CardLayout"
14             android:layout_width="100dp"
15             android:layout_height="100dp"
16             android:contentDescription="Imaxe"
17             app:layout_constraintEnd_toStartOf="@+id/tvTexto_UD04_01_CardView"
18             app:layout_constraintStart_toStartOf="parent"
19             app:layout_constraintTop_toTopOf="parent"
20             app:srcCompat="@mipmap/ic_launcher2" />
21 
22         <TextView
23             android:id="@+id/tvTexto_UD04_01_CardView"
24             android:layout_width="0dp"
25             android:layout_height="wrap_content"
26             android:paddingStart="5dp"
27             android:text="Texto a amosar por fila"
28             android:textColor="@color/corvermello"
29             android:textSize="24sp"
30             app:layout_constraintBottom_toBottomOf="parent"
31             app:layout_constraintEnd_toEndOf="parent"
32             app:layout_constraintStart_toEndOf="@+id/imgImaxe_UD04_01_CardLayout"
33             app:layout_constraintTop_toTopOf="parent" />
34     </android.support.constraint.ConstraintLayout>
35 </android.support.v7.widget.CardView>


  • Fixarse que temos unha serie de propiedades específicas do cardview:
PDM CardView 4.jpg
Podedes consultar a lista completa neste enlace.
Entre as que imos modificar están:
  • cardBackgroundColor: Cor de fondo da tarxeta
  • cardCornerRadius: O perfil redondeado das tarxetas
  • cardElevation: Elevación (Material Design)
  • contentPadding: Padding de todo o contido que está dentro da tarxeta.
  • Para separar unha tarxeta de outra podemos facer uso dos margin a nivel de CardView



 1 <?xml version="1.0" encoding="utf-8"?>
 2 <?xml version="1.0" encoding="utf-8"?>
 3 <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:app="http://schemas.android.com/apk/res-auto"
 5     xmlns:tools="http://schemas.android.com/tools"
 6     android:layout_width="match_parent"
 7     android:layout_height="wrap_content"
 8     android:layout_margin="5dp"
 9     app:cardBackgroundColor="#81C784"
10     app:cardCornerRadius="12dp"
11     app:cardElevation="3dp"
12     app:contentPadding="4dp">
13 
14     <android.support.constraint.ConstraintLayout
15         android:id="@+id/ConstraintLayout"
16         android:layout_width="match_parent"
17         android:layout_height="wrap_content">
18 
19         <ImageView
20             android:id="@+id/imgImaxe_UD04_01_CardLayout"
21             android:layout_width="100dp"
22             android:layout_height="100dp"
23             android:contentDescription="Imaxe"
24             app:layout_constraintEnd_toStartOf="@+id/tvTexto_UD04_01_CardView"
25             app:layout_constraintStart_toStartOf="parent"
26             app:layout_constraintTop_toTopOf="parent"
27             app:srcCompat="@mipmap/ic_launcher2" />
28 
29         <TextView
30             android:id="@+id/tvTexto_UD04_01_CardView"
31             android:layout_width="0dp"
32             android:layout_height="wrap_content"
33             android:paddingStart="5dp"
34             android:text="Texto a amosar por fila"
35             android:textColor="@color/corvermello"
36             android:textSize="24sp"
37             app:layout_constraintBottom_toBottomOf="parent"
38             app:layout_constraintEnd_toEndOf="parent"
39             app:layout_constraintStart_toEndOf="@+id/imgImaxe_UD04_01_CardLayout"
40             app:layout_constraintTop_toTopOf="parent" />
41     </android.support.constraint.ConstraintLayout>
42 </android.support.v7.widget.CardView>



Creando o Adaptador

  • Un adaptador:
    • é un elemento intermediario entre unha fonte de datos (XML, Arrays, Ficheiros, BBDD) e un interface de usuario que amosa eses datos, por exemplo un Spinner, unha lista de Selección, etc.
    • Por cada dato crea unha View e a representa.
    • É o responsable de xerar todos os elementos de representación asociados aos datos. Imaxinar que cada ítem estivera formado por dous subcompoñentes: nome de persoa e foto. O adaptador debe ser quen de poder representar iso.
  • No caso do RecycleView, vai empregar un adaptador que deriva da clase RecycleView.Adapter.
Polo tanto imos crear unha clase que derive dela.
PDM CardView 5.jpg


Ao facelo dará un erro no que se nos informa que debemos de implementar unha serie de métodos.
 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 import android.support.annotation.NonNull;
 4 import android.support.v7.widget.RecyclerView;
 5 import android.view.ViewGroup;
 6 
 7 public class RecycleViewAdapter_UD04_01_RecycleViewCardView extends RecyclerView.Adapter {
 8     @NonNull
 9     @Override
10     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
11         return null;
12     }
13 
14     @Override
15     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
16 
17     }
18 
19     @Override
20     public int getItemCount() {
21         return 0;
22     }
23 }
Como vemos se implementan os seguintes métodos:
  • getItemCount(): Ten que devolver o número de elementos que se van visualizar na lista.
  • onCreateViewHolder(): Este método ten que devolver un obxecto da clase ViewHolder a cal é empregada para visualizar o contido da lista. Será na clase ViewHolder onde 'cargaremos' o deseño de fila feito no paso anterior.
  • onBindViewHolder(): Este método recibe o ViewHolder do método anterior e asociamos a cada compoñente gráfico de dito View o dato que queremos que visualice.


  • Neste adaptador é onde teremos que 'obter' os datos que conformarán as filas.
Poderíamos obtelos dunha consulta a unha base de datos ou de calquera outra fonte (internet, un arquivo,...).
No exemplo imos definilos localmente...
No noso exemplo tedes que descargar imaxes de varios planetas (eu o fixen con 5) e gardalas no cartafol /res/drawable
Os datos serán os seguintes (adaptalos ao voso caso):
 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 import android.support.annotation.NonNull;
 4 import android.support.v7.widget.RecyclerView;
 5 import android.view.ViewGroup;
 6 
 7 public class RecycleViewAdapter_UD04_01_RecycleViewCardView extends RecyclerView.Adapter {
 8 
 9     private String[] textos = {"Mercurio","Venus","Tierra","Jupiter","Saturno"};
10     private int[] imaxes = {R.drawable.mercurio,R.drawable.venus,R.drawable.tierra,R.drawable.jupiter,R.drawable.saturno};
11 
12     @NonNull
13     @Override
14     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
15         return null;
16     }
17     .......
Nota: Fixarse na orde e como o número de elemento dentro do array se corresponde nos dous arrays có mesmo concepto (na posición 0 do array está o texto e a imaxe de Mercurio).



Definindo a clase ViewHolder

  • Lembrar que o ViewHolder vai ser o que emprege o adaptador para 'cargar' os datos nos elementos gráficos que conforman cada fila (no noso exemplo, unha imaxe e un texto).
Creamos por tanto unha clase que derive de RecycleView.ViewHolder (poderíamos creala dentro da clase RecycleAdapter) :
PDM CardView 6.jpg
Ao facelo daranos un erro de que hai que implementar un constructor. O facemos có asistente.
 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 import android.support.annotation.NonNull;
 4 import android.support.v7.widget.RecyclerView;
 5 import android.view.View;
 6 
 7 public class ViewHolder_UD04_01_RecycleViewCardView extends RecyclerView.ViewHolder {
 8 
 9     public ViewHolder_UD04_01_RecycleViewCardView(@NonNull View itemView) {
10         super(itemView);
11     }
12 }


Esta clase vai ser a que nos permite acceder aos elementos gráficos definidos no CardView (o que está definido no layout que representa cada fila).
Desta forma dende o Adapter imos poder cargar con datos os elementos gráficos.
Ao constructor de esta clase vai vir (o veremos no seguinte paso) unha instancia de 'card_layout_ud04_01_recycleviewcardview'.
Simplemente referenciaremos ditos controis para poder manexalos dende o adaptador.
Modificamos o código polo seguinte:
 1 public class ViewHolder_UD04_01_RecycleViewCardView extends RecyclerView.ViewHolder {
 2 
 3     public ImageView itemImaxe;
 4     public TextView itemTexto;
 5 
 6     public ViewHolder_UD04_01_RecycleViewCardView(@NonNull View itemView) {
 7         super(itemView);
 8 
 9         itemImaxe = itemView.findViewById(R.id.imgImaxe_UD04_01_CardLayout);
10         itemTexto = itemView.findViewById(R.id.tvTexto_UD04_01_CardView);
11     }
12 }



Completando o funcionamento do adaptador


Instanciando o ViewHolder

  • Como dixemos antes, o método onCreateViewHolder ten que 'devolver' un obxecto ViewHolder no que se atopan os elementos gráficos que conforman a fila.
A clase na que se vai basear van ser a que fixemos nos pasos anteriores e que derivaba de ViewHolder (ViewHolder_UD04_01_RecycleViewCardView).
Para facelo temos que realizar un proceso de 'inflar' o layout que conforma cada fila (card_layout_ud04_01_recycleviewcardview.xml) a un obxecto da clase View.
E despois crear un obxecto da clase ViewHolder_UD04_01_RecycleViewCardView en base ao View obtido anteriormente.


  • Para facer isto primeiro temos que 'converter' o layout onde están definidos os elementos gráficos que conforman a fila a un View.
Para iso empregamos a clase LayoutInflater.
  • Primeiro obtemos unha referencia a dita clase dunha das seguintes forma:
  • LayoutInflater mInflater = (LayoutInflater) viewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
  • LayoutInflater mInflater = LayoutInflater.from(viewgroup.getContext());
  • Despois chamamos ao método 'inflate' para que devolva por programación unha referencia ao layout onde están definidos os elementos gráficos da fila (un View):
  • View v = mInflater.inflate(R.layout.card_layout_ud04_01_recycleviewcardview,viewGroup,false);
  • E por último creamos o ViewHolder creando un obxecto da clase ViewHolder creada por nos previamente (ViewHolder_UD04_01_RecycleViewCardView) e pasando como parámetro no constructor o View anterior:
  • RecyclerView.ViewHolder viewHolder = new ViewHolder_UD04_01_RecycleViewCardView(v);


 1     @NonNull
 2     @Override
 3     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
 4 
 5         LayoutInflater mInflater = (LayoutInflater) viewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
 6         //View view = (LayoutInflater.from(viewGroup.getContext()))
 7         View v = mInflater.inflate(R.layout.card_layout_ud04_01_recycleviewcardview,viewGroup,false);
 8         RecyclerView.ViewHolder viewHolder = new ViewHolder_UD04_01_RecycleViewCardView(v);
 9 
10         return viewHolder;
11     }



Engadindo datos ao ViewHolder

  • Os datos, tedes que lembrar, que están definidos en dous arrays, pero podedes ter un único arrays de obxectos dunha clase e recollelos dese array.
O que si ides ter sempre é a lo menos un array de elementos con información.
  • Outro método que vimos que se creaba cando creamos o RecycleView.Adapter era o onBindViewHolder.
Neste método imos a 'meter' os datos que queremos que aparezan no ViewHolder creado no paso anterior.^:
Para iso temos que empregar o parámetro 'i' que indica o número de elemento do array sobre o que temos que buscar a información e despois asociala aos elementos gráficos.
Por outra banda como o obxecto da clase ViewHolder pertence realmente á clase ViewHolder_UD04_01_RecycleViewCardView, podemos acceder aos seus elementos gráficos xa que están declarados como 'public' na definición da clase.
  • O código queda como o seguinte:
1     @Override
2     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
3 
4         ViewHolder_UD04_01_RecycleViewCardView viewHolderMeu = (ViewHolder_UD04_01_RecycleViewCardView) viewHolder;
5         viewHolderMeu.itemImaxe.setImageResource(imaxes[i]);
6         viewHolderMeu.itemTexto.setText(textos[i]);
7     }



Implementando o método getItemCount

  • Como indicamos anteriormente, dito método ten que devolver o número de elementos da lista, que debe de coincidir có número de elementos do array onde están os datos.
Polo tanto:
1     @Override
2     public int getItemCount() {
3         return textos.length;
4     }



Paso final

  • Por último temos que facer dúas cousas:
  • 1º Paso: O RecycleView necesita un Layout Manager que lle diga como van distribuídos cada un dos elementos que van aparecer.
A forma máis común de facelo é cun LinearLayout e que vaian en forma de fila, pero podemos empregar outras distribucións.


PDM CardView 8.jpg
Na imaxe anterior vemos:
  • Exemplo de LinearLayout con distribución vertical (por defecto):
  • RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
  • Exemplo de LinearLayout con distribución horizontal:
  • RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this,LinearLayoutManager.HORIZONTAL,false);
  • Exemplo de GridLayout con dúas columnas:
  • RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this,2);
Unha vez creado o LayoutManager hai que asocialo ao RecycleView.
  • 2º Paso: Hai que crear unha instancia do adaptador creado por nos (RecycleViewAdapter_UD04_01_RecycleViewCardView) e asocialo ao RecycleView.


 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 import android.support.v7.app.AppCompatActivity;
 4 import android.os.Bundle;
 5 import android.support.v7.widget.GridLayoutManager;
 6 import android.support.v7.widget.LinearLayoutManager;
 7 import android.support.v7.widget.RecyclerView;
 8 
 9 import cifprodolfoucha.cursoandroid.aprendiendo.R;
10 
11 public class UD04_01_RecycleViewCardView extends AppCompatActivity {
12 
13     @Override
14     protected void onCreate(Bundle savedInstanceState) {
15         super.onCreate(savedInstanceState);
16         setContentView(R.layout.activity_ud04_01__recycle_view_card_view);
17 
18         RecycleViewAdapter_UD04_01_RecycleViewCardView recycleAdapter = new RecycleViewAdapter_UD04_01_RecycleViewCardView();
19 
20         RecyclerView.LayoutManager layoutManager = new GridLayoutManager(this,2);
21         RecyclerView recyclerView = findViewById(R.id.rvwRecycleView);
22         recyclerView.setLayoutManager(layoutManager);
23         recyclerView.setAdapter(recycleAdapter);
24 
25     }
26 }




Xestionar eventos de Click´s sobre os elementos

  • Podemos modificar un par de propiedades do layout asociado ao cardview para que cando prememos apareza un efecto de 'selección' sobre o elemento premido.
 1 <?xml version="1.0" encoding="utf-8"?>
 2 
 3 <android.support.v7.widget.CardView xmlns:android="http://schemas.android.com/apk/res/android"
 4     xmlns:app="http://schemas.android.com/apk/res-auto"
 5     xmlns:tools="http://schemas.android.com/tools"
 6     android:layout_width="match_parent"
 7     android:layout_height="wrap_content"
 8     android:layout_margin="5dp"
 9     android:foreground="?android:attr/selectableItemBackground"
10     android:clickable="true"
11     android:focusable="true"
12     app:cardBackgroundColor="#81C784"
13     app:cardCornerRadius="12dp"
14     app:cardElevation="3dp"
15     app:contentPadding="4dp">
16 
17      .....


  • Podedes ler máis acerca deste tipo de animacións neste enlace.



  • Se queremos xestionar o evento do Click o podemos facer:
  • Sobre todo o conxunto de elementos que conforman a interface gráfica da fila.
  • Sobre algún dos elementos que conforman a interface gráfica da fila.


  • Caso a) Xestión do Click sobre todo o conxunto No primeiro caso temos que facer uso do obxecto itemView que se atopa dispoñible na clase ViewHolder e que representa o CardView con todo:
 1 public class ViewHolder_UD04_01_RecycleViewCardView extends RecyclerView.ViewHolder {
 2 
 3     public ImageView itemImaxe;
 4     public TextView itemTexto;
 5 
 6     public ViewHolder_UD04_01_RecycleViewCardView(@NonNull final View itemView) {
 7         super(itemView);
 8 
 9         itemImaxe = itemView.findViewById(R.id.imgImaxe_UD04_01_CardLayout);
10         itemTexto = itemView.findViewById(R.id.tvTexto_UD04_01_CardView);
11 
12         itemView.setOnClickListener(new View.OnClickListener() {
13             @Override
14             public void onClick(View v) {
15                 int posicion = getAdapterPosition();
16                 Toast.makeText(v.getContext(),"Pulsado elemento " + posicion + " da lista.",Toast.LENGTH_SHORT).show();
17             }
18         });
19     }
20 }
  • Liña 15: Dispoñemos do método getAdapterPosition() que nos devolve a posición do elemento seleccionado da lista.


Nota: Isto mesmo o podemos facer dende a clase 'RecycleViewAdapter_UD04_01_RecycleViewCardView' xa que lembrar que o view que pasamos como parámetro ao constructor do ViewHolder é o que empregamos no exemplo anterior.


  • Caso b) Xestión do Click sobre un view do conxunto
Neste caso debemos de rexistrar o evento de Click sobre o view que nos interese.
O podemos facer na clase ViewHolder ou na clase RecycleViewAdapter_UD04_01_RecycleViewCardView.
 1 public class ViewHolder_UD04_01_RecycleViewCardView extends RecyclerView.ViewHolder {
 2 
 3     public ImageView itemImaxe;
 4     public TextView itemTexto;
 5 
 6     public ViewHolder_UD04_01_RecycleViewCardView(@NonNull final View itemView) {
 7         super(itemView);
 8 
 9         itemImaxe = itemView.findViewById(R.id.imgImaxe_UD04_01_CardLayout);
10         itemTexto = itemView.findViewById(R.id.tvTexto_UD04_01_CardView);
11 
12         itemImaxe.setOnClickListener(new View.OnClickListener() {
13             @Override
14             public void onClick(View v) {
15                 int posicion = getAdapterPosition();
16                 Toast.makeText(v.getContext(),"Pulsado elemento " + posicion + " da lista.",Toast.LENGTH_SHORT).show();
17             }
18         });
19     }
20 }
Nota: Fixarse que agora soamente responderá ao evento de facer click sobre a imaxe.



Pasando información

  • Todos view´s dispoñen dunha propiedade Tag asociada na que se pode gardar calquera tipo de información, xa que permite gardar un obxecto de calquera clase.
Polo tanto podemos empregar dita propiedade para 'asociar' información a un view.
Nun exemplo real, teríamos unha clase onde gardaríamos os datos de cada elemento da lista. Por exemplo, unha clase Planeta, con datos coma o nome, ruta e nome da imaxe na sd, dimensións, velocidade de rotación,...e moitos máis datos.
No adaptador do RecycleView teríamos un ArrayList da clase Planeta e non dous arrays separados como temos agora.
Na lista soamente aparecería a imaxe e nome do planeta, pero nos querremos acceder a todos os seus datos e non soamente aos que aparecen 'visualmente'.


  • Imos modificar o exemplo para empregar esta clase Planeta:
Arquivo: Planeta_UD04_01_RecycleViewCardView.java
 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 public class Planeta_UD04_01_RecycleViewCardView {
 4 
 5     int id;
 6     String nombre;
 7     boolean habitable;
 8     int fotoId;
 9     
10     public Planeta_UD04_01_RecycleViewCardView(int id, String nombre, boolean habitable,int fotoId){
11         this.id = id;
12         this.nombre = nombre;
13         this.habitable = habitable;
14         this.fotoId = fotoId;
15     }
16 
17     public int getId() {
18         return id;
19     }
20 
21     public String getNombre() {
22         return nombre;
23     }
24 
25     public boolean isHabitable() {
26         return habitable;
27     }
28 
29     public int getFotoId() {
30         return fotoId;
31     }    
32 
33     @Override
34     public String toString(){
35         return "Planeta con id " + id + " e de nome " + nome + (habitable ? " é habitable." : " non é habitable");
36     }
37    
38 }



  • Modificamos a clase adaptadora e empregaremos un ArrayList de obxectos pertencentes á clase anterior.
Estes datos poderían vir dunha base de datos...
Clase RecycleViewAdapter_UD04_01_RecycleViewCardView
 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 import android.content.Context;
 4 import android.support.annotation.NonNull;
 5 import android.support.v7.widget.RecyclerView;
 6 import android.view.LayoutInflater;
 7 import android.view.View;
 8 import android.view.ViewGroup;
 9 
10 import java.util.ArrayList;
11 
12 import cifprodolfoucha.cursoandroid.aprendiendo.R;
13 
14 public class RecycleViewAdapter_UD04_01_RecycleViewCardView extends RecyclerView.Adapter {
15 
16     private ArrayList<Planeta_UD04_01_RecycleViewCardView>planetas = new ArrayList<Planeta_UD04_01_RecycleViewCardView>();
17 
18 
19     public RecycleViewAdapter_UD04_01_RecycleViewCardView(){
20 
21         planetas.add(new Planeta_UD04_01_RecycleViewCardView(1,"MERCURIO",false,R.drawable.mercurio));
22         planetas.add(new Planeta_UD04_01_RecycleViewCardView(2,"VENUS",false,R.drawable.venus));
23         planetas.add(new Planeta_UD04_01_RecycleViewCardView(3,"TIERRA",false,R.drawable.tierra));
24         planetas.add(new Planeta_UD04_01_RecycleViewCardView(4,"JUPITER",false,R.drawable.jupiter));
25         planetas.add(new Planeta_UD04_01_RecycleViewCardView(5,"SATURNO",false,R.drawable.saturno));
26 
27     }
28 
29     @NonNull
30     @Override
31     public RecyclerView.ViewHolder onCreateViewHolder(@NonNull ViewGroup viewGroup, int i) {
32 
33         LayoutInflater mInflater = (LayoutInflater) viewGroup.getContext().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
34         //View view = (LayoutInflater.from(viewGroup.getContext()))
35         View v = mInflater.inflate(R.layout.card_layout_ud04_01_recycleviewcardview,viewGroup,false);
36         RecyclerView.ViewHolder viewHolder = new ViewHolder_UD04_01_RecycleViewCardView(v);
37 
38         return viewHolder;
39     }
40 
41     @Override
42     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
43 
44         ViewHolder_UD04_01_RecycleViewCardView viewHolderMeu = (ViewHolder_UD04_01_RecycleViewCardView) viewHolder;
45         viewHolderMeu.itemImaxe.setImageResource(planetas.get(i).getFotoId());
46         viewHolderMeu.itemTexto.setText(planetas.get(i).getNombre());
47     }
48 
49     @Override
50     public int getItemCount() {
51         return planetas.size();
52     }
53 }


  • Agora queremos pasar dalgunha forma o obxecto seleccionado (e fixarse que digo obxecto) ao view, de tal forma que cando preme sobre o elemento da lista, poida recuperar a información completa do obxecto.
Para iso facemos uso do método setTag() e getTag().


Clase RecycleViewAdapter_UD04_01_RecycleViewCardView

1     @Override
2     public void onBindViewHolder(@NonNull RecyclerView.ViewHolder viewHolder, int i) {
3 
4         ViewHolder_UD04_01_RecycleViewCardView viewHolderMeu = (ViewHolder_UD04_01_RecycleViewCardView) viewHolder;
5 
6         viewHolderMeu.itemView.setTag(planetas.get(i));
7         viewHolderMeu.itemImaxe.setImageResource(planetas.get(i).getFotoId());
8         viewHolderMeu.itemTexto.setText(planetas.get(i).getNome());
9     }
Nota: Non se pode facer no método 'onCreateViewHolder' xa que o 'int i' non se corresponde có índice do elemento que vai visualizarse.

Clase ViewHolder_UD04_01_RecycleViewCardView

 1 public class ViewHolder_UD04_01_RecycleViewCardView extends RecyclerView.ViewHolder {
 2 
 3     public ImageView itemImaxe;
 4     public TextView itemTexto;
 5 
 6     public ViewHolder_UD04_01_RecycleViewCardView(@NonNull final View itemView) {
 7         super(itemView);
 8 
 9         itemImaxe = itemView.findViewById(R.id.imgImaxe_UD04_01_CardLayout);
10         itemTexto = itemView.findViewById(R.id.tvTexto_UD04_01_CardView);
11 
12         itemView.setOnClickListener(new View.OnClickListener() {
13             @Override
14             public void onClick(View v) {
15                 Planeta_UD04_01_RecycleViewCardView planetaSeleccionado = (Planeta_UD04_01_RecycleViewCardView) v.getTag();
16 
17                 Toast.makeText(v.getContext(),"Pulsado elemento " + getAdapterPosition() + " da lista.\n" + planetaSeleccionado,Toast.LENGTH_SHORT).show();
18             }
19         });
20     }
21 }



Engadindo-Borrando-Actualizando elementos

  • Se facemos calquera destas operacións teremos que informar ao adaptador que hai cambios para que volva a cargar os elementos da lista.
Para iso teremos que chamar o método notifyDataSetChanged().
O malo que ten esta chamada é que é pouco eficiente xa que reconstrúe todos os view´s do RecyclerView.
Normalmente se chama cando temos moitas operacións ou cambios na estructura de elementos.
É mais eficiente chamar aos seguintes métodos:
  • notifyItemChanged(int)
  • notifyItemInserted(int)
  • notifyItemRemoved(int)
  • notifyItemRangeChanged(int, int)
  • notifyItemRangeInserted(int, int)
  • notifyItemRangeRemoved(int, int)
Podedes consultar o que fai cada un neste enlace.


  • Seguindo có noso exemplo, imos agregar un botón á activity do RecyclerView (no meu caso engadín un FloatActionButton):

Layout activity_ud04_01_recycle_view_card_view

 1 <?xml version="1.0" encoding="utf-8"?>
 2 <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
 3 xmlns:app="http://schemas.android.com/apk/res-auto"
 4 xmlns:tools="http://schemas.android.com/tools"
 5 android:layout_width="match_parent"
 6 android:layout_height="match_parent"
 7 tools:context=".UD2.Adaptadores.UD04_01_RecycleViewCardView">
 8 
 9 <android.support.v7.widget.RecyclerView
10     android:id="@+id/rvwRecycleView"
11     android:layout_width="match_parent"
12     android:layout_height="match_parent"
13     android:layout_marginTop="24dp"
14     app:layout_constraintBottom_toBottomOf="parent"
15     app:layout_constraintEnd_toEndOf="parent"
16     app:layout_constraintStart_toStartOf="parent"
17     app:layout_constraintTop_toTopOf="parent" />
18 
19     <android.support.design.widget.FloatingActionButton
20         android:id="@+id/fabAdd_ud04_01_recyclecardview"
21         android:layout_width="wrap_content"
22         android:layout_height="wrap_content"
23         android:layout_margin="20dp"
24         android:clickable="true"
25         app:layout_constraintBottom_toBottomOf="parent"
26         app:layout_constraintEnd_toEndOf="parent"
27         app:srcCompat="@android:drawable/ic_input_add" />
28 </android.support.constraint.ConstraintLayout>


  • Agora os datos van vir dende a Activity e non van estar definidos no clase Adaptadora.
Para pasar os datos a dita clase, faremos uso do constructor da clase Adaptadora.

Clase RecycleViewAdapter_UD04_01_RecycleViewCardView

 1   ..........
 2   public class RecycleViewAdapter_UD04_01_RecycleViewCardView extends RecyclerView.Adapter {
 3 
 4     private ArrayList<Planeta_UD04_01_RecycleViewCardView>planetas;
 5 
 6     public RecycleViewAdapter_UD04_01_RecycleViewCardView(ArrayList<Planeta_UD04_01_RecycleViewCardView> planetas){
 7         this.planetas = planetas;
 8     }
 9 
10    .......


  • Na activity agora é onde teríamos que buscar os datos a unha base de datos, por exemplo, e pasalos á clase Adaptadora no constructor.

Activity UD04_01_RecycleViewCardView

 1 package cifprodolfoucha.cursoandroid.aprendiendo.UD2.Adaptadores;
 2 
 3 import android.support.design.widget.FloatingActionButton;
 4 import android.support.v7.app.AppCompatActivity;
 5 import android.os.Bundle;
 6 import android.support.v7.widget.GridLayoutManager;
 7 import android.support.v7.widget.LinearLayoutManager;
 8 import android.support.v7.widget.RecyclerView;
 9 import android.view.View;
10 import android.widget.AdapterView;
11 import android.widget.ListView;
12 
13 import java.util.ArrayList;
14 
15 import cifprodolfoucha.cursoandroid.aprendiendo.R;
16 
17 public class UD04_01_RecycleViewCardView extends AppCompatActivity {
18 
19     private RecycleViewAdapter_UD04_01_RecycleViewCardView recycleAdapter;
20 
21     private ArrayList<Planeta_UD04_01_RecycleViewCardView>planetas;
22 
23     private void inicializarDatosPlanetas(){
24 
25         planetas = new ArrayList<>();
26 
27         planetas.add(new Planeta_UD04_01_RecycleViewCardView(1,"MERCURIO",false,R.drawable.mercurio));
28         planetas.add(new Planeta_UD04_01_RecycleViewCardView(2,"VENUS",false,R.drawable.venus));
29         planetas.add(new Planeta_UD04_01_RecycleViewCardView(3,"TIERRA",false,R.drawable.tierra));
30         planetas.add(new Planeta_UD04_01_RecycleViewCardView(4,"JUPITER",false,R.drawable.jupiter));
31         planetas.add(new Planeta_UD04_01_RecycleViewCardView(5,"SATURNO",false,R.drawable.saturno));
32 
33     }
34     private void inicializarRecycleView(){
35 
36         recycleAdapter = new RecycleViewAdapter_UD04_01_RecycleViewCardView(planetas);
37 
38         RecyclerView.LayoutManager layoutManager = new LinearLayoutManager(this);
39         RecyclerView recyclerView = findViewById(R.id.rvwRecycleView);
40         recyclerView.setLayoutManager(layoutManager);
41         recyclerView.setAdapter(recycleAdapter);
42 
43 
44     }
45 
46     private void xestionarEventos(){
47 
48         FloatingActionButton fab = findViewById(R.id.fabAdd_ud04_01_recyclecardview);
49         fab.setOnClickListener(new View.OnClickListener() {
50             @Override
51             public void onClick(View v) {
52                 planetas.add(new Planeta_UD04_01_RecycleViewCardView(6,"URANO",false,R.drawable.ic_menu_camera));
53                 recycleAdapter.notifyItemInserted(planetas.size());
54             }
55         });
56 
57     }
58 
59 
60     @Override
61     protected void onCreate(Bundle savedInstanceState) {
62         super.onCreate(savedInstanceState);
63         setContentView(R.layout.activity_ud04_01__recycle_view_card_view);
64 
65         inicializarDatosPlanetas();
66         inicializarRecycleView();
67         xestionarEventos();
68 
69     }
70 }
  • Liña 36: Agora pasamos os datos ao Adaptador mediante o constructor.
  • Liña 53: Fixarse como agora, cando engadimos un novo planeta ao ArrayList, chamamos ao método notifyItemInserted, indicando a posición do elemento engadido.
Probar a cambiar o código e facer que cando se preme o botón se borre o primeiro planeta da lista.




Enlace a la página principal de la UD4

Enlace a la página principal del curso





-- Ángel D. Fernández González e Carlos Carrión Álvarez -- (2015).