IPhone como cabezal deslizante, o: ¿cómo forzar el redibujo inmediato en el cambio de margen superior?

Estoy tratando de implementar un efecto similar como el iPhone-alike cabecera deslizante en la aplicación de contacto de iPhone (la cabecera deslizante que el grupo de los contactos por su letra de inicio).

Esta es la pantalla de mi aplicación, y lo que quiero lograr es la siguiente:

Introduzca aquí la descripción de la imagen

Tengo una "cabecera de guía" y tres "pestañas" para ordenar la lista. Cuando el usuario desplaza la lista hacia arriba, quiero que todo se desplace hacia arriba (encabezado de guía, pestañas, lista). Sin embargo, cuando las pestañas lleguen a la parte superior de la pantalla (y el encabezado de guía se apagará de la pantalla), quiero que las pestañas se detengan y permanezcan allí (permanezcan como "encabezado pegajoso") y solo los elementos de la lista se desplazan como En cualquier vista de lista normal.

Tengo un grupo de la visión (cabecera de la guía) sobre una visión de la lista.

En primer lugar, quiero que la cabecera de guía ajuste su posición dependiendo de la posición de desplazamiento de la vista de lista.

Primer enfoque: Mi idea era establecer un onScrollListener en la vista de lista y cambiar el margen superior del encabezado de guía a cualquier posición de desplazamiento del primer elemento de la vista de lista (que sería un valor negativo).

La lógica es correcta, pero el problema que estoy enfrentando es que la vista de cabecera de guía no se vuelve a dibujar lo suficientemente rápido mientras estoy desplazándose en la vista de lista. La vista de cabecera de guía sólo se actualiza (a mi valor de margen superior cambiado) cuando la vista de lista llega a su fin. Incluso el desplazamiento lento no funciona. Invalidar (invalidate ()) la vista de cabecera de guía o su padre también no ayuda, puesto que sólo pondría una solicitud de invalidación a la cola, pero la invalidación y redibujo no ocurre inmediatamente, pero sólo cuando el subproceso de interfaz de usuario se vuelve inactivo , Lo que no parece ocurrir mientras el usuario todavía tiene sus dedos en la vista de lista de desplazamiento. Parece que lanzar la vista de lista bloquea todo el hilo de la interfaz de usuario o lo mantiene ocupado por sí mismo.

Así que el problema principal es: cambiar el margen de la vista de cabecera de guía no se hace visible inmediatamente mientras el usuario está desplazando la vista de lista. El código que estoy usando esto:

@Override public void onScroll(final AbsListView view, final int firstVisibleItem, final int visibleItemCount, final int totalItemCount) { // Get the first list item and check it's scroll position. This will be the value (top), that we also // use the scroll the header parallel. View v = mainList.getChildAt(0); final int top = (v==null)?0:v.getTop(); // This logs the current scroll position of the first list item element/view group. Log.d("onScroll", "onScroll: " + top); // Here we finally change the margin (setting a negative margin) to the header element. ((LinearLayout.LayoutParams)(findViewById(R.id.header_container).getLayoutParams())).setMargins(0, top, 0, 0); // was just a test: invalidating the outer container/view group, doesn't help // findViewById(R.id.ll_container).invalidate(); } 

Veo la salida de registro "onScroll:" que inserté en el código anterior en el logcat, pero el siguiente ajuste del margen superior no se hace visible.

Mi segundo enfoque: es usar una vista de desplazamiento para la cabecera de guía + pestañas y trabajar con ellas. Desplazando el encabezado de guía (que es entonces una vista de desplazamiento) del código con scrollView.scrollTo (0, Math.abs (Math.abs (arriba)) del método onScroll de la vista de lista funciona y casi inmediatamente se muestra en la pantalla, Sin embargo, no es muy preciso / estable cuando el usuario arroja la vista de lista muy rápido – lo que significa que salta en intervalos y no parece suave, es sólo precisa / estable al desplazarse lentamente.

Mi pregunta es ahora: ¿hay alguna mejor práctica para lograr un efecto de cabecera deslizante, y más concreto: hay una manera de forzar la vista de cabecera de guía a ser redibujado mientras el usuario sigue desplazando la vista de lista (en mi primer enfoque mencionado ).

Para esto debes usar algunos trucos (afaik no hay una implementación lista para usar de tal característica).
Por ejemplo, puede detectar gestos en su vista, y

  • Si el gesto actual coincide con una rueda hacia abajo y el primer elemento de la lista está visible, animate-reduce el tamaño del encabezado a 0, el tamaño de la vista de la pestaña a match_parent. Comience a desplazarse por la lista sólo cuando el encabezado no esté presente.
  • Si el gesto actual coincide con desplazarse hacia arriba y el primero ya está visible, animate-expanda el encabezado a su tamaño original.

Así que usar la animación en la vista de cabecera puede ser su solución.

Actualizar
Otra solución sería extender su List (la matriz de valores de su adaptador):
Insertar un nuevo elemento (ficticio) en la parte superior para la representación del encabezado y modificar el método getView :

 @Override public View getView(int position, View convertView, ViewGroup parent) { if (position == 0) { convertView = inflater.inflate(R.layout.sliding_header, parent, false); return convertView; } //TODO: your original method body comes here } 

Donde el xml al que hace referencia R.layout.sliding_header debe contener el diseño de encabezado de su lista.

Una aplicación OnScrollListener personalizada aplicada al ListView haría imperceptible que el encabezado sea realmente un elemento de la lista, ya que podría ocultar la barra de desplazamiento.
Debe añadir este listener a su listView en el método onCreate la actividad:

 listView.setOnScrollListener(new MyScrollListener()); 

Donde MyScrollListener es:

 /** * Custom OnScrollListener */ private final class MyScrollListener implements OnScrollListener { @Override public void onScrollStateChanged(AbsListView view, int scrollState) {} @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (view.getFirstVisiblePosition() == 0) view.setVerticalScrollBarEnabled(false); else if (!view.isVerticalScrollBarEnabled()) view.setVerticalScrollBarEnabled(true); } } 

Creo que también puedes probar y usar mi ExpandAnimation para eso. http://udinic.wordpress.com/2011/09/03/expanding-listview-items/

Simplemente pase la clase de animación que "guíe la vista de encabezado", y deje que la animación haga el trabajo por usted, no se necesita desplazamiento en ese caso, y es suave.

  • ViewPager no desliza con FragmentPagerAdapter
  • TransitionDrawable: invierte automáticamente la transición una vez que completa
  • Direcciones de la transición de explosión entre fragmentos
  • ¿Existe un recurso / widget pre-construido para el indicador de progreso "agradable" indeterminado en Android Wear?
  • ¿Cómo lograr la interfaz de usuario de Android como este diseño de imagen? Acerca de android: clipChildren
  • Cómo crear Android La vista de cuadrícula de Google Play como Widget con imágenes de diferentes tamaños cargadas dinámicamente
  • Creación de un botón de retroceso personalizado en android
  • Keyevent para hacer clic en Alert Dialog de la pantalla de Android
  • Cuándo utilizar res / xml vs.res / carpetas de diseño en Android
  • Obtener la posición de la imagen actual en la Galería
  • Reemplace el título de la barra de acción con una ruleta (desplegable)
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.