Skip to content

Commit

Permalink
Modify NestedScrollableHost to suit our need
Browse files Browse the repository at this point in the history
Now manages nested child scrolling when the orientation is perpendicular
  • Loading branch information
ebraminio committed Apr 21, 2020
1 parent 6f74af7 commit cd93435
Showing 1 changed file with 23 additions and 45 deletions.
Expand Up @@ -14,6 +14,7 @@
* limitations under the License.
*
* Source: https://github.com/android/views-widgets-samples/blob/87e58d1/ViewPager2/app/src/main/java/androidx/viewpager2/integration/testapp/NestedScrollableHost.kt
* And modified for our need
*/

package de.danoeh.antennapod.view;
Expand All @@ -23,21 +24,23 @@
import android.view.MotionEvent;
import android.view.View;
import android.view.ViewConfiguration;
import android.view.ViewParent;
import android.widget.FrameLayout;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.viewpager2.widget.ViewPager2;

import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_HORIZONTAL;
import static androidx.viewpager2.widget.ViewPager2.ORIENTATION_VERTICAL;

/**
* Layout to wrap a scrollable component inside a ViewPager2. Provided as a solution to the problem
* where pages of ViewPager2 have nested scrollable elements that scroll in the same direction as
* ViewPager2. The scrollable element needs to be the immediate and only child of this host layout.
*
* <p>This solution has limitations when using multiple levels of nested scrollable elements
* (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).</p>
* (e.g. a horizontal RecyclerView in a vertical RecyclerView in a horizontal ViewPager2).
*/
class NestedScrollableHost extends FrameLayout {

Expand All @@ -63,47 +66,19 @@ private ViewPager2 getParentViewPager() {
return v == null ? null : (ViewPager2) v;
}

private View getChild() {
return getChildCount() > 0 ? getChildAt(0) : null;
}

private boolean canChildScroll(int orientation, float delta) {
int direction = (int) -Math.copySign(1, delta);
View child = getChild();
if (child == null) {
return false;
}
switch (orientation) {
case 0:
return child.canScrollHorizontally(direction);
case 1:
return child.canScrollVertically(direction);
default:
return false;
}
}

public boolean onInterceptTouchEvent(MotionEvent e) {
handleInterceptTouchEvent(e);
return super.onInterceptTouchEvent(e);
}

private void handleInterceptTouchEvent(MotionEvent e) {
ViewPager2 parentViewPager = getParentViewPager();
if (parentViewPager == null) {
return;
return super.onInterceptTouchEvent(e);
}
int orientation = parentViewPager.getOrientation();

// Early return if child can't scroll in same direction as parent
if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f)) {
return;
}
ViewParent parent = getParent();
int orientation = parentViewPager.getOrientation();

if (e.getAction() == MotionEvent.ACTION_DOWN) {
initialX = e.getX();
initialY = e.getY();
getParent().requestDisallowInterceptTouchEvent(true);
parent.requestDisallowInterceptTouchEvent(true);
} else if (e.getAction() == MotionEvent.ACTION_MOVE) {
int dx = (int) (e.getX() - initialX);
int dy = (int) (e.getY() - initialY);
Expand All @@ -112,22 +87,25 @@ private void handleInterceptTouchEvent(MotionEvent e) {
// assuming ViewPager2 touch-slop is 2x touch-slop of child
float scaledDx = Math.abs(dx) * (isVpHorizontal ? .5f : 1f);
float scaledDy = Math.abs(dy) * (isVpHorizontal ? 1f : .5f);

if (scaledDx > touchSlop || scaledDy > touchSlop) {
int value = isVpHorizontal ? dy : dx;
if (isVpHorizontal == (scaledDy > scaledDx)) {
// Gesture is perpendicular, allow all parents to intercept
getParent().requestDisallowInterceptTouchEvent(false);
} else {
// Gesture is parallel, query child if movement in that direction is possible
if (canChildScroll(orientation, isVpHorizontal ? dx : dy)) {
// Child can scroll, disallow all parents to intercept
getParent().requestDisallowInterceptTouchEvent(true);
} else {
// Child cannot scroll, allow all parents to intercept
getParent().requestDisallowInterceptTouchEvent(false);
}
// Gesture is perpendicular
orientation = orientation == ORIENTATION_VERTICAL
? ORIENTATION_HORIZONTAL : ORIENTATION_VERTICAL;
value = isVpHorizontal ? dy : dx;
}

int direction = (int) -Math.copySign(1, value);
View child = getChildAt(0);
if (orientation == ORIENTATION_HORIZONTAL)
parent.requestDisallowInterceptTouchEvent(child.canScrollHorizontally(direction));
else {
parent.requestDisallowInterceptTouchEvent(child.canScrollVertically(direction));
}
}
}

return super.onInterceptTouchEvent(e);
}
}

0 comments on commit cd93435

Please sign in to comment.