Going down the BottomSheetBehavior rabbit hole...

BottomSheetBehavior only supports one scrolling child. Add support for a ViewPager.
ViewPager.getChildAt sometimes does not match the actual position.
Make sure that it keeps all children using setOffscreenPageLimit
This commit is contained in:
ByteHamster 2020-03-23 14:05:11 +01:00
parent 6b79daacfe
commit 5ad7228b4e
6 changed files with 110 additions and 19 deletions

View File

@ -0,0 +1,75 @@
package com.google.android.material.bottomsheet;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.ViewGroup;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import androidx.core.view.ViewCompat;
import androidx.viewpager.widget.ViewPager;
import java.lang.ref.WeakReference;
/**
* Override {@link #findScrollingChild(View)} to support {@link ViewPager}'s nested scrolling.
* By the way, In order to override package level method and field.
* This class put in the same package path where {@link BottomSheetBehavior} located.
* Source: https://medium.com/@hanru.yeh/funny-solution-that-makes-bottomsheetdialog-support-viewpager-with-nestedscrollingchilds-bfdca72235c3
*/
public class ViewPagerBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
public ViewPagerBottomSheetBehavior() {
super();
}
public ViewPagerBottomSheetBehavior(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
View findScrollingChild(View view) {
if (ViewCompat.isNestedScrollingEnabled(view)) {
return view;
}
if (view instanceof ViewPager) {
ViewPager viewPager = (ViewPager) view;
View currentViewPagerChild = viewPager.getChildAt(viewPager.getCurrentItem());
return findScrollingChild(currentViewPagerChild);
} else if (view instanceof ViewGroup) {
ViewGroup group = (ViewGroup) view;
for (int i = 0, count = group.getChildCount(); i < count; i++) {
View scrollingChild = findScrollingChild(group.getChildAt(i));
if (scrollingChild != null) {
return scrollingChild;
}
}
}
return null;
}
public void updateScrollingChild() {
final View scrollingChild = findScrollingChild(viewRef.get());
nestedScrollingChildRef = new WeakReference<>(scrollingChild);
}
/**
* A utility function to get the {@link ViewPagerBottomSheetBehavior} associated with the {@code view}.
*
* @param view The {@link View} with {@link ViewPagerBottomSheetBehavior}.
* @return The {@link ViewPagerBottomSheetBehavior} associated with the {@code view}.
*/
@SuppressWarnings("unchecked")
public static <V extends View> ViewPagerBottomSheetBehavior<V> from(V view) {
ViewGroup.LayoutParams params = view.getLayoutParams();
if (!(params instanceof CoordinatorLayout.LayoutParams)) {
throw new IllegalArgumentException("The view is not a child of CoordinatorLayout");
}
CoordinatorLayout.Behavior behavior = ((CoordinatorLayout.LayoutParams) params).getBehavior();
if (!(behavior instanceof ViewPagerBottomSheetBehavior)) {
throw new IllegalArgumentException(
"The view is not associated with ViewPagerBottomSheetBehavior");
}
return (ViewPagerBottomSheetBehavior<V>) behavior;
}
}

View File

@ -2,7 +2,6 @@ package de.danoeh.antennapod.adapter;
import android.content.Context;
import android.text.TextUtils;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
@ -116,7 +115,6 @@ public class ChaptersListAdapter extends RecyclerView.Adapter<ChaptersListAdapte
@Override
public int getItemCount() {
if (media == null || media.getChapters() == null) {
Log.d("aaaaa", "0");
return 0;
}
// ignore invalid chapters
@ -126,7 +124,6 @@ public class ChaptersListAdapter extends RecyclerView.Adapter<ChaptersListAdapte
counter++;
}
}
Log.d("aaaaa", "0"+counter);
return counter;
}

View File

@ -16,7 +16,7 @@ import androidx.annotation.Nullable;
import androidx.appcompat.widget.Toolbar;
import androidx.fragment.app.Fragment;
import androidx.fragment.app.FragmentManager;
import androidx.fragment.app.FragmentStatePagerAdapter;
import androidx.fragment.app.FragmentPagerAdapter;
import androidx.viewpager.widget.ViewPager;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import de.danoeh.antennapod.R;
@ -119,6 +119,14 @@ public class AudioPlayerFragment extends Fragment implements
pager = root.findViewById(R.id.pager);
AudioPlayerPagerAdapter pagerAdapter = new AudioPlayerPagerAdapter(getFragmentManager());
pager.setAdapter(pagerAdapter);
// Required for getChildAt(int) in ViewPagerBottomSheetBehavior to return the correct page
pager.setOffscreenPageLimit(NUM_CONTENT_FRAGMENTS);
pager.addOnPageChangeListener(new ViewPager.SimpleOnPageChangeListener() {
@Override
public void onPageSelected(int position) {
pager.post(() -> ((MainActivity) getActivity()).getBottomSheet().updateScrollingChild());
}
});
pageIndicator = root.findViewById(R.id.page_indicator);
pageIndicator.setViewPager(pager);
pageIndicator.setOnClickListener(v ->
@ -468,7 +476,7 @@ public class AudioPlayerFragment extends Fragment implements
return false;
}
private static class AudioPlayerPagerAdapter extends FragmentStatePagerAdapter {
private static class AudioPlayerPagerAdapter extends FragmentPagerAdapter {
private static final String TAG = "AudioPlayerPagerAdapter";
public AudioPlayerPagerAdapter(FragmentManager fm) {

View File

@ -10,6 +10,7 @@ import android.view.View;
import android.view.ViewGroup;
import androidx.annotation.NonNull;
import androidx.fragment.app.Fragment;
import de.danoeh.antennapod.R;
import de.danoeh.antennapod.core.util.playback.PlaybackController;
import de.danoeh.antennapod.core.util.playback.Timeline;
import de.danoeh.antennapod.view.ShownotesWebView;
@ -35,7 +36,8 @@ public class ItemDescriptionFragment extends Fragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
Log.d(TAG, "Creating view");
webvDescription = new ShownotesWebView(getActivity().getApplicationContext());
View root = inflater.inflate(R.layout.item_description_fragment, container, false);
webvDescription = root.findViewById(R.id.webview);
webvDescription.setTimecodeSelectedListener(time -> {
if (controller != null) {
controller.seekTo(time);
@ -46,7 +48,7 @@ public class ItemDescriptionFragment extends Fragment {
webvDescription.postDelayed(ItemDescriptionFragment.this::restoreFromPreference, 50);
});
registerForContextMenu(webvDescription);
return webvDescription;
return root;
}
@Override

View File

@ -5,14 +5,13 @@ import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
import androidx.coordinatorlayout.widget.CoordinatorLayout;
import com.google.android.material.bottomsheet.BottomSheetBehavior;
import com.google.android.material.bottomsheet.ViewPagerBottomSheetBehavior;
/**
* Based on https://stackoverflow.com/a/40798214
*/
public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBehavior<V> {
private boolean mLocked = false;
public class LockableBottomSheetBehavior<V extends View> extends ViewPagerBottomSheetBehavior<V> {
private boolean isLocked = false;
public LockableBottomSheetBehavior() {}
@ -21,14 +20,14 @@ public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBeha
}
public void setLocked(boolean locked) {
mLocked = locked;
isLocked = locked;
}
@Override
public boolean onInterceptTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
boolean handled = false;
if (!mLocked) {
if (!isLocked) {
handled = super.onInterceptTouchEvent(parent, child, event);
}
@ -39,7 +38,7 @@ public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBeha
public boolean onTouchEvent(CoordinatorLayout parent, V child, MotionEvent event) {
boolean handled = false;
if (!mLocked) {
if (!isLocked) {
handled = super.onTouchEvent(parent, child, event);
}
@ -51,7 +50,7 @@ public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBeha
View target, int nestedScrollAxes) {
boolean handled = false;
if (!mLocked) {
if (!isLocked) {
handled = super.onStartNestedScroll(coordinatorLayout, child, directTargetChild, target, nestedScrollAxes);
}
@ -61,14 +60,14 @@ public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBeha
@Override
public void onNestedPreScroll(CoordinatorLayout coordinatorLayout, V child, View target,
int dx, int dy, int[] consumed) {
if (!mLocked) {
if (!isLocked) {
super.onNestedPreScroll(coordinatorLayout, child, target, dx, dy, consumed);
}
}
@Override
public void onStopNestedScroll(CoordinatorLayout coordinatorLayout, V child, View target) {
if (!mLocked) {
if (!isLocked) {
super.onStopNestedScroll(coordinatorLayout, child, target);
}
}
@ -78,11 +77,10 @@ public class LockableBottomSheetBehavior<V extends View> extends BottomSheetBeha
float velocityX, float velocityY) {
boolean handled = false;
if (!mLocked) {
if (!isLocked) {
handled = super.onNestedPreFling(coordinatorLayout, child, target, velocityX, velocityY);
}
return handled;
}
}

View File

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<androidx.core.widget.NestedScrollView
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:fillViewport="false">
<de.danoeh.antennapod.view.ShownotesWebView
android:id="@+id/webview"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</androidx.core.widget.NestedScrollView>