Skip to content

Instantly share code, notes, and snippets.

@pedrojoya
Last active September 5, 2017 08:43
Show Gist options
  • Save pedrojoya/e32c12771c6b90a30026 to your computer and use it in GitHub Desktop.
Save pedrojoya/e32c12771c6b90a30026 to your computer and use it in GitHub Desktop.
Entrada RecyclerView
public class MainActivity extends AppCompatActivity implements AlumnosAdapter.OnItemClickListener {
private RecyclerView lstAlumnos;
private AlumnosAdapter mAdaptador;
@Override
protected void onCreate(Bundle savedInstanceState) {
...
initVistas();
}
// Obtiene e inicializa las vistas.
private void initVistas() {
lstAlumnos = (RecyclerView) findViewById(R.id.lstAlumnos);
lstAlumnos.setHasFixedSize(true);
mAdaptador = new AlumnosAdapter(DB.getAlumnos());
mAdaptador.setOnItemClickListener(this);
lstAlumnos.setAdapter(mAdaptador);
lstAlumnos.setLayoutManager(
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
lstAlumnos.setItemAnimator(new DefaultItemAnimator());
...
}
// Cuando se hace click sobre un elemento de la lista.
@Override
public void onItemClick(View view, Alumno alumno, int position) {
Toast.makeText(this, getString(R.string.ha_pulsado_sobre) + alumno.getNombre(),
Toast.LENGTH_SHORT).show();
}
...
}
// Adaptador para el recyclerview de alumnos.
// Extiende de RecyclerView.Adapter<Clase ViewHolder personalizado>.
public class AlumnosAdapter extends RecyclerView.Adapter<AlumnosAdapter.ViewHolder> {
private final ArrayList<Alumno> mDatos;
// Constructor. Recibe contexto y datos.
public AlumnosAdapter(ArrayList<Alumno> datos) {
mDatos = datos;
}
// Retorna el número de ítems de datos.
@Override
public int getItemCount() {
return mDatos.size();
}
// Cuando se debe crear una nueva vista que represente el ítem.
// Recibe la vista padre que lo contendrá (para el inflado) y el tipo de vista
// (por si hay varios tipos de ítems en el recyclerview).
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Se infla la especificación XML para obtener la vista correspondiente al ítem.
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_main_item, parent, false);
// Se crea y retorna el contenedor de subvistas de la vista correspondiente
// al ítem.
return new ViewHolder(itemView);
}
// Cuando se deben escribir los datos en las subvistas de la vista correspondiente
// al ítem. Recibe el contenedor y la posición del ítem en la colección de datos.
@Override
public void onBindViewHolder(AlumnosAdapter.ViewHolder holder, int position) {
// Se obtiene el alumno correspondiente.
Alumno alumno = mDatos.get(position);
// Se escriben los mDatos en la vista.
holder.lblNombre.setText(alumno.getNombre());
holder.lblDireccion.setText(alumno.getDireccion());
holder.imgFoto.setImageUri(alumno.getFoto());
}
// Contenedor de vistas para la vista correspondiente al elemento.
static class ViewHolder extends RecyclerView.ViewHolder {
// El contenedor de vistas para un elemento de la lista debe contener...
private final TextView lblNombre;
private final TextView lblDireccion;
private final ImageView imgFoto;
// El constructor recibe la vista correspondiente al elemento.
public ViewHolder(View itemView) {
// No olvidar llamar al constructor del padre.
super(itemView);
// Se obtienen las subvistas de la vista correspondiente al elemento.
lblNombre = (TextView) itemView.findViewById(R.id.lblNombre);
lblDireccion = (TextView) itemView.findViewById(R.id.lblDireccion);
imgFoto = (ImageView) itemView.findViewById(R.id.imgFoto);
}
}
}
recyclerView.addItemDecoration(
new DividerItemDecoration(this, LinearLayoutManager.VERTICAL));
public class AlumnosAdapter extends RecyclerView.Adapter<AlumnosAdapter.ViewHolder> {
private final ArrayList<Alumno> mDatos;
...
// Añade un elemento al adaptador.
public void addItem(Alumno alumno, int position) {
mDatos.add(position, alumno);
notifyItemInserted(position);
}
// Elimina un elemento del adaptador.
public void remove(ViewModel item) {
int position = mDatos.indexOf(item);
mDatos.remove(position);
notifyItemRemoved(position);
}
...
}
dependencies {
...
compile 'com.android.support:recyclerview-v7:X.X.X'
}
import android.content.Context;
import android.content.res.TypedArray;
import android.graphics.Canvas;
import android.graphics.Rect;
import android.graphics.drawable.Drawable;
import android.support.v7.widget.LinearLayoutManager;
import android.support.v7.widget.RecyclerView;
import android.view.View;
public class DividerItemDecoration extends RecyclerView.ItemDecoration {
private static final int[] ATTRS = new int[]{
android.R.attr.listDivider
};
public static final int HORIZONTAL_LIST = LinearLayoutManager.HORIZONTAL;
public static final int VERTICAL_LIST = LinearLayoutManager.VERTICAL;
private Drawable mDivider;
private int mOrientation;
public DividerItemDecoration(Context context, int orientation) {
final TypedArray a = context.obtainStyledAttributes(ATTRS);
mDivider = a.getDrawable(0);
a.recycle();
setOrientation(orientation);
}
public void setOrientation(int orientation) {
if (orientation != HORIZONTAL_LIST && orientation != VERTICAL_LIST) {
throw new IllegalArgumentException("invalid orientation");
}
mOrientation = orientation;
}
@Override
public void onDraw(Canvas c, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
drawVertical(c, parent);
} else {
drawHorizontal(c, parent);
}
}
public void drawVertical(Canvas c, RecyclerView parent) {
// Se respetará el padding izquierdo del recyclerview.
final int left = parent.getPaddingLeft();
// Se respetará también el padding izquierdo del recyclerview.
final int right = parent.getWidth() - parent.getPaddingRight();
// Para cada ítem.
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
// Se pintará debajo del ítem respetando el margen inferior.
final int top = child.getBottom() + params.bottomMargin;
// Hasta completar la altura del drawable que actúa como divisor.
final int bottom = top + mDivider.getIntrinsicHeight();
// Se establecen los límites del trazado y se dibuja en el canvas.
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
public void drawHorizontal(Canvas c, RecyclerView parent) {
final int top = parent.getPaddingTop();
final int bottom = parent.getHeight() - parent.getPaddingBottom();
final int childCount = parent.getChildCount();
for (int i = 0; i < childCount; i++) {
final View child = parent.getChildAt(i);
final RecyclerView.LayoutParams params = (RecyclerView.LayoutParams) child
.getLayoutParams();
final int left = child.getRight() + params.rightMargin;
final int right = left + mDivider.getIntrinsicHeight();
mDivider.setBounds(left, top, right, bottom);
mDivider.draw(c);
}
}
@Override
public void getItemOffsets(Rect outRect, int itemPosition, RecyclerView parent) {
if (mOrientation == VERTICAL_LIST) {
outRect.set(0, 0, 0, mDivider.getIntrinsicHeight());
} else {
outRect.set(0, 0, mDivider.getIntrinsicWidth(), 0);
}
}
}
public class AlumnosAdapter extends RecyclerView.Adapter<AlumnosAdapter.ViewHolder> {
private final ArrayList<Alumno> mDatos;
...
// Elimina un elemento de la lista.
public void removeItem(int position) {
mDatos.remove(position);
notifyItemRemoved(position);
}
// Intercambia dos elementos de la lista.
public void swapItems(int from, int to) {
// Se realiza el intercambio.
Collections.swap(mDatos, from, to);
// Se notifica el movimiento.
notifyItemMoved(from, to);
}
...
}
static class ElementoTipo1ViewHolder extends RecyclerView.ViewHolder {
// Vistas del layout del ElementoTipo1
private final TextView lbl1;
...
public void onBind(ElementoTipo1 elemento) {
// Se escriben los datos en la vista.
...
}
}
static class ElementoTipo2ViewHolder extends RecyclerView.ViewHolder {
// Vistas del layout del ElementoTipo2
private final TextView lbl2;
...
public void onBind(ElementoTipo2 elemento) {
// Se escriben los datos en la vista.
...
}
}
private RecyclerView.AdapterDataObserver mObservador;
private void checkAdapterIsEmpty () {
mEmptyView.setVisibility(mAdapter.getItemCount() == 0?View.VISIBLE:View.INVISIBLE);
}
// Llamado normalmente desde onCreate()
protected void configRecyclerView() {
...
// Se agrega un observador al adaptador para cuando se agreguen o eliminen datos en el
// adaptador se muestre u oculte la empty view en consecuencia.
mObservador = new RecyclerView.AdapterDataObserver() {
@Override
public void onItemRangeInserted(int positionStart, int itemCount) {
super.onItemRangeInserted(positionStart, itemCount);
checkAdapterIsEmpty();
}
@Override
public void onItemRangeRemoved(int positionStart, int itemCount) {
super.onItemRangeRemoved(positionStart, itemCount);
checkAdapterIsEmpty();
}
};
mAdaptador.registerAdapterDataObserver(mObservador);
...
lstAlumnos.setAdapter(mAdaptador);
// Tras asignar el adaptador se realiza la comprobación inicial.
checkAdapterIsEmpty();
}
@Override
protected void onDestroy() {
// Se quita el registro el observador.
mAdaptador.unregisterAdapterDataObserver(mObservador);
super.onDestroy();
}
@Override
public int getItemViewType(int position) {
// Retorna el tipo del elemento situado en dicha posición.
return mDatos.get(position).getType();
}
recyclerView.setAdapter(adaptador);
recyclerView.setLayoutManager(
new GridLayoutManager(this, 3, LinearLayoutManager.HORIZONTAL, false));
// Se crea el helper.
ItemTouchHelper itemTouchHelper = new ItemTouchHelper(
new ItemTouchHelper.SimpleCallback(
ItemTouchHelper.UP | ItemTouchHelper.DOWN,
ItemTouchHelper.RIGHT) {
// Cuando se detecta un gesto drag & drop.
@Override
public boolean onMove(RecyclerView recyclerView,
RecyclerView.ViewHolder viewHolder,
RecyclerView.ViewHolder target) {
final int fromPos = viewHolder.getAdapterPosition();
final int toPos = target.getAdapterPosition();
mAdaptador.swapItems(fromPos, toPos);
return true;
}
// Cuando se detecta un gesto swipe to dismiss.
@Override
public void onSwiped(RecyclerView.ViewHolder viewHolder, int direction) {
// Se elimina el elemento.
mAdaptador.removeItem(viewHolder.getAdapterPosition());
}
});
// Se enlaza con el RecyclerView.
itemTouchHelper.attachToRecyclerView(lstAlumnos);
<android.support.v7.widget.RecyclerView
android:id="@+id/lstAlumnos"
android:layout_width="match_parent"
android:layout_height="match_parent" />
recyclerView.setAdapter(adaptador);
recyclerView.setLayoutManager(
new LinearLayoutManager(this, LinearLayoutManager.VERTICAL, false));
SnapHelper snapHelper = new LinearSnapHelper();
snapHelper.attachToRecyclerView(recyclerView);
public abstract class ListItem implements Parcelable {
static final int TYPE_TIPO1 = 0;
static final int TYPE_TIPO2 = 1;
public abstract int getType();
}
class ElementoTipo1 extends ListItem implements Parcelable {
...
@Override
public int getType() {
return ListItem.TYPE_TIPO1;
}
...
}
class ElementoTipo2 extends ListItem implements Parcelable {
...
@Override
public int getType() {
return ListItem.TYPE_TIPO2;
}
...
}
@Override
public void onBindViewHolder(RecyclerView.ViewHolder holder, int position) {
if (mDatos.get(position).getType() == ListItem.TYPE_TIPO1) {
((ElementoTipo1ViewHolder) holder).onBind((ElementoTipo1) mDatos.get(position));
} else {
((ElementoTipo2ViewHolder) holder).onBind((ElementoTipo2) mDatos.get(position));
}
}
@Override
public RecyclerView.ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
switch(viewType) {
case ListItem.TYPE_TIPO1:
return onCreateElementoTipo1ViewHolder(parent);
default:
return onCreateElementoTipo2ViewHolder(parent);
}
}
private RecyclerView.ViewHolder onCreateElementoTipo1ViewHolder(ViewGroup parent) {
// Se infla el layout adecuado.
final View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_main_elemento_tipo1, parent, false);
// Se crea el contenedor de vistas adecuado.
final RecyclerView.ViewHolder viewHolder = new ElementoTipo1ViewHolder(itemView);
// Se retorna el contenedor.
return viewHolder;
}
private RecyclerView.ViewHolder onCreateElementoTipo2ViewHolder(ViewGroup parent) {
// Se infla el layout adecuado.
final View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_main_elemento_tipo2, parent, false);
// Se crea el contenedor de vistas adecuado.
final RecyclerView.ViewHolder viewHolder = new ElementoTipo2ViewHolder(itemView);
// Se retorna el contenedor.
return viewHolder;
}
public class AlumnosAdapter extends RecyclerView.Adapter<AlumnosAdapter.ViewHolder> {
// Interfaz que debe implementar el listener para cuando se haga click sobre un elemento.
public interface OnItemClickListener {
void onItemClick(View view, Alumno alumno, int position);
}
private final ArrayList<Alumno> mDatos;
private OnItemClickListener onItemClickListener;
...
// Cuando se debe crear una nueva vista que represente el ítem.
@Override
public ViewHolder onCreateViewHolder(ViewGroup parent, int viewType) {
// Se infla la especificación XML para obtener la vista del ítem.
View itemView = LayoutInflater.from(parent.getContext())
.inflate(R.layout.activity_main_item, parent, false);
// Se crea el contenedor de subvistas de la vista del ítem.
final ViewHolder viewHolder = new ViewHolder(itemView);
// Cuando se hace click sobre el elemento.
itemView.setOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
if (onItemClickListener != null) {
// Se informa al listener.
onItemClickListener.onItemClick(v,
mDatos.get(viewHolder.getAdapterPosition()),
viewHolder.getAdapterPosition());
}
}
});
// Se retorna el contenedor.
return viewHolder;
}
// Establece el listener a informar cuando se hace click sobre un ítem.
public void setOnItemClickListener(OnItemClickListener listener) {
this.onItemClickListener = listener;
}
...
}
public class MainActivity extends AppCompatActivity {
private static final String STATE_LISTA = "estadoLista";
private LinearLayoutManager mLayoutManager;
private Parcelable mEstadoLista;
...
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
// Se salva el estado del RecyclerView.
mEstadoLista = mLayoutManager.onSaveInstanceState();
outState.putParcelable(STATE_LISTA, mEstadoLista);
}
@Override
protected void onRestoreInstanceState(Bundle savedInstanceState) {
super.onRestoreInstanceState(savedInstanceState);
// Se obtiene el estado anterior de la lista.
mEstadoLista = savedInstanceState.getParcelable(STATE_LISTA);
}
@Override
protected void onResume() {
super.onResume();
// Se retaura el estado de la lista.
if (mEstadoLista != null) {
mLayoutManager.onRestoreInstanceState(mEstadoLista);
}
}
}
recyclerView.setItemAnimator(new DefaultItemAnimator());
gridLayoutManager.setSpanSizeLookup(new GridLayoutManager.SpanSizeLookup() {
@Override
public int getSpanSize(int position) {
// Se retorna un número de columnas dependiendo del tipo de elemento.
switch(mAdaptador.getItemViewType(position)){
case ListItem.TYPE_TIPO1:
return 1;
case ListItem.TYPE_TIPO2:
return 3;
default:
return 0;
}
}
});
recyclerView.setAdapter(adaptador);
recyclerView.setLayoutManager(
new StaggeredGridLayoutManager(2, StaggeredGridLayoutManager.HORIZONTAL));
// Contenedor de vistas para la vista correspondiente al elemento.
static class ViewHolder extends RecyclerView.ViewHolder {
// El contenedor de vistas para un elemento de la lista debe contener...
private final TextView lblNombre;
private final TextView lblDireccion;
private final ImageView imgFoto;
// El constructor recibe la vista correspondiente al elemento.
public ViewHolder(View itemView) {
super(itemView);
// Se obtienen las subvistas de la vista correspondiente al elemento.
lblNombre = (TextView) itemView.findViewById(R.id.lblNombre);
lblDireccion = (TextView) itemView.findViewById(R.id.lblDireccion);
imgFoto = (ImageView) itemView.findViewById(R.id.imgFoto);
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment