I have a single vertical nestedscrollview that contains a bunch of recyclerview with a horizontal layoutmanager setup. The idea is pretty similar to how the new google play
Since falc0nit3 solution doesn't work anymore (currently the project using 28.0.0
version of support library), i have found an another one.
The background reason of the issue is still the same, scrollable view eats on down event by returning true
on the second tap, where it shouldn't, because naturally second tap on the fling view stops scrolling and may be used with next move
event to start opposite scroll
The issue is reproduced as with NestedScrollView
as with RecyclerView
.
My solution is to stop scrolling manually before native view will be able to intercept it in onInterceptTouchEvent
. In this case it won't eat the ACTION_DOWN
event, because it have been stopped already.
So, for NestedScrollView
:
class NestedScrollViewFixed(context: Context, attrs: AttributeSet) :
NestedScrollView(context, attrs) {
override fun onInterceptTouchEvent(ev: MotionEvent): Boolean {
if (ev.actionMasked == MotionEvent.ACTION_DOWN) {
onTouchEvent(ev)
}
return super.onInterceptTouchEvent(ev)
}
}
For RecyclerView
:
class RecyclerViewFixed(context: Context, attrs: AttributeSet) :
RecyclerView(context, attrs) {
override fun onInterceptTouchEvent(e: MotionEvent): Boolean {
if (e.actionMasked == MotionEvent.ACTION_DOWN) {
this.stopScroll()
}
return super.onInterceptTouchEvent(e)
}
}
Despite solution for RecyclerView
looks easy to read, for NestedScrollView
it's a bit complicated.
Unfortunately, there is no clear way to stop scrolling manually in widget, which the only responsibility is to manage scroll (omg). I'm interesting in abortAnimatedScroll()
method, but it is private. It is possible to use reflection to get around it, but for me better is to call method, which calls abortAnimatedScroll()
itself.
Look at onTouchEvent
handling of ACTION_DOWN
:
/*
* If being flinged and user touches, stop the fling. isFinished
* will be false if being flinged.
*/
if (!mScroller.isFinished()) {
Log.i(TAG, "abort animated scroll");
abortAnimatedScroll();
}
Basically stopping fling is managed in this method, but a bit later, than we have to call it to fix the bug
Unfortunately due to this we can't just create OnTouchListener
and set it outside, so only inheritance fits the requirements