onClick method not working properly after NestedScrollView scrolled
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 [email protected]'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;
}
}
}
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.
I found solution for same problem on this thread :The item inside RecyclerView can't be clicked right after scrolling
You can fix your code by adding layout_behavior to your AppBarLayout.You can find code here Fixed AppBarLayout.Behavior .Just add this class tou your project and fix your code :
<android.support.design.widget.AppBarLayout
android:layout_width="match_parent"
app:layout_behavior="yourPackageName.FixAppBarLayoutBehavior"
android:layout_height="wrap_content">
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.