Android listView busca la cantidad de píxeles desplazados

Tengo una listaVer. Cuando me desplazo y para en un lugar particular.

¿Cómo puedo obtener la cantidad de píxeles que despliegue (desde arriba)?

He intentado usar get listView.getScrollY (), pero devuelve 0.

Yo tuve el mismo problema.

No puedo usar View.getScrollY () porque siempre devuelve 0 y no puedo usar OnScrollListener.onScroll (…) porque funciona con posiciones no con píxeles. No puedo subclasificar ListView y anular onScrollChanged (…) porque sus valores de parámetro son siempre 0. Meh.

Todo lo que quiero saber es la cantidad que los niños (es decir, el contenido de listview) se desplazó hacia arriba o hacia abajo. Así que me llegó con una solución. Rastreo a uno de los niños (o puede decir una de las "filas") y seguir su cambio de posición vertical.

Aquí está el código:

public class ObservableListView extends ListView { public static interface ListViewObserver { public void onScroll(float deltaY); } private ListViewObserver mObserver; private View mTrackedChild; private int mTrackedChildPrevPosition; private int mTrackedChildPrevTop; public ObservableListView(Context context, AttributeSet attrs) { super(context, attrs); } @Override protected void onScrollChanged(int l, int t, int oldl, int oldt) { super.onScrollChanged(l, t, oldl, oldt); if (mTrackedChild == null) { if (getChildCount() > 0) { mTrackedChild = getChildInTheMiddle(); mTrackedChildPrevTop = mTrackedChild.getTop(); mTrackedChildPrevPosition = getPositionForView(mTrackedChild); } } else { boolean childIsSafeToTrack = mTrackedChild.getParent() == this && getPositionForView(mTrackedChild) == mTrackedChildPrevPosition; if (childIsSafeToTrack) { int top = mTrackedChild.getTop(); if (mObserver != null) { float deltaY = top - mTrackedChildPrevTop; mObserver.onScroll(deltaY); } mTrackedChildPrevTop = top; } else { mTrackedChild = null; } } } private View getChildInTheMiddle() { return getChildAt(getChildCount() / 2); } public void setObserver(ListViewObserver observer) { mObserver = observer; } } 

Un par de notas:

  • Anulamos onScrollChanged (…) porque se llama cuando la lista se desplaza (sólo sus parámetros son inútiles)
  • Entonces elegimos un niño (fila) desde el centro (no tiene que ser precisamente el niño en el medio)
  • Cada vez que ocurre el desplazamiento calculamos el movimiento vertical basado en la posición anterior (getTop ()) del niño rastreado
  • Dejamos de rastrear a un niño cuando no es seguro ser rastreado (por ejemplo, en los casos en que podría ser reutilizado)

Usted no puede obtener píxeles de la parte superior de la lista (porque entonces usted necesita para el diseño de todas las vistas desde la parte superior de la lista – puede haber un montón de elementos). Pero puede obtener píxeles del primer elemento visible: int pixels = listView.getChildAt(0).getTop(); Generalmente será cero o negativo – muestra la diferencia entre la parte superior de listView y la parte superior de la primera vista en la lista

Editar: He mejorado en esta clase para evitar algunos momentos que la pista estaba perdiendo debido a las vistas son demasiado grandes y no obtener correctamente un getTop()

Esta nueva solución utiliza 4 puntos de seguimiento:

  • Primer hijo, abajo
  • Niño medio, arriba
  • Niño medio, abajo
  • Último hijo, arriba

Que hace que siempre tengamos un isSafeToTrack igual a true

 import android.view.View; import android.widget.AbsListView; /** * Created by budius on 16.05.14. * This improves on Zsolt Safrany answer on stack-overflow (see link) * by making it a detector that can be attached to any AbsListView. * http://stackoverflow.com/questions/8471075/android-listview-find-the-amount-of-pixels-scrolled */ public class PixelScrollDetector implements AbsListView.OnScrollListener { private final PixelScrollListener listener; private TrackElement[] trackElements = { new TrackElement(0), // top view, bottom Y new TrackElement(1), // mid view, bottom Y new TrackElement(2), // mid view, top Y new TrackElement(3)};// bottom view, top Y public PixelScrollDetector(PixelScrollListener listener) { this.listener = listener; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // init the values every time the list is moving if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL || scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { for (TrackElement t : trackElements) t.syncState(view); } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { boolean wasTracked = false; for (TrackElement t : trackElements) { if (!wasTracked) { if (t.isSafeToTrack(view)) { wasTracked = true; if (listener != null) listener.onScroll(view, t.getDeltaY()); t.syncState(view); } else { t.reset(); } } else { t.syncState(view); } } } public static interface PixelScrollListener { public void onScroll(AbsListView view, float deltaY); } private static class TrackElement { private final int position; private TrackElement(int position) { this.position = position; } void syncState(AbsListView view) { if (view.getChildCount() > 0) { trackedChild = getChild(view); trackedChildPrevTop = getY(); trackedChildPrevPosition = view.getPositionForView(trackedChild); } } void reset() { trackedChild = null; } boolean isSafeToTrack(AbsListView view) { return (trackedChild != null) && (trackedChild.getParent() == view) && (view.getPositionForView(trackedChild) == trackedChildPrevPosition); } int getDeltaY() { return getY() - trackedChildPrevTop; } private View getChild(AbsListView view) { switch (position) { case 0: return view.getChildAt(0); case 1: case 2: return view.getChildAt(view.getChildCount() / 2); case 3: return view.getChildAt(view.getChildCount() - 1); default: return null; } } private int getY() { if (position <= 1) { return trackedChild.getBottom(); } else { return trackedChild.getTop(); } } View trackedChild; int trackedChildPrevPosition; int trackedChildPrevTop; } } 

Respuesta original

Primero quiero agradecer a @ zsolt-safrany por su respuesta, que fue una gran cosa, un total de felicitaciones para él.

Pero entonces quiero presentar mi mejora en su respuesta (todavía es más o menos su respuesta, sólo algunas mejoras)

Mejoras:

  • Es un tipo separado de "detector de gestos" de clase que se puede agregar a cualquier clase que extienda AbsListView llamando .setOnScrollListener() , por lo que es un enfoque más flexible.

  • Está utilizando el cambio en el estado de desplazamiento para preasignar al niño rastreado, por lo que no "desperdicia" un pase onScroll para asignar su posición.

  • Se vuelve a calcular el niño rastreado en cada pase onScroll para evitar la falta de pase al azar onScroll para volver a calcular el niño. (Esto podría ser hacer más eficiente mediante el almacenamiento en caché algunas alturas y sólo volver a calcular después de cierta cantidad de desplazamiento).

Espero eso ayude

 import android.view.View; import android.widget.AbsListView; /** * Created by budius on 16.05.14. * This improves on Zsolt Safrany answer on stack-overflow (see link) * by making it a detector that can be attached to any AbsListView. * http://stackoverflow.com/questions/8471075/android-listview-find-the-amount-of-pixels-scrolled */ public class PixelScrollDetector implements AbsListView.OnScrollListener { private final PixelScrollListener listener; private View mTrackedChild; private int mTrackedChildPrevPosition; private int mTrackedChildPrevTop; public PixelScrollDetector(PixelScrollListener listener) { this.listener = listener; } @Override public void onScrollStateChanged(AbsListView view, int scrollState) { // init the values every time the list is moving if (scrollState == AbsListView.OnScrollListener.SCROLL_STATE_TOUCH_SCROLL || scrollState == AbsListView.OnScrollListener.SCROLL_STATE_FLING) { if (mTrackedChild == null) { syncState(view); } } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { if (mTrackedChild == null) { // case we don't have any reference yet, try again here syncState(view); } else { boolean childIsSafeToTrack = (mTrackedChild.getParent() == view) && (view.getPositionForView(mTrackedChild) == mTrackedChildPrevPosition); if (childIsSafeToTrack) { int top = mTrackedChild.getTop(); if (listener != null) { float deltaY = top - mTrackedChildPrevTop; listener.onScroll(view, deltaY); } // re-syncing the state make the tracked child change as the list scrolls, // and that gives a much higher true state for `childIsSafeToTrack` syncState(view); } else { mTrackedChild = null; } } } private void syncState(AbsListView view) { if (view.getChildCount() > 0) { mTrackedChild = getChildInTheMiddle(view); mTrackedChildPrevTop = mTrackedChild.getTop(); mTrackedChildPrevPosition = view.getPositionForView(mTrackedChild); } } private View getChildInTheMiddle(AbsListView view) { return view.getChildAt(view.getChildCount() / 2); } public static interface PixelScrollListener { public void onScroll(AbsListView view, float deltaY); } } 

Trate de implementar OnScrollListener :

 list.setOnScrollListener(new OnScrollListener() { @Override public void onScrollStateChanged(AbsListView view, int scrollState) { int last = view.getLastVisiblePosition(); break; } } @Override public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) { } }); 
  • Detener el desplazamiento en una vista de lista
  • Barra de desplazamiento a ViewGroup personalizado
  • ¿Cómo configurar el desplazamiento perfomance para webview?
  • Desplazamiento sobre lienzo grande
  • Desplácese dentro de un EditText que está en un ScrollView
  • Cómo desplazarse mediante programación WebView de Android
  • Restablecer la posición de TextView (desplazable) en la nueva carga de texto
  • Actualizar Android listview after scrollBy on
  • Vistas de varias listas de Android que no se desplazan de forma independiente
  • Vista de cuadrícula personalizada con rango de fila y extensión de columna
  • Sincronizar la posición de dos vistas ScrollView
  • FlipAndroid es un fan de Google para Android, Todo sobre Android Phones, Android Wear, Android Dev y Aplicaciones para Android Aplicaciones.