平滑滚动的GridView控件平滑、控件、GridView

2023-09-07 11:35:53 作者:间歇性心动

确实 smoothScrollToPosition()方法的GridView 正常工作? 我发现一个开放的 bug报告和我的是不能正常工作或者。

Does smoothScrollToPosition() method for GridView works correctly? I have found an open bug report and mine is not working correctly either.

setSelection()工作正常,但我希望有一个平滑滚动的效果。

setSelection() is working fine but I want a smooth scroll effect.

你有关于这个问题的任何想法?

Do you have any idea about this issue?

如果这是一个长期存在的问题,我应该在哪里开始实施一个良好的滚动效果?

If this is a persistent problem, where should I start to implement a good scroll effect?

推荐答案

虽然我没有看到运行的例子code,你贴了,如果你没有看到在您的应用程序一致的结果,这不是太靠谱的任何问题创建自己的滚动控制。下面是一个示例实现,你可以使用:

While I'm not seeing any issues running the example code you posted, if you're not seeing consistent results in your application it's not too tricky to create your own scroll controller. Here's an example implementation you could use:

private class ScrollPositioner {
    private static final int SCROLL_DURATION = 20;
    private static final int DIR_UP = 1;
    private static final int DIR_DOWN = 2;

    int mTargetPosition = AdapterView.INVALID_POSITION;
    int mDirection = AdapterView.INVALID_POSITION;
    int mLastSeenPosition = AdapterView.INVALID_POSITION;
    int mExtraScroll;
    GridView mGrid;

    public ScrollPositioner(GridView grid) {
        mGrid = grid;
        mExtraScroll = ViewConfiguration.get(mGrid.getContext()).getScaledFadingEdgeLength();
    }

    Handler mHandler = new Handler();
    Runnable mScroller = new Runnable() {
        public void run() {
            int firstPos = mGrid.getFirstVisiblePosition();
            switch(mDirection) {
            case DIR_UP: {
                if (firstPos == mLastSeenPosition) {
                    // No new views, let things keep going.
                    mHandler.postDelayed(mScroller, SCROLL_DURATION);
                    return;
                }

                final View firstView = mGrid.getChildAt(0);
                if (firstView == null) {
                    return;
                }
                final int firstViewTop = firstView.getTop();
                final int extraScroll = firstPos > 0 ? mExtraScroll : mGrid.getPaddingTop();

                mGrid.smoothScrollBy(firstViewTop - extraScroll, SCROLL_DURATION);

                mLastSeenPosition = firstPos;

                if (firstPos > mTargetPosition) {
                    mHandler.postDelayed(mScroller, SCROLL_DURATION);
                }
                break;
            }

            case DIR_DOWN: {
                final int lastViewIndex = mGrid.getChildCount() - 1;
                final int lastPos = firstPos + lastViewIndex;

                if (lastViewIndex < 0) {
                    return;
                }

                if (lastPos == mLastSeenPosition) {
                    // No new views, let things keep going.
                    mHandler.postDelayed(mScroller, SCROLL_DURATION);
                    return;
                }

                final View lastView = mGrid.getChildAt(lastViewIndex);
                final int lastViewHeight = lastView.getHeight();
                final int lastViewTop = lastView.getTop();
                final int lastViewPixelsShowing = mGrid.getHeight() - lastViewTop;
                final int extraScroll = lastPos < mGrid.getAdapter().getCount() - 1 ? mExtraScroll : mGrid.getPaddingBottom();

                mGrid.smoothScrollBy(lastViewHeight - lastViewPixelsShowing + extraScroll, SCROLL_DURATION);

                mLastSeenPosition = lastPos;
                if (lastPos < mTargetPosition) {
                    mHandler.postDelayed(mScroller, SCROLL_DURATION);
                }
                break;
            }

            default:
                break;
            }
        }
    };

    public void scrollToPosition(int position) {
        mTargetPosition = position;
        mLastSeenPosition = AdapterView.INVALID_POSITION;

        if(position < mGrid.getFirstVisiblePosition()) {
            mDirection = DIR_UP;
        } else if (position > mGrid.getLastVisiblePosition()) {
            mDirection = DIR_DOWN;
        } else {
            return;
        }
        mHandler.post(mScroller);
    }
}

下面是从你的链接,其中包括这个新类来实现滚动到位的框架实现的示例代码段:

Here's a snippet from the example you linked that includes where this new class to do the scrolling in place of the framework implementation:

GridView g;
boolean t= false;
@Override
public void onBackPressed() {
    //Instantiate and attach the custom positioner
    if(mPositioner == null) {
        mPositioner = new ScrollPositioner(g);
    }
    //Use the custom object to scroll the view
    mPositioner.scrollToPosition(0);
    if(t) {
        super.onBackPressed();
    }
    else {
        t = true;
    }
}

如果你想添加一个功能,所选择的位置始终滚动到顶部,即使在滚动的方向是向下,你能做到这一点。 这是不是该框架的实施是专门做,但你可以通过添加一些code。在 DIR_DOWN 继续滚动,直到完成它第一个可见的位置相匹配的目标(如 DIR_UP 一样)。您还必须提防,其中前的位置到达顶部的滚动结束的情况下,这样你就不会不断地张贴处理程序的情况下你将永远不会得到一个不同的结果。

If you want to add a feature where the selected position is always scrolled to the top even when the scrolling direction is down, you could do that. This is not something the framework's implementation is designed to do, but you could accomplish it by adding some code in DIR_DOWN to continue scrolling until the first visible position matches target (like DIR_UP does). You must also beware of the case where the scrolling ends before the position reaches the top, so you aren't constantly posting the handler in cases where you will never get a different result.

心连心