列表视图对齐项目

时间:2010-12-13 18:36:29

标签: android listview

我正在使用ListView创建图片列表,照片的大小可以在屏幕上显示2到3张照片。

我遇到的问题是,当用户停止滚动显示可见列表的第一项会捕捉到屏幕顶部时,我想这样做,例如,如果滚动结束并且第一项的一小部分显示图片后,我们向下滚动列表,以便图片始终完全显示,如果显示的是大部分图片,我们将列表向上滚动,以便下一张图片完全可见。

有没有办法在android中使用listview实现这个目的?

7 个答案:

答案 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