Android Listview Custom Sección Encabezado
¿Cómo puedo implementar la sección o encabezado personalizado de ListView como la aplicación Instagram en android.
Http://prsarahevans.com/wp-content/uploads/2011/06/photo.PNG
- Título personalizado de ActionBar como ImaveView en lugar de TextView
- Cambio de fondo y color de texto de AppCompat Light DarkActionBar Theme en android
- Cómo personalizar cardview?
- Uso de Textview personalizado en estilo
- Android Modificación de la pantalla de llamadas a través de AOSP
Cuando se desplaza hacia arriba la barra que tiene userpic, nombre y tiempo todavía estar allí y cuando otra barra de encabezado ir cerca de ella luego animar como empujar hacia arriba.
Gracias.
- ActionBar superposición con GridView relleno o personalizado GridView para mostrar toda la primera imagen?
- ¿Cómo crear un ListView cerrado (circular)?
- Personalización de la funcionalidad de la pantalla de bloqueo de Android?
- ¿Por qué los estilos de corte personalizado aparecen en gris en lugar del color especificado?
- Cambiar el color del cursor editext en API 12
- Cambiar el color de texto de ListView al hacer clic
- Androide. Yor propio progreso-bar?
- Cuerdas Android dependientes del tema
Fui capaz de resolver este problema mediante el uso de scroll escucha en el listview. (Probado en 2.1)
Digamos que para cada fila de lista tengo un diseño como el de abajo. Hay una parte de contenido y una parte de encabezado. No importa el tipo de vista que utilice para el encabezado o el contenido.
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" android:background="#FFFFFF"> <ImageView android:id="@+id/content" android:layout_width="fill_parent" android:layout_height="300dp" android:scaleType="centerCrop" android:src="@drawable/pic" android:background="#aaaaff" android:layout_marginTop="40dp"/> <TextView android:id="@+id/header" android:layout_width="fill_parent" android:layout_height="40dp" android:padding="12dp" android:text="Deneme Row" android:textColor="#000000" android:background="#99ffffff"/> </RelativeLayout>
El diseño de la prueba para la actividad es como en los siguientes:
<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:orientation="vertical" > <ListView android:id="@+id/list" android:layout_width="fill_parent" android:layout_height="fill_parent" > </ListView> </LinearLayout>
Finalmente el código para la actividad se da a continuación. Aquí tuve que tener un adaptador que usa ViewHolder para almacenar la vista de cabecera y también una variable para mantener un registro del cambio en el desplazamiento de cada evento de desplazamiento sucesivo (anteriorTop). Esto es debido al hecho de que offsetTopAndBottom () cambia el desplazamiento de la vista relacionada con la ubicación anterior del mismo.
public class TestActivity extends Activity implements AbsListView.OnScrollListener{ ListView list; @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.main); list = (ListView) findViewById(R.id.list); list.setAdapter(new Adapter(this)); list.setOnScrollListener(this); } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { //the listview has only few children (of course according to the height of each child) who are visible for(int i=0; i < list.getChildCount(); i++){ View child = list.getChildAt(i); ViewHolder holder = (ViewHolder) child.getTag(); //if the view is the first item at the top we will do some processing if(i == 0){ boolean isAtBottom = child.getHeight() <= holder.header.getBottom(); int offset = holder.previousTop - child.getTop(); if(!(isAtBottom && offset > 0)){ holder.previousTop = child.getTop(); holder.header.offsetTopAndBottom(offset); holder.header.invalidate(); } } //if the view is not the first item it "may" need some correction because of view re-use else if (holder.header.getTop() != 0) { int offset = -1 * holder.header.getTop(); holder.header.offsetTopAndBottom(offset); holder.previousTop = 0; holder.header.invalidate(); } } } @Override public void onScrollStateChanged(AbsListView view, int scrollState) {} private static class Adapter extends ArrayAdapter<String> { public Adapter(Context context) { super(context, R.layout.row, R.id.header); for(int i=0; i < 50; i++){ add(Integer.toString(i)); } } @Override public View getView(int position, View convertView, ViewGroup parent) { if(convertView == null){ convertView = LayoutInflater.from(getContext()).inflate(R.layout.row, parent, false); ViewHolder holder = new ViewHolder(); holder.header = (TextView) convertView.findViewById(R.id.header); convertView.setTag(holder); } ViewHolder holder = (ViewHolder) convertView.getTag(); holder.header.setText(getItem(position)); return convertView; } } private static class ViewHolder { TextView header; int previousTop = 0; } }
He mejorado la pregunta de Siyamed un poco para que el encabezado no se ha ido cuando la vista se vuelve a dibujar, por ejemplo, si un mapa de bits en el elemento de vista de lista se cambia.
En lugar de utilizar coordenadas con respecto a la última posición, utilizo coordenadas relativas a la parte superior de la vista y uso relleno en lugar de desplazamientos.
@Override public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) { for(int i=0; i < list.getChildCount(); i++){ View child = list.getChildAt(i); ViewHolder holder = (ViewHolder) child.getTag(); if(i == 0){ try { boolean isAtBottom = child.getHeight() <= holder.movingHeader.getBottom(); if(!(isAtBottom)){ if (child.getTop() >= 0){} else if (child.getHeight() - movingHeader.getHeight() - 1 > -child.getTop()) { holder.movingHeader.setPadding(0, -child.getTop(), 0, 0); holder.movingHeader.invalidate(); } else { holder.movingHeader.setPadding(0, child.getHeight() - movingHeader.getHeight(), 0, 0); holder.movingHeader.invalidate(); } } } catch (Exception e) { e.printStackTrace(); } } else if (holder.movingHeader.getPaddingTop() != 0) { holder.movingHeader.setPadding(0, 0, 0, 0); holder.movingHeader.invalidate(); } } }
Si está usando la vista de lista, entonces tiene 2 vistas dentro de su elemento de lista. Uno es encabezado y otro es en realidad elemento.
Ocultar la vista del encabezado inicialmente y cuando el estado de desplazamiento cambia o el usuario toca el elemento de la lista cambia la visibilidad del encabezado.
Después de su setcontentview hacer algo como el siguiente código.
ListView list = getListView(); View footer = getLayoutInflater().inflate(R.layout.footerlayout, list, false); View header = getLayoutInflater().inflate(R.layout.headerlayout, list, false); list.addHeaderView(header); list.addFooterView(footer);
Sé que esta pregunta es un poco antigua, pero logró encontrar la biblioteca StickyListHeaders, que hace un trabajo bastante bueno de abstraer la creación de los encabezados de sección.