Подтвердить что ты не робот

Как получить скорость прокрутки в ListView?

У меня есть ListView с onScrollStateChanged и onScroll прослушиватели событий. Я хочу, чтобы получить скорость прокрутки ListView или каким-то образом, чтобы получить конечное местоположение начального прокрутки в каком-либо прослушивателе событий. Наше приложение предназначено для SDK версии 7.

Мне нужно измерить или получить скорость, с которой прокручивается ListView.

4b9b3361

Ответ 1

Разделение первых видимых различий по разнице во времени не является хорошим решением. OnScroll прослушиватель получает событие onScroll каждый фиксированный период времени, поэтому в большинстве случаев результат деления будет "0".

Итак, вы можете попробовать что-то вроде этого:

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) {
    }
};

Ответ 2

Попробуйте:

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) {
    }
}

Ответ 3

Итак, это всего лишь какой-то теоретический псевдокод, но не похоже на эту работу?

Я думаю, что принятый ответ действительно не работает, разрешение очень низкое (т.е. вы получаете только скорость после прокрутки элемента со всего экрана, но что, если у вас большие представления элементов?).

   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 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 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;
   }

Снова это просто псевдокод, который я не тестировал, но я думаю, что он должен работать. Вы также должны будете иметь reset значения последнего и верхнего положения, когда состояние прокрутки STATE_IDLE.

Ответ 4

Существует простой способ получить скорость (NOT Velocity) в ListView, но это не идеальный способ.

/** The scroll speed threshold, it 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;
}
  1. Идеальный способ - использовать текущую прокрутку Velocity при обратном вызове onScroll, в AbsListView мы можем получить скорость с помощью FlingRunnable # mScroller.getCurrVelocity(), но к сожалению, AbsListView не предоставляет общедоступный метод getCurrVelocity(), поэтому, если мы хотим получить этот метод, есть два метода его получения
    • Отразите этот метод, но я думаю, что у него есть проблема с производительностью, когда он получает onScroll обратный вызов
    • Скопируйте источник AbsListView.java и создайте новый класс AbsListViewEx, предоставите общедоступный метод getCurrVelocity() в этом классе, пусть новый ListViewEx простирается от AbsListViewEx, но он также имеет некоторые проблемы: 1) это может быть сложная вещь 2) ListViewEx может иметь проблему совместимости. Однако, я думаю, это лучше, чем Reflect method.

Ответ 5

Здесь код, если вам нужно знать, сколько пикселей в секунду прокручивается, когда элементы имеют разные размеры или когда у вас очень длинный список. Вычисление и кеширование каждого размера элемента не будет работать, если некоторые элементы пропущены. BTW, если вы выберете этот метод, вы должны кэшировать смещение элемента вместо высоты, поэтому вам не нужно делать так много вычислений.

Переопределить 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;
}

Ответ 6

вы можете использовать android:fastScrollEnabled="true" в себе и не забудьте: YourListView.requestFocusFromTouch(); после yourAdapter.notifyDataSetChanged();, потому что он (ваш список) потеряет фокус с быстрой скоростью