我有一个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不确定,但只是一个随机的想法。 –