applm / ma-components

Android library with some Widgets and handy pieces of code I have developed
Other
160 stars 220 forks source link

Any solution for scrollToPosition() bug? #24

Open polaris0227 opened 6 years ago

MohamedElshafey commented 6 years ago

I make a small hack to solve this problem

go to EndlessLoopAdapterContainer.java

and replace onTouchEvent() function by this snippet

public boolean onTouchEvent(MotionEvent event) {
    if (mAdapter == null) {
        return false;
    }
    if (mVelocityTracker == null) {
        mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);

    final int action = event.getAction();
    final float x = event.getX();
    final float y = event.getY();

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            super.onTouchEvent(event);
            /*
             * If being flinged and user touches, stop the fling. isFinished
             * will be false if being flinged.
             */
            if (!mScroller.isFinished()) {
                mScroller.forceFinished(true);
            }

            downX = (int) x;
            // Remember where the motion event started
            mLastMotionX = x;
            mLastMotionY = y;

            break;
        case MotionEvent.ACTION_MOVE:
            //if we have scrolling disabled, we don't do anything
            if (!shouldRepeat && isSrollingDisabled) return false;

            if (mTouchState == TOUCH_STATE_SCROLLING) {
                // Scroll to follow the motion event
                final int deltaX = (int) (mLastMotionX - x);
                mLastMotionX = x;
                mLastMotionY = y;

                int sx = getScrollX() + deltaX;

                if (downX > x) {
                    scrollBy(5, 0);
                } else {
                    scrollBy(-5, 0);
                }
                downX = (int) x;

            } else {
                final int xDiff = (int) Math.abs(x - mLastMotionX);

                final int touchSlop = mTouchSlop;
                final boolean xMoved = xDiff > touchSlop;

                if (xMoved) {

                    // Scroll if the user moved far enough along the X axis
                    mTouchState = TOUCH_STATE_SCROLLING;
                    enableChildrenCache();

                    // Either way, cancel any pending longpress
                    if (mAllowLongPress) {
                        mAllowLongPress = false;
                        // Try canceling the long press. It could also have been scheduled
                        // by a distant descendant, so use the mAllowLongPress flag to block
                        // everything
                        cancelLongPress();
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:

            //this must be here, in case no child view returns true,
            //events will propagate back here and on intercept touch event wont be called again
            //in case of no parent it propagates here, in case of parent it usualy propagates to on cancel
            if (mHandleSelectionOnActionUp && mTouchState == TOUCH_STATE_RESTING) {
                final float d = ToolBox.getLineLength(mDown.x, mDown.y, x, y);
                if ((event.getEventTime() - event.getDownTime()) < ViewConfiguration.getLongPressTimeout() && d < mTouchSlop)
                    handleClick(mDown);
                mHandleSelectionOnActionUp = false;
            }

            //if we had normal down click and we haven't moved enough to initiate drag, take action as a click on down coordinates
            if (mTouchState == TOUCH_STATE_SCROLLING) {

                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                int initialXVelocity = (int) mVelocityTracker.getXVelocity();
                int initialYVelocity = (int) mVelocityTracker.getYVelocity();

                if (Math.abs(initialXVelocity) + Math.abs(initialYVelocity) > mMinimumVelocity) {
                    fling(-initialXVelocity, -initialYVelocity);
                } else {
                    // Release the drag
                    clearChildrenCache();
                    mTouchState = TOUCH_STATE_RESTING;
                    checkScrollPosition();
                    mAllowLongPress = false;

                    mDown.x = -1;
                    mDown.y = -1;
                }

                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
                }

                break;
            }

            // Release the drag
            clearChildrenCache();
            mTouchState = TOUCH_STATE_RESTING;
            mAllowLongPress = false;

            mDown.x = -1;
            mDown.y = -1;

            break;
        case MotionEvent.ACTION_CANCEL:          

            mAllowLongPress = false;

            mDown.x = -1;
            mDown.y = -1;

            if (mTouchState == TOUCH_STATE_SCROLLING) {
                if (checkScrollPosition()) {
                    break;
                }
            }

            mTouchState = TOUCH_STATE_RESTING;
    }

    return true;
}
ArcherEmiya05 commented 3 years ago

I make a small hack to solve this problem

go to EndlessLoopAdapterContainer.java

and replace onTouchEvent() function by this snippet

public boolean onTouchEvent(MotionEvent event) {
    if (mAdapter == null) {
        return false;
    }
    if (mVelocityTracker == null) {
        mVelocityTracker = VelocityTracker.obtain();
    }
    mVelocityTracker.addMovement(event);

    final int action = event.getAction();
    final float x = event.getX();
    final float y = event.getY();

    switch (action) {
        case MotionEvent.ACTION_DOWN:
            super.onTouchEvent(event);
            /*
             * If being flinged and user touches, stop the fling. isFinished
             * will be false if being flinged.
             */
            if (!mScroller.isFinished()) {
                mScroller.forceFinished(true);
            }

            downX = (int) x;
            // Remember where the motion event started
            mLastMotionX = x;
            mLastMotionY = y;

            break;
        case MotionEvent.ACTION_MOVE:
            //if we have scrolling disabled, we don't do anything
            if (!shouldRepeat && isSrollingDisabled) return false;

            if (mTouchState == TOUCH_STATE_SCROLLING) {
                // Scroll to follow the motion event
                final int deltaX = (int) (mLastMotionX - x);
                mLastMotionX = x;
                mLastMotionY = y;

                int sx = getScrollX() + deltaX;

                if (downX > x) {
                    scrollBy(5, 0);
                } else {
                    scrollBy(-5, 0);
                }
                downX = (int) x;

            } else {
                final int xDiff = (int) Math.abs(x - mLastMotionX);

                final int touchSlop = mTouchSlop;
                final boolean xMoved = xDiff > touchSlop;

                if (xMoved) {

                    // Scroll if the user moved far enough along the X axis
                    mTouchState = TOUCH_STATE_SCROLLING;
                    enableChildrenCache();

                    // Either way, cancel any pending longpress
                    if (mAllowLongPress) {
                        mAllowLongPress = false;
                        // Try canceling the long press. It could also have been scheduled
                        // by a distant descendant, so use the mAllowLongPress flag to block
                        // everything
                        cancelLongPress();
                    }
                }
            }
            break;
        case MotionEvent.ACTION_UP:

            //this must be here, in case no child view returns true,
            //events will propagate back here and on intercept touch event wont be called again
            //in case of no parent it propagates here, in case of parent it usualy propagates to on cancel
            if (mHandleSelectionOnActionUp && mTouchState == TOUCH_STATE_RESTING) {
                final float d = ToolBox.getLineLength(mDown.x, mDown.y, x, y);
                if ((event.getEventTime() - event.getDownTime()) < ViewConfiguration.getLongPressTimeout() && d < mTouchSlop)
                    handleClick(mDown);
                mHandleSelectionOnActionUp = false;
            }

            //if we had normal down click and we haven't moved enough to initiate drag, take action as a click on down coordinates
            if (mTouchState == TOUCH_STATE_SCROLLING) {

                mVelocityTracker.computeCurrentVelocity(1000, mMaximumVelocity);
                int initialXVelocity = (int) mVelocityTracker.getXVelocity();
                int initialYVelocity = (int) mVelocityTracker.getYVelocity();

                if (Math.abs(initialXVelocity) + Math.abs(initialYVelocity) > mMinimumVelocity) {
                    fling(-initialXVelocity, -initialYVelocity);
                } else {
                    // Release the drag
                    clearChildrenCache();
                    mTouchState = TOUCH_STATE_RESTING;
                    checkScrollPosition();
                    mAllowLongPress = false;

                    mDown.x = -1;
                    mDown.y = -1;
                }

                if (mVelocityTracker != null) {
                    mVelocityTracker.recycle();
                    mVelocityTracker = null;
                }

                break;
            }

            // Release the drag
            clearChildrenCache();
            mTouchState = TOUCH_STATE_RESTING;
            mAllowLongPress = false;

            mDown.x = -1;
            mDown.y = -1;

            break;
        case MotionEvent.ACTION_CANCEL:          

            mAllowLongPress = false;

            mDown.x = -1;
            mDown.y = -1;

            if (mTouchState == TOUCH_STATE_SCROLLING) {
                if (checkScrollPosition()) {
                    break;
                }
            }

            mTouchState = TOUCH_STATE_RESTING;
    }

    return true;
}

Where did you get downX?