java - una - rapidez promedio y velocidad promedio
¿Cómo obtener la velocidad de desplazamiento en un ListView? (6)
Aquí está el código si necesita saber cuántos píxeles por segundo se desplaza cuando los elementos tienen tamaños diferentes o cuando tiene una lista muy larga. Calcular y almacenar en caché el tamaño de cada elemento no funcionaría si se pierden algunos elementos. Por cierto, si elige ese método, debe almacenar en caché la compensación del elemento en lugar de la altura para que no tenga que hacer tantos cálculos.
Anular OnScrollListener:
private HashMap<Integer, Integer> offsetMap = new HashMap<>();
private long prevScrollTime = System.currentTimeMillis();
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
float traveled = 0;
Set<Integer> oldKeys = new HashSet<>(offsetMap.keySet());
for (int i = 0; i < visibleItemCount; i++) {
int pos = firstVisibleItem + i;
int newOffset = view.getChildAt(i).getTop();
if (offsetMap.containsKey(pos) && traveled == 0) {
traveled = Math.abs(newOffset - offsetMap.get(pos));
}
offsetMap.put(pos, newOffset);
oldKeys.remove(pos);
}
// remove those that are no longer in view
for (Integer key : oldKeys) {
offsetMap.remove(key);
}
long newTime = System.currentTimeMillis();
long t = newTime - prevScrollTime;
if (t > 0) {
float speed = traveled / t * 1000f;
} else {
// speed = 0
}
prevScrollTime = newTime;
}
Tengo un ListView con oyentes de eventos onScrollStateChanged y onScroll. Quiero poder obtener la velocidad de desplazamiento de ListView o de alguna manera obtener la ubicación finalX del desplazamiento iniciado en algún detector de eventos. Nuestra aplicación apunta al SDK versión 7.
Necesito medir u obtener la velocidad a la que se desplaza el ListView.
Así que esto es solo un pseudocódigo teórico, pero ¿no funcionaría algo como esto?
Creo que la respuesta aceptada no funciona realmente, la resolución es muy baja (es decir, solo se obtiene una velocidad después de que un elemento se haya desplazado de la pantalla completa, pero ¿qué sucede si tiene vistas de elementos grandes?).
int mTrackingPosition = -1;
int mLastTop;
long mLastEventTime;
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
// Get a new tracking position if our old one is no longer on screen
// (this also includes the first time)
if (first > mTrackingPosition || last < mTrackingPosition) {
// We get the middle position here since that''s likely to stay
// on screen for a bit when scrolling up or down.
mTrackingPosition = firstVisibleItem + visibleItemCount / 2;
// Reset our times since we can''t really get velocity from this
// one measurement
mLastTop = mLastEventTime = -1;
// Handle the case that this happens more than once in a
// row if that''s even reasonably possible (i.e. they
// scrolled rediculously fast)
}
// Get the measurements of the tracking view
View v = view.getViewForPosition(mTrackingPosition);
int top = v.getTop();
long time = System.currentTimeMillis();
// We can only get speed if we have a last recorded time
if (mLastTop != -1 && mLastEventTime != -1) {
// Velocity = distance / time
float velocity = (mLastTop - top) / (time - mLastEventTime);
// What do you want to do with the velocity?
...
}
// Update the last top and time so that we can track the difference
mLastTop = top;
mLastEventTime = time;
}
Nuevamente, esto es solo un pseudocódigo que no he probado, pero creo que debería funcionar. También deberá restablecer los valores de última hora y posición superior cuando el estado de desplazamiento sea STATE_IDLE
.
Hay una forma sencilla de obtener la velocidad (NO velocidad) de ListView, pero no es la manera perfecta.
/** The scroll speed threshold, it''s a empiric value. */
private static final int LOW_SPEED_SCROLL_THRESHOLD = 3000;
/** The offset, in pixels, by which the content of this view is scrolled vertically. */
private long mScrollY = 0;
/** The last offset, in pixels, by which the content of this view is scrolled vertically. */
private long mLastScrollY = 0;
/** The last scroll time, in millisecond */
private long mLastTime = 0;
public void onScroll(AbsListView absListView, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
final View currentItemView = absListView.getChildAt(0);
if (currentItemView != null) {
// The first try to scroll, reset the last time flag
if (mLastTime == 0) {
mLastTime = System.currentTimeMillis();
return;
}
final int height = currentItemView.getHeight();
final int currentPos = firstVisibleItem;
final int currentPosOffset = currentItemView.getTop(); // < 0
mScrollY = currentPos * height - currentPosOffset;
final long deltaOffset = mScrollY - mLastScrollY;
final long currTime = System.currentTimeMillis();
if (currTime == mLastTime) {
return;
}
final long speed = deltaOffset * 1000 / (currTime - mLastTime);
if (Math.abs(speed) < LOW_SPEED_SCROLL_THRESHOLD) {
// low speed
} else {
// high speed
}
mLastTime = currTime;
mLastScrollY = mScrollY;
} else {
resetScrollState();
}
}
private void resetScrollState() {
mLastTime = 0;
mScrollY = 0;
mLastScrollY = 0;
}
- La forma perfecta es usar la velocidad de desplazamiento actual cuando la devolución de llamada en
onScroll
, en AbsListView, podemos obtener la velocidad con FlingRunnable # mScroller.getCurrVelocity () , pero desafortunadamente,AbsListView
no proporciona el método público degetCurrVelocity()
, por lo que si desea obtener este método, hay dos métodos para obtenerlo- Refleje este método, pero creo que tiene el problema de rendimiento cuando lo obtiene en la devolución de llamada de
onScroll
- Copie la fuente AbsListView.java y cree una nueva clase de AbsListViewEx, proporcione un método público de
getCurrVelocity()
en esta clase, deje que el nuevo ListViewEx se extienda desde AbsListViewEx, pero también tiene algún problema: 1) quizás sea algo complejo 2) el ListViewEx puede tener problemas de compatibilidad. Sin embargo, de esta manera creo que es mejor que elReflect method
.
- Refleje este método, pero creo que tiene el problema de rendimiento cuando lo obtiene en la devolución de llamada de
Intentalo:
private class SpeedMeterOnScrollListener implements OnScrollListener {
private long timeStamp;
private int lastFirstVisibleItem;
public SpeedMeterOnScrollListener() {
timeStamp = System.currentTimeMillis();
lastFirstVisibleItem = 0;
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem, int visibleItemCount, int totalItemCount) {
long lastTime = System.currentTimeMillis();
//calculate speed by firstVisibleItem, lastFirstVisibleItem, timeStamp and lastTime
timeStamp = lastTime;
lastFirstVisibleItem = firstVisibleItem;
}
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
}
}
La diferencia de los primeros artículos visibles de la división en la diferencia de tiempo no es una buena solución. El oyente OnScroll recibe el evento OnScroll cada período de tiempo fijo, por lo que en la mayoría de los casos el resultado de la división será "0".
Así que puedes probar algo como esto:
private OnScrollListener onScrollListener = new OnScrollListener() {
private int previousFirstVisibleItem = 0;
private long previousEventTime = 0;
private double speed = 0;
@Override
public void onScroll(HtcAbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
if (previousFirstVisibleItem != firstVisibleItem){
long currTime = System.currentTimeMillis();
long timeToScrollOneElement = currTime - previousEventTime;
speed = ((double)1/timeToScrollOneElement)*1000;
previousFirstVisibleItem = firstVisibleItem;
previousEventTime = currTime;
Log.d("DBG", "Speed: " +speed + " elements/second");
}
}
@Override
public void onScrollStateChanged(HtcAbsListView view, int scrollState) {
}
};
puede usar android:fastScrollEnabled="true"
en usted y no olvide: YourListView.requestFocusFromTouch();
después de yourAdapter.notifyDataSetChanged();
porque (tu vista de lista) pierde el foco en velocidad rápida