Smooth Scroll for GridView

前端 未结 2 805
日久生厌
日久生厌 2021-01-19 06:20

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

<
相关标签:
2条回答
  • 2021-01-19 07:13

    Had the same issue- I built a simple GridView and for some reason the smoothScrollToPosition() didn't work at all (just bounce from time to time).

    after lot of debugging it turn out to be that I need to remove the android:padding parameter from the GridView.

    very strange, I really don't know why it is like this, but at least now it works.

    0 讨论(0)
  • 2021-01-19 07:15

    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;
        }
    }
    

    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.

    HTH

    0 讨论(0)
提交回复
热议问题