diff options
author | ueen <ueli.sarnighausen@online.de> | 2021-05-14 21:06:04 +0200 |
---|---|---|
committer | GitHub <noreply@github.com> | 2021-05-14 21:06:04 +0200 |
commit | 292c9bf15136f76fea8928ed7abb2b55fb316678 (patch) | |
tree | 144f3969825b2b910e6bc0640325942bb8ed969e /app/src/main/java/de/danoeh/antennapod/view | |
parent | fb6bd0cbaa909b6067fedef1e8a108130841f3fe (diff) | |
download | AntennaPod-292c9bf15136f76fea8928ed7abb2b55fb316678.zip |
New media player screen (#5075)
Co-authored-by: jonasburian <jonas.burian@protonmail.com>
Co-authored-by: ByteHamster <info@bytehamster.com>
Diffstat (limited to 'app/src/main/java/de/danoeh/antennapod/view')
-rw-r--r-- | app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java | 165 |
1 files changed, 127 insertions, 38 deletions
diff --git a/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java b/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java index 0e1846f1c..ff52df71f 100644 --- a/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java +++ b/app/src/main/java/de/danoeh/antennapod/view/NestedScrollableHost.java @@ -20,92 +20,181 @@ package de.danoeh.antennapod.view; import android.content.Context; +import android.content.res.TypedArray; +import android.os.Build; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.view.ViewConfiguration; -import android.view.ViewParent; +import android.view.ViewTreeObserver; import android.widget.FrameLayout; import androidx.annotation.NonNull; import androidx.annotation.Nullable; +import androidx.annotation.RequiresApi; import androidx.viewpager2.widget.ViewPager2; +import de.danoeh.antennapod.R; + 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 + * 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). - */ -class NestedScrollableHost extends FrameLayout { + */ // KhaledAlharthi/NestedScrollableHost.java +public class NestedScrollableHost extends FrameLayout { + + private ViewPager2 parentViewPager; + private int touchSlop = 0; + private float initialX = 0f; + private float initialY = 0f; + private int preferVertical = 1; + private int preferHorizontal = 1; + private int scrollDirection = 0; public NestedScrollableHost(@NonNull Context context) { super(context); - touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + init(context); } public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs) { super(context, attrs); + init(context); + setAttributes(context, attrs); + } + + public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, int defStyleAttr) { + super(context, attrs, defStyleAttr); + init(context); + setAttributes(context, attrs); + } + + @RequiresApi(api = Build.VERSION_CODES.LOLLIPOP) + public NestedScrollableHost(@NonNull Context context, @Nullable AttributeSet attrs, + int defStyleAttr, int defStyleRes) { + super(context, attrs, defStyleAttr, defStyleRes); + init(context); + setAttributes(context, attrs); + } + + private void setAttributes(@NonNull Context context, @Nullable AttributeSet attrs) { + TypedArray a = context.getTheme().obtainStyledAttributes( + attrs, + R.styleable.NestedScrollableHost, + 0, 0); + + try { + preferHorizontal = a.getInteger(R.styleable.NestedScrollableHost_preferHorizontal, 1); + preferVertical = a.getInteger(R.styleable.NestedScrollableHost_preferVertical, 1); + scrollDirection = a.getInteger(R.styleable.NestedScrollableHost_scrollDirection, 0); + } finally { + a.recycle(); + } + + } + + private void init(Context context) { touchSlop = ViewConfiguration.get(context).getScaledTouchSlop(); + + + getViewTreeObserver().addOnPreDrawListener(new ViewTreeObserver.OnPreDrawListener() { + @Override + public boolean onPreDraw() { + View v = (View) getParent(); + while (v != null && !(v instanceof ViewPager2) || isntSameDirection(v)) { + v = (View) v.getParent(); + } + parentViewPager = (ViewPager2) v; + + getViewTreeObserver().removeOnPreDrawListener(this); + return false; + } + }); } - private int touchSlop; - private float initialX = 0f; - private float initialY = 0f; + private Boolean isntSameDirection(View v) { + int orientation = 0; + switch (scrollDirection) { + default: + case 0: + return false; + case 1: + orientation = ORIENTATION_VERTICAL; + break; + case 2: + orientation = ORIENTATION_HORIZONTAL; + break; + } + return ((v instanceof ViewPager2) && ((ViewPager2) v).getOrientation() != orientation); + } + + + @Override + public boolean onInterceptTouchEvent(MotionEvent ev) { + handleInterceptTouchEvent(ev); + return super.onInterceptTouchEvent(ev); + } - private ViewPager2 getParentViewPager() { - View v = (View) getParent(); - while (v != null && !(v instanceof ViewPager2)) { - v = (View) v.getParent(); + + private boolean canChildScroll(int orientation, float delta) { + int direction = (int) -delta; + View child = getChildAt(0); + if (orientation == 0) { + return child.canScrollHorizontally(direction); + } else if (orientation == 1) { + return child.canScrollVertically(direction); + } else { + throw new IllegalArgumentException(); } - return v == null ? null : (ViewPager2) v; } - public boolean onInterceptTouchEvent(MotionEvent e) { - ViewPager2 parentViewPager = getParentViewPager(); + private void handleInterceptTouchEvent(MotionEvent e) { if (parentViewPager == null) { - return super.onInterceptTouchEvent(e); + return; } - - ViewParent parent = getParent(); int orientation = parentViewPager.getOrientation(); + boolean preferedDirection = preferHorizontal + preferVertical > 2; + + // Early return if child can't scroll in same direction as parent and theres no prefered scroll direction + if (!canChildScroll(orientation, -1f) && !canChildScroll(orientation, 1f) && !preferedDirection) { + return; + } + if (e.getAction() == MotionEvent.ACTION_DOWN) { initialX = e.getX(); initialY = e.getY(); - parent.requestDisallowInterceptTouchEvent(true); + getParent().requestDisallowInterceptTouchEvent(true); } else if (e.getAction() == MotionEvent.ACTION_MOVE) { - int dx = (int) (e.getX() - initialX); - int dy = (int) (e.getY() - initialY); - boolean isVpHorizontal = orientation == ORIENTATION_HORIZONTAL; + float dx = e.getX() - initialX; + float dy = e.getY() - initialY; + boolean isVpHorizontal = orientation == ViewPager2.ORIENTATION_HORIZONTAL; // 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); + float scaledDx = Math.abs(dx) * (isVpHorizontal ? 1f : 0.5f) * preferHorizontal; + float scaledDy = Math.abs(dy) * (isVpHorizontal ? 0.5f : 1f) * preferVertical; if (scaledDx > touchSlop || scaledDy > touchSlop) { - int value = isVpHorizontal ? dy : dx; if (isVpHorizontal == (scaledDy > scaledDx)) { - // 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)); + // Gesture is perpendicular, allow all parents to intercept + getParent().requestDisallowInterceptTouchEvent(preferedDirection); } else { - parent.requestDisallowInterceptTouchEvent(child.canScrollVertically(direction)); + // 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); + } } } - } - return super.onInterceptTouchEvent(e); + } } } |