Pasé un momento tratando de encontrar una manera de agregar un encabezado a RecyclerView
, sin éxito.
Esto es lo que obtuve hasta ahora:
@Override
protected void onCreate(Bundle savedInstanceState) {
...
layouManager = new LinearLayoutManager(getActivity());
recyclerView.setLayoutManager(layouManager);
LayoutInflater inflater = (LayoutInflater) getActivity().getSystemService(Context.LAYOUT_INFLATER_SERVICE);
headerPlaceHolder = inflater.inflate(R.layout.view_header_holder_medium, null, false);
layouManager.addView(headerPlaceHolder, 0);
...
}
El LayoutManager
parece ser el objeto que maneja la disposición de los RecyclerView
artículos. Como no pude encontrar ningún addHeaderView(View view)
método, decidí seguir el método de LayoutManager
's addView(View view, int position)
y agregar mi vista de encabezado en la primera posición para actuar como un encabezado.
Y aquí es donde las cosas se ponen más feas:
java.lang.NullPointerException: Attempt to read from field 'android.support.v7.widget.RecyclerView$ViewHolder android.support.v7.widget.RecyclerView$LayoutParams.mViewHolder' on a null object reference
at android.support.v7.widget.RecyclerView.getChildViewHolderInt(RecyclerView.java:2497)
at android.support.v7.widget.RecyclerView$LayoutManager.addViewInt(RecyclerView.java:4807)
at android.support.v7.widget.RecyclerView$LayoutManager.addView(RecyclerView.java:4803)
at com.mathieumaree.showz.fragments.CategoryFragment.setRecyclerView(CategoryFragment.java:231)
at com.mathieumaree.showz.fragments.CategoryFragment.access$200(CategoryFragment.java:47)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:201)
at com.mathieumaree.showz.fragments.CategoryFragment$2.success(CategoryFragment.java:196)
at retrofit.CallbackRunnable$1.run(CallbackRunnable.java:41)
at android.os.Handler.handleCallback(Handler.java:739)
at android.os.Handler.dispatchMessage(Handler.java:95)
at android.os.Looper.loop(Looper.java:135)
at android.app.ActivityThread.main(ActivityThread.java:5221)
at java.lang.reflect.Method.invoke(Native Method)
at java.lang.reflect.Method.invoke(Method.java:372)
at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:899)
at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:694)
Después de que varios NullPointerExceptions
intentaran llamar addView(View view)
a los diferentes momentos de la creación de la Actividad (también intenté agregar la vista una vez que todo está configurado, incluso los datos del Adaptador), me di cuenta de que no tengo idea si esta es la forma correcta de hacerlo (y no parece ser)
PD: ¡También se agradecería una solución que pudiera manejar GridLayoutManager
además del LinearLayoutManager
!
fuente
Respuestas:
Tuve que agregar un pie de página a mi
RecyclerView
y aquí estoy compartiendo mi fragmento de código, ya que pensé que podría ser útil. Consulte los comentarios dentro del código para comprender mejor el flujo general.El fragmento de código anterior agrega un pie de página al
RecyclerView
. Puede consultar este repositorio de GitHub para verificar la implementación de agregar tanto el encabezado como el pie de página.fuente
RecyclerView
dinámica. Puede tener control sobre cada uno de los elementos de suRecyclerView
. Mire la sección de código para un proyecto de trabajo. Espero que pueda ayudar. github.com/comeondude/dynamic-recyclerview/wikiint getItemViewType (int position)
- Devuelva el tipo de vista del artículo en la posición para fines de reciclaje de vista. La implementación predeterminada de este método devuelve 0, asumiendo un solo tipo de vista para el adaptador. A diferencia de losListView
adaptadores, los tipos no necesitan ser contiguos. Considere el uso de recursos de identificación para identificar de forma exclusiva los tipos de vista de elementos. - De la documentación. developer.android.com/reference/android/support/v7/widget/…Muy simple de resolver !!
No me gusta la idea de tener lógica dentro del adaptador como un tipo de vista diferente porque cada vez que verifica el tipo de vista antes de devolver la vista. La solución a continuación evita controles adicionales.
Simplemente agregue la vista de encabezado LinearLayout (vertical) + vista de reciclaje + vista de pie de página dentro de android.support.v4.widget.NestedScrollView .
Mira esto:
Agregue esta línea de código para un desplazamiento suave
Esto perderá todo el rendimiento de RV y RV intentará diseñar todos los titulares de vista independientemente de la
layout_height
de RVSe recomienda su uso para la lista de tamaño pequeño como el cajón de navegación o la configuración, etc.
fuente
RecyclerView
trae: pierde el reciclaje real y la optimización que brinda.Tuve el mismo problema en Lollipop y creé dos enfoques para envolver el
Recyclerview
adaptador. Uno es bastante fácil de usar, pero no estoy seguro de cómo se comportará con un conjunto de datos cambiante. Debido a que envuelve su adaptador y necesita asegurarse de llamar a métodos comonotifyDataSetChanged
en el objeto adaptador adecuado.El otro no debería tener tales problemas. Simplemente deje que su adaptador regular extienda la clase, implemente los métodos abstractos y debería estar listo. Y aquí están:
lo esencial
new HeaderRecyclerViewAdapterV1(new RegularAdapter());
RegularAdapter extends HeaderRecyclerViewAdapterV2
HeaderRecyclerViewAdapterV1
HeaderRecyclerViewAdapterV2
Comentarios y tenedores apreciados. Voy a utilizar
HeaderRecyclerViewAdapterV2
por mi mismo y evolucionar, probar y publicar los cambios en el futuro.EDITAR : @OvidiuLatcu Sí, tuve algunos problemas. En realidad, dejé de compensar el encabezado implícitamente
position - (useHeader() ? 1 : 0)
y en su lugar creé un método públicoint offsetPosition(int position)
para ello. Porque si configura una vistaOnItemTouchListener
de Recycler, puede interceptar el toque, obtener las coordenadas x, y del toque, encontrar la vista secundaria correspondiente y luego llamarrecyclerView.getChildPosition(...)
y siempre obtendrá la posición no compensada en el adaptador. Esta es una deficiencia en el Código RecyclerView, no veo un método fácil para superar esto. Es por eso que ahora compenso las posiciones explícitas cuando lo necesito con mi propio código.fuente
No lo he intentado, pero simplemente agregaría 1 (o 2, si desea un encabezado y un pie de página) al entero devuelto por getItemCount en su adaptador. Luego puede anular
getItemViewType
en su adaptador para devolver un número entero diferente cuandoi==0
: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html#getItemViewType(int)createViewHolder
luego se le pasa el entero del que regresógetItemViewType
, lo que le permite crear o configurar el soporte de la vista de manera diferente para la vista del encabezado: https://developer.android.com/reference/android/support/v7/widget/RecyclerView.Adapter.html# createViewHolder (android.view.ViewGroup , int)No olvides restar uno de la posición al número entero pasado
bindViewHolder
.fuente
getItemViewType(int position) { return position == 0 ? 0 : 1; }
(RecyclerView
no tiene ungetViewTypeCount()
método). Por otro lado, estoy de acuerdo con @IZI_Shadow_IZI, realmente tengo la sensación de que LayoutManager debería ser el que maneje este tipo de cosas. Alguna otra idea?Puede usar esta biblioteca de GitHub que permite agregar Encabezado y / o Pie de página en su RecyclerView de la manera más simple posible.
Debe agregar la biblioteca HFRecyclerView en su proyecto o también puede obtenerla de Gradle:
Este es un resultado en la imagen:
EDITAR:
Si solo desea agregar un margen en la parte superior o inferior con esta biblioteca: SimpleItemDecoration :
fuente
Terminé implementando mi propio adaptador para envolver cualquier otro adaptador y proporcionar métodos para agregar vistas de encabezado y pie de página.
Creé una esencia aquí: HeaderViewRecyclerAdapter.java
La característica principal que quería era una interfaz similar a un ListView, así que quería ser capaz de inflar las vistas en mi Fragmento y añadirlos a la
RecyclerView
deonCreateView
. Esto se realiza creando unHeaderViewRecyclerAdapter
pase para adaptar el adaptador, y llamandoaddHeaderView
yaddFooterView
pasando sus vistas infladas. Luego configure laHeaderViewRecyclerAdapter
instancia como el adaptador en elRecyclerView
.Un requisito adicional era que necesitaba poder cambiar fácilmente los adaptadores manteniendo los encabezados y pies de página, no quería tener múltiples adaptadores con múltiples instancias de estos encabezados y pies de página. Por lo tanto, puede llamar
setAdapter
para cambiar el adaptador envuelto dejando los encabezados y pies de página intactos, con laRecyclerView
notificación del cambio.fuente
mi forma de "mantenerlo simple y estúpido" ... desperdicia algunos recursos, lo sé, pero no me importa ya que mi código es simple, así que ... 1) agregue pie de página con visibilidad GONE a su item_layout
2) luego configúrelo visible en el último elemento
hacer lo contrario para el encabezado
fuente
Basado en la solución de @ seb, creé una subclase de RecyclerView.Adapter que admite un número arbitrario de encabezados y pies de página.
https://gist.github.com/mheras/0908873267def75dc746
Aunque parece ser una solución, también creo que esto debería ser administrado por LayoutManager. Desafortunadamente, lo necesito ahora y no tengo tiempo para implementar un StaggeredGridLayoutManager desde cero (ni siquiera extenderlo).
Todavía lo estoy probando, pero puedes probarlo si quieres. Avíseme si encuentra algún problema con él.
fuente
Puede usar viewtype para resolver este problema, aquí está mi demo: https://github.com/yefengfreedom/RecyclerViewWithHeaderFooterLoadingEmptyViewErrorView
puede definir algunos modos de visualización de la vista del reciclador:
public static final int MODE_DATA = 0, MODE_LOADING = 1, MODE_ERROR = 2, MODE_EMPTY = 3, MODE_HEADER_VIEW = 4, MODE_FOOTER_VIEW = 5;
2.sobre el método getItemViewType
3.sobre el método getItemCount
4.sobre el método onCreateViewHolder. crear titular de vista por viewType
5. Anule el método onBindViewHolder. enlazar datos por viewType
fuente
Puede usar la biblioteca SectionedRecyclerViewAdapter para agrupar sus elementos en secciones y agregar un encabezado a cada sección, como en la imagen a continuación:
Primero creas tu clase de sección:
Luego configura RecyclerView con sus secciones y cambia el SpanSize de los encabezados con un GridLayoutManager:
fuente
Sé que llego tarde, pero solo recientemente pude implementar ese "addHeader" en el Adaptador. En mi proyecto FlexibleAdapter , puede llamar
setHeader
a un elemento seccionable y luego llamarshowAllHeaders
. Si solo necesita 1 encabezado, el primer elemento debe tener el encabezado. Si elimina este elemento, el encabezado se vincula automáticamente con el siguiente.Lamentablemente, los pies de página no están cubiertos (todavía).
El Adaptador flexible le permite hacer mucho más que crear encabezados / secciones. Realmente deberías echar un vistazo: https://github.com/davideas/FlexibleAdapter .
fuente
Simplemente agregaría una alternativa a todas esas implementaciones de HeaderRecyclerViewAdapter. Adaptador compuesto:
https://github.com/negusoft/CompoundAdapter-android
Es un enfoque más flexible, ya que puede crear un grupo de adaptadores a partir de adaptadores. Para el ejemplo de encabezado, use su adaptador tal como está, junto con un adaptador que contenga un elemento para el encabezado:
Es bastante simple y legible. Puede implementar un adaptador más complejo fácilmente utilizando el mismo principio.
fuente