我正在使用ListView创建图片列表,照片的大小可以在屏幕上显示2到3张照片。
我遇到的问题是,当用户停止滚动显示可见列表的第一项会捕捉到屏幕顶部时,我想这样做,例如,如果滚动结束并且第一项的一小部分显示图片后,我们向下滚动列表,以便图片始终完全显示,如果显示的是大部分图片,我们将列表向上滚动,以便下一张图片完全可见。
有没有办法在android中使用listview实现这个目的?
答案 0 :(得分:26)
我找到了一种方法来实现这一点,只需通过实现ListView.OnScrollListener
滚动并在滚动结束时更改位置@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
switch (scrollState) {
case OnScrollListener.SCROLL_STATE_IDLE:
if (scrolling){
// get first visible item
View itemView = view.getChildAt(0);
int top = Math.abs(itemView.getTop()); // top is a negative value
int bottom = Math.abs(itemView.getBottom());
if (top >= bottom){
((ListView)view).setSelectionFromTop(view.getFirstVisiblePosition()+1, 0);
} else {
((ListView)view).setSelectionFromTop(view.getFirstVisiblePosition(), 0);
}
}
scrolling = false;
break;
case OnScrollListener.SCROLL_STATE_TOUCH_SCROLL:
case OnScrollListener.SCROLL_STATE_FLING:
Log.i("TEST", "SCROLLING");
scrolling = true;
break;
}
}
改变不是那么顺利但是有效。
答案 1 :(得分:5)
利用来自@nininho的解决方案中的一些想法,我得到了我的listview以顺利滚动而不是突然进入该项目。需要注意的是,我只在带有文本的基本ListView中的Moto X上测试了这个解决方案,但它在设备上运行良好。尽管如此,我对此解决方案充满信心,并鼓励您提供反馈。
listview.setOnScrollListener(new OnScrollListener() {
@Override
public void onScrollStateChanged(AbsListView view, int scrollState) {
// TODO Auto-generated method stub
if (scrollState == SCROLL_STATE_IDLE) {
View itemView = view.getChildAt(0);
int top = Math.abs(itemView.getTop());
int bottom = Math.abs(itemView.getBottom());
int scrollBy = top >= bottom ? bottom : -top;
if (scrollBy == 0) {
return;
}
smoothScrollDeferred(scrollBy, (ListView)view);
}
}
private void smoothScrollDeferred(final int scrollByF,
final ListView viewF) {
final Handler h = new Handler();
h.post(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
viewF.smoothScrollBy(scrollByF, 200);
}
});
}
@Override
public void onScroll(AbsListView view, int firstVisibleItem,
int visibleItemCount, int totalItemCount) {
// TODO Auto-generated method stub
}
});
我推迟平滑滚动的原因是因为在我的测试中,直接调用状态改变回调的smoothScrollBy方法实际上有滚动问题。此外,我没有预见到一个经过充分测试的强大解决方案,它拥有非常多的状态,而在我的解决方案中,我根本就没有任何状态。此解决方案尚未在Google Play商店中使用,但应作为一个很好的起点。
答案 2 :(得分:2)
使用@nininho的解决方案
在onScrollStateChanged
状态变为SCROLL_STATE_IDLE
时,请记住要捕捉并举起旗帜的位置:
snapTo = view.getFirstVisiblePosition();
shouldSnap = true;
然后,覆盖computeScroll()
方法:
@Override
public void computeScroll() {
super.computeScroll();
if(shouldSnap){
this.smoothScrollToPositionFromTop(snapTo, 0);
shouldSnap = false;
}
}
答案 3 :(得分:1)
如果使用RecyclerView,您可以进行更流畅的滚动。 OnScrollListener更好。
我在这里做了一个例子:https://github.com/plattysoft/SnappingList
答案 4 :(得分:0)
除了尝试上面的代码之外,你应该确保你的listView的高度可以适合你想要显示的项目的确切数量。 例如 如果要在捕捉效果后显示4个项目,并且行高(在其布局中定义)应为列表总高度的1/4。
答案 5 :(得分:0)
请注意,在smoothScrollBy()
来电后,getFirstVisiblePosition()
可能会指向列表视图中最顶端的列表项。 view.getChildAt(0).getBottom() == 0
时尤其如此。我不得不打电话给view.setSelection(view.getFirstVisiblePosition() + 1)
来解决这个奇怪的行为。
答案 6 :(得分:0)
嗯..我知道问这个问题已有10年了,但是现在我们可以使用LinearSnapHelper:
new LinearSnapHelper().attachToRecyclerView(recyclerView);
来源: https://proandroiddev.com/android-recyclerview-snaphelper-19eaa9598da6