42

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

NestedScrollView contain the LinearLayout as the root child, I put the 2 TextViews into LinearLayout to enable expand/collapse animation. The one was set Visible and other one was set to Gone. And switching visibility by onClick event of LinearLayout

Normally, everything work as expected but when I scrolled the NestedScrollView the onClick event not working properly. I need double click after scroll to get expand/collapse animation

Does anyone have same problem with me ? Please help me

<android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v4.widget.NestedScrollView android:layout_width="match_parent" android:layout_height="match_parent" app:layout_behavior="@string/appbar_scrolling_view_behavior"> <LinearLayout android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" android:paddingBottom="98dp" android:paddingLeft="24dp" android:paddingRight="24dp"> <android.support.v7.widget.AppCompatTextView android:id="@+id/detail_expense_reason_trim" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="false" android:textColor="@color/add_new_expense_text_color" /> <android.support.v7.widget.AppCompatTextView android:id="@+id/detail_expense_reason" android:layout_width="match_parent" android:layout_height="wrap_content" android:singleLine="false" android:textColor="@color/add_new_expense_text_color" android:visibility="gone" /> </LinearLayout> </android.support.v4.widget.NestedScrollView> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar android:id="@+id/detail_expense_toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:layout_scrollFlags="scroll|enterAlways" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> </android.support.design.widget.AppBarLayout> 

 @InjectView(R.id.detail_expense_reason) AppCompatTextView originalReason; @InjectView(R.id.detail_expense_reason_trim) AppCompatTextView trimReason; @InjectView(R.id.detail_expense_container) LinearLayout expenseContainer; 

// Handle event

public void onClick() { if (originalReason.getVisibility() == View.VISIBLE) { originalReason.setVisibility(View.GONE); trimReason.setVisibility(View.VISIBLE); } else { originalReason.setVisibility(View.VISIBLE); trimReason.setVisibility(View.GONE); } } 
5
  • 1
    Everything work well after change NestedScrollView to ScrollView, But we miss scrolled animation to show/hide toolbar Commented Aug 6, 2015 at 3:43
  • Same problem here, did you found a solution? Commented Aug 17, 2015 at 21:59
  • 1
    It seems to be google design library bugs, I still use ScrollView instead of NestedScrollView and losing the animation. Commented Aug 18, 2015 at 11:09
  • 1
    Reported the bug on code.google.com/p/android/issues/detail?id=184028 Commented Aug 27, 2015 at 13:32
  • this worked for me ,just put OnClickListener on the child layout like Linear or Constraint Layout not on scroll view Commented Feb 22, 2022 at 6:20

8 Answers 8

32

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">

Sign up to request clarification or add additional context in comments.

2 Comments

It solves the touch issue after a fling but normal ACTION_MOVE does not work on horizontal RecyclerView inside NestedScrollView. Thanks for the solution though!!
Great Research... Saved my day!
19

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.

1 Comment

It makes another problem. If the NestedScrollView is fling ,we cannot click to stop the fling
10

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

1 Comment

This is useful .Worked for me .
1

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.

Comments

1

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" ...> 

Comments

1

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.

1 Comment

as @dustinb mentioned in his answer stackoverflow.com/a/46876273/2290950 it issue related to specific OS versions, not support lib issue. I'm on the latest versions of all libs and see this issue on my Nexus 6p (oreo - 8.1).
0

I have same issue coming,i had recyclerview and i was trying to collapse and expand, So when i do collapse, my first click do not work.. but when i do research on it and i found that i was doing scroll up my nestedScrollView on collapsing my recycleview.

 this.nestedScrollView.post { nestedScrollView.fling(0) nestedScrollView.smoothScrollBy( 0, - 100dp), 1000ms ) } 

So this fling up and scrolling up code is blocking my click listener for 1000ms. So when i handled this duration value my problem is solved :)

Comments

-1

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

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.