onClick method not working properly after NestedScrollView scrolled

前端 未结 7 930
梦毁少年i
梦毁少年i 2020-11-30 23:13

I used NestedScrollView with CoordinatorLayout to enable scroll animation for Toolbar (by app:layout_scrollFlags=\"scroll|enterAlways\").

NestedScrollView contain th

相关标签:
7条回答
  • 2020-11-30 23:26

    It is a Bug mention at Google #issues 194398.

    Just need to use this WorkaroundNestedScrollView.java class which extends NestedScrollView like,

    WorkaroundNestedScrollView.java

    public class WorkaroundNestedScrollView extends NestedScrollView {
    
    public WorkaroundNestedScrollView(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    public boolean onInterceptTouchEvent(MotionEvent ev) {
        if (ev.getAction() == MotionEvent.ACTION_DOWN) {
            // Explicitly call computeScroll() to make the Scroller compute itself
            computeScroll();
        }
        return super.onInterceptTouchEvent(ev);
    }
    }
    

    And in yourlayout use it like this,

    layout.xml

    <com.yourpackagename.whatever.WorkaroundNestedScrollView
        android:layout_width="match_parent"
        android:layout_height="match_parent">
    ...
    ...
    
    </com.yourpackagename.whatever.WorkaroundNestedScrollView>
    

    You can alson find more details here.

    0 讨论(0)
  • 2020-11-30 23:28

    Best solution :

    1) Create this class :

    public class FixAppBarLayoutBehavior extends AppBarLayout.Behavior {
    
    public FixAppBarLayoutBehavior() {
        super();
    }
    
    public FixAppBarLayoutBehavior(Context context, AttributeSet attrs) {
        super(context, attrs);
    }
    
    @Override
    public void onNestedScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child, View target,
            int dxConsumed, int dyConsumed, int dxUnconsumed, int dyUnconsumed, int type) {
        super.onNestedScroll(coordinatorLayout, child, target, dxConsumed, dyConsumed,
                dxUnconsumed, dyUnconsumed, type);
        stopNestedScrollIfNeeded(dyUnconsumed, child, target, type);
    }
    
    @Override
    public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, AppBarLayout child,
            View target, int dx, int dy, int[] consumed, int type) {
        super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed, type);
        stopNestedScrollIfNeeded(dy, child, target, type);
    }
    
    private void stopNestedScrollIfNeeded(int dy, AppBarLayout child, View target, int type) {
        if (type == ViewCompat.TYPE_NON_TOUCH) {
            final int currOffset = getTopAndBottomOffset();
            if ((dy < 0 && currOffset == 0)
                    || (dy > 0 && currOffset == -child.getTotalScrollRange())) {
                ViewCompat.stopNestedScroll(target, ViewCompat.TYPE_NON_TOUCH);
            }
        }
    }}
    

    2) And use in xml :

    <android.support.design.widget.AppBarLayout
    ...
    app:layout_behavior="yourPackageName.FixAppBarLayoutBehavior"
    ...>
    
    0 讨论(0)
  • 2020-11-30 23:33

    I met this problem too

        public class NestedScrollView extends FrameLayout implements NestedScrollingParent,
        NestedScrollingChild, ScrollingView {
           @Override
            public boolean onTouchEvent(MotionEvent ev) {
              switch (actionMasked) {
                case MotionEvent.ACTION_DOWN: {
                    if (getChildCount() == 0) {
                        return false;
                    }
                    //add this line
                    if (!inChild((int) ev.getX(), (int) ev.getY())) {
                        return false;
                    }
                    if ((mIsBeingDragged = !mScroller.isFinished())) {
                            final ViewParent parent = getParent();
                        if (parent != null) {
                            parent.requestDisallowInterceptTouchEvent(true);
                        }
                    }
               }
          }
    

    and I change my xml file,change paddingTop to margin_top,then my top floating view's OnClick event will not be intercepted by NestedScrollView

    0 讨论(0)
  • 2020-11-30 23:43

    I've opened another issue here: https://issuetracker.google.com/issues/68103042 as it still seems to be an issue in Oreo for us (multiple devices, including emulators).

    My fix (adapted from ta..@graymeter.com's suggestions at https://issuetracker.google.com/issues/37051723) doesn't require modifying AOSP code as it uses reflection:

    public class MyNestedScrollView extends NestedScrollView {
    
        private static final Logger sLogger = LogFactory.getLogger(MyNestedScrollView.class);
    
        private OverScroller mScroller;
        public boolean isFling = false;
    
        public MyNestedScrollView(Context context, AttributeSet attrs) {
            super(context, attrs);
            mScroller = getOverScroller();
        }
    
        @Override
        public void fling(int velocityY) {
            super.fling(velocityY);
    
            // here we effectively extend the super class functionality for backwards compatibility and just call invalidateOnAnimation()
            if (getChildCount() > 0) {
                ViewCompat.postInvalidateOnAnimation(this);
    
                // Initializing isFling to true to track fling action in onScrollChanged() method
                isFling = true;
            }
        }
    
        @Override
        protected void onScrollChanged(int l, final int t, final int oldl, int oldt) {
            super.onScrollChanged(l, t, oldl, oldt);
    
            if (isFling) {
                if (Math.abs(t - oldt) <= 3 || t == 0 || t == (getChildAt(0).getMeasuredHeight() - getMeasuredHeight())) {
                    isFling = false;
    
                    // This forces the mFinish variable in scroller to true (as explained the
                    //    mentioned link above) and does the trick
                    if (mScroller != null) {
                        mScroller.abortAnimation();
                    }
                }
            }
        }
    
        private OverScroller getOverScroller() {
            Field fs = null;
            try {
                fs = this.getClass().getSuperclass().getDeclaredField("mScroller");
                fs.setAccessible(true);
                return (OverScroller) fs.get(this);
            } catch (Throwable t) {
                return null;
            }
        }
    }
    
    0 讨论(0)
  • 2020-11-30 23:45

    It is a bug of the NestedScrollView, the detail of the bug can be found in here: issue. The problem is that mScroller.isFinished() in onInterceptTouchEvent(MotionEvent ev) will not return true after a fling operation (even if the fling is stopped). Therefore the touch event is intercepted.

    This bug have been reported for a while, but still have not been fixed. So I have created by own version of bug fix for this problem. I implemented my own NestedScrollView, copied all the code from NestedScrollView and having the with the following amendments:

    public class NestedScrollView extends FrameLayout implements NestedScrollingParent, NestedScrollingChild {
        ...
        private void initScrollView() {
            ...
            // replace this line:
            // mScroller = new ScrollerCompat(getContext(), null);
            mScroller = ScrollerCompat.create(getContext(), null);
            ...
        }
    
        @Override
        public boolean onInterceptTouchEvent(MotionEvent ev) {
            ...
            switch (action & MotionEventCompat.ACTION_MASK) {
                ...
                case MotionEvent.ACTION_DOWN: {
                    ...
                    // replace this line:
                    // mIsBeingDragged = !mScroller.isFinished();
                    mIsBeingDragged = false;
                    ...
                }
            }
        }   
    }
    

    And this NestedScrollView should have the same behaviour as the original one.

    0 讨论(0)
  • 2020-11-30 23:48

    This was an issue in support libraries. see this https://issuetracker.google.com/u/1/issues/37070828

    If you are using androidX then

    'androidx.appcompat:appcompat:1.1.0-alpha04'.
    

    will probably fix this issue though this is an alpha build.

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