Two solutions for scrolling conflicts in Android

When will you encounter a scrolling conflict

There are many widgets in Android that users can drag, slide or scroll. Such as SeekBar, ViewPager, ScrollView, RecyclerView and so on. With the change of product requirements, UI becomes more and more complex, and it is inevitable that there will be multiple nested scrollable views, such as ViewPager in ViewPager, ViewPager in ScrollView, RecyclerView in ViewPager. And there are some scrollable custom views nested with standard widgets.

What causes a scrolling conflict

Generally speaking, when a scrolling conflict occurs, there must be a scrollable parent widget as a container that wraps a scrollable child widget.

What are the ideas for resolving scrolling conflicts

Since the event must be dispatched through the parent view, the parent view can listen to touch events, recognize scrolling gestures, and let ViewGroup.onInterceptTouchEvent return true when it needs to handle scrolling. But this is not enough, because the parent view does not know what the logic of its internal child view is, and the scrollable child view does not know whether its parent view knows when it can be intercepted and when it cannot be intercepted. Therefore, the parent view provides the ViewGroup.requestDisallowInterceptTouchEvent method for the child view to notify the parent view when it can be intercepted and when it cannot be intercepted.

Scrolling threshold

When the event flows through the parent view, the parent view does not intercept the event, but always calculates the user’s scrolling direction and distance. Once the angle between the user’s scrolling direction and his own scrollable direction is less than a certain degree, and the sliding distance exceeds a threshold, and the child control does not prohibit the parent view from intercepting, the parent control returns true in ViewGroup.onInterceptTouchEvent to intercept the event. Then hand over to ViewGroup.onTouchEvent to handle the scrolling. If the child view prohibits the parent view from intercepting events, the parent view does not intercept events and does not need to recognize scrolling gestures.

Actively detect scrollable direction

Since the scrolling threshold does not work in some cases, an active detection method is required. That is, after the parent view detects the scrolling event, it first detects the scrollability of the child view in the direction and distance. If the child view is not scrollable, the event is intercepted by the parent view; if the child control is scrollable, the event is dispatched normally. And the child view handles the scrolling event by itself and prohibits the parent view from intercepting. There are exactly two methods: View.canScrollHorizontally and View.canScrollVertically. There are also implementations of compatible versions in the support package.

Nested scrolling widgets

The nested scrolling itself is to solve the cooperative scrolling problem of nested scrollabed widgets. As mentioned earlier, a scrolling event is either handled by the parent view or by the child view. It is difficult to make a child view consume a part of the scrolling event, and then pass the rest to the parent view for consumption, or the parent view consumes a part and then pass the rest to the child view for consumption.

How to handling scrolling conflicts in actual development

If you are writing a scrollable parent view (that is, a view container, and other scrollable views may be nested inside), use the scrolling threshold is enough for most cases. If you want to achieve more precise control, you can use View.canScrollXXX to detect the scrollability of child views.

--

--

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store