我有一個ListView與onScrollStateChanged和onScroll事件偵聽器。我希望能夠獲得ListView的滾動速度,或者某種方式來獲取某個Event偵聽器中啓動的滾動的finalX位置。我們的應用程序目標SDK版本7.如何獲得ListView的滾動速度?
我需要測量或獲取ListView滾動的速度。
我有一個ListView與onScrollStateChanged和onScroll事件偵聽器。我希望能夠獲得ListView的滾動速度,或者某種方式來獲取某個Event偵聽器中啓動的滾動的finalX位置。我們的應用程序目標SDK版本7.如何獲得ListView的滾動速度?
我需要測量或獲取ListView滾動的速度。
司第一個可見項目時差的差異並不是一個好的解決方案。 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) {
}
};
+1謝謝,它解決了我的問題.. –
很酷,但這似乎不工作時使用快速滾動。 \t \t android:fastScrollEnabled =「true」。 – andymal
試試:
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) {
}
}
,你可以在你 使用android:fastScrollEnabled="true"
,不要忘了:yourAdapter.notifyDataSetChanged();
後YourListView.requestFocusFromTouch();
因爲它(yourlistview)失去焦點在速度快
所以這只是一些理論僞代碼,但不會像這樣的工作?
我認爲接受的答案並不真正起作用,分辨率超低(即只有在項目從整個屏幕上滾動後才能獲得速度,但如果您有大量項目視圖?)。
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;
}
再次,這只是僞代碼,我沒有測試過,但我認爲它應該工作。當滾動狀態爲STATE_IDLE
時,您還必須重置上次和頂部位置值。
有一個簡單的方法來得到速度(NOT速度)ListView控件的,但它不是最完美的方式。
/** 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;
}
onScroll
,在AbsListView,我們可以與FlingRunnable#mScroller.getCurrVelocity()得到速度,但不幸的是,AbsListView
不提供getCurrVelocity()
的公共方法,所以如果我們想獲得這種方法,有兩種方法得到它
onScroll
回調getCurrVelocity()
,讓新的ListViewEx從AbsListViewEx擴展出來,但它也有一些問題:1)它可能是一個複雜的事情2)ListViewEx可能有兼容性問題。不過,這樣我覺得比Reflect method
好。下面的代碼,如果你需要知道什麼時候該項目具有不同的尺寸,或當你有一個很長的名單它多少像素每秒滾動。如果某些項目被遺漏,計算和緩存每個項目大小將不起作用。順便說一句,如果你選擇這種方法,你應該緩存項目的偏移量,而不是高度,所以你不必這麼多的計算。
覆蓋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;
}
我還沒有嘗試過任何東西,但有兩個想法浮現在腦海中。 1)使用'onFling()'方法使用手勢檢測器來檢測手勢的速度。 2)調用'listView.getFirstVisiblePosition()'來跟蹤每次調用計算速度的時間。 – theisenp
@theisenp看起來兩個合理的選項,我會看看他們。 – Joost
你可以嘗試使用Scroller http://developer.android.com/reference/android/widget/Scroller.html不確定,但只是一個隨機的想法。 –