NestedScrolling внутри Viewpager внутри BottomSheetDialog
Укороченная версия:
Как мне установить NestedScrollingChild
из NestedScrollingParent
с множественным номером такого ребенка.
Длинная версия
Я реализовал BottomSheetDialogFragment
чей макет состоит из ViewPager
Адаптер этого видового пейджера содержит RecyclerView
,
Теперь проблема в том, что с NestedScrollingParent
который в это время расположение координат нижней таблицы поддерживает только один прямой NestedScrollingChild
только первый фрагмент адаптера может быть прокручен.
Что я имею в виду, когда бы setAdapter
вызывается в viewpager, первый элемент поддерживает вложенную прокрутку. Но после того, как я изменил страницу, новая страница теперь не прокручивается. Затем, когда я возвращаюсь на предыдущую страницу, он все еще поддерживает прокрутку.
Кроме того, я заметил, что если фрагмент или страница, которая может прокручиваться, уничтожается, следующая страница теперь может прокручиваться, что означает, что последняя страница становится дочерним элементом прокрутки нижнего листа. Проблема в том, что страница, которая теперь получила возможность прокрутки, является не текущим элементом, а предыдущим (мой адаптер должен поддерживать 3 фрагмента).
Резюме:
После setAdapter
- фрагмент 0 можно прокрутить
- затем после смены страницы на фрагмент 1 фрагмент 1 не может прокручиваться
- но переключение на фрагмент 2, а затем возврат к фрагменту 1 позволяет фрагменту 1 прокручиваться (так как фрагмент 0 уничтожен, я думаю)
4 ответа
Покопавшись в исходном коде, я обнаружил, что проблема заключается в неисправном алгоритме, используемом при поиске NestedScrollingChild
в нижней части листа (люди в Google не приняли во внимание возможность ViewPager
внутри нижнего листа).
Смотрите метод здесь: findScrollingChild ()
Что этот метод делает, он вернет первый NestedScrollingChild
он встречается в заданном представлении (в данном случае в нижней части таблицы), которое в случае просмотра с 3 страницами предшествует текущей странице. Кроме того, этот метод запускается на этапе макета дочерних элементов CoordinatorLayout
Обертка нижнего листа.
Имея это в виду, можно придумать много решений, включая создание подкласса самого поведения.
Кроме того, можно ограничить NestedScrollingChild
внутри viewpager путем добавления и удаления одного экземпляра такого потомка (удалить со старой страницы, затем добавить на текущей странице), что я и сделал. Вы можете сделать это внутри setPrimaryItem
адаптера или на OnPageChangeListener
, Просто обязательно позвони requestLayout
на координатор макета нижнего листа. (Это решение зависит от типа компоновки / структуры адаптера пейджера, поэтому я не буду публиковать свое точное решение).
У меня были некоторые проблемы с этими предыдущими ответами. На самом деле, в моем случае @NonNull Object object
в setPrimaryItem
метод возвращает фрагмент и не может быть приведен к NestedScrollView
,
Вот что у меня есть в моем XML:
- Один
BottomSheet
содержащийViewPager
, ViewPager
с двумя страницами, содержащими однуFragment
каждый.- каждый
Fragment
Содержит одинNestedScrollView
в корне зрения.
Вот мой ViewPagerAdapter
(Котлин)
class MyViewPagerAdapter(val id: String) :
FragmentStatePagerAdapter(supportFragmentManager) {
val titles = arrayOf(getString(R.string.title1),
getString(R.string.title2))
override fun getItem(position: Int) = when (position) {
0 -> MyFragment1.newInstance(id)
1 -> MyFragment2.newInstance(id)
else -> Fragment()
}
override fun getCount() = 2
override fun getPageTitle(position: Int): CharSequence? {
return titles[position]
}
override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) {
super.setPrimaryItem(container, position, `object`)
val currentFragment = `object` as Fragment
if (currentFragment.view != null) { //The first time the view isn't created yet
for (i in 0 until count) {
(container.getChildAt(i) as NestedScrollView).isNestedScrollingEnabled = false
}
val currentNestedScrollView: NestedScrollView = currentFragment.view as NestedScrollView
currentNestedScrollView.isNestedScrollingEnabled = true
container.requestLayout()
}
}
}
У меня была точно такая же проблема, и я нашел очень похожее решение.
Предоставление моего решения для справки:
ViewPagerAdapter.java
....
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
NestedScrollView current = ((NestedScrollView)object);
current.setNestedScrollingEnabled(true);
for (int i = 0; i < getCount(); i++) {
if (i != position) {
NestedScrollView otherScrollView = container.findViewWithTag(i);
otherScrollView.setNestedScrollingEnabled(false);
}
}
container.requestLayout();
}
...
Кроме того, я пишу сообщение в блоге на эту тему: Невозможно прокрутить прокручиваемый контент внутри ViewPager как BottomSheet из CoordinatorLayout
В дополнение к ответу @saiday эти коды отлично работают у меня (API 21 и выше);
Вот что у меня есть в моем XML:
Один BottomSheet, содержащий ViewPager.
ViewPager с двумя страницами, каждая из которых содержит по одному фрагменту.
Каждый фрагмент содержит один NestedScrollView в корневом представлении.
и мой код ViewPagerAdapter (java):
@Override
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
Fragment currentFragment = (Fragment) object;
if (currentFragment.getView() != null) {
for (int i = 0; i < getCount(); i++) {
((NestedScrollView) container.getChildAt(i)).setNestedScrollingEnabled(false);
((NestedScrollView) container.getChildAt(i)).getChildAt(0).setNestedScrollingEnabled(false); //this is recyclerview's nestedscroll
}
NestedScrollView currentNestedScrollView = ((NestedScrollView) currentFragment.getView());
currentNestedScrollView.setNestedScrollingEnabled(true);
currentNestedScrollView.getChildAt(0).setNestedScrollingEnabled(true); //this is recyclerview's nestedscroll, I used getChildAt(0) because I have one element in NestedScrollView.
container.requestLayout();
}
}
Мой первый и второй макеты (только идентификаторы разные):
<?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:orientation="vertical"
android:id="@+id/marketMembersFragmentScrollView"
android:fillViewport="true">
<androidx.recyclerview.widget.RecyclerView
android:layout_width="match_parent"
android:layout_height="match_parent"
android:id="@+id/marketMembersFragmentRecyclerView"/>
</androidx.core.widget.NestedScrollView>
Я упростила saiday's
Решение немного. Важно знать, что я возвращаю ViewBindings вместо Views из instantiateItem
,
public void setPrimaryItem(@NonNull ViewGroup container, int position, @NonNull Object object) {
super.setPrimaryItem(container, position, object);
for (int i = 0; i < container.getChildCount(); i++) {
//First disable nested scrolling for all instantiated child views
((NestedScrollView)container.getChildAt(i)).setNestedScrollingEnabled(false);
}
//Enable nested scrolling for the primary item
ViewDataBinding binding = (ViewDataBinding) object;
NestedScrollView current = ((NestedScrollView)binding.getRoot());
current.setNestedScrollingEnabled(true);
container.requestLayout();
}
При использовании библиотек Androidx RecyclerView реализует NestedScrollingChild
вместо того NestedScrollView
.
override fun setPrimaryItem(container: ViewGroup, position: Int, `object`: Any) {
super.setPrimaryItem(container, position, `object`)
val currentFragment = `object` as Fragment
if (currentFragment.view != null) {
for (i in 0 until count) {
(container.getChildAt(i) as? NestedScrollingChild)?.isNestedScrollingEnabled = false
}
val currentNestedScrollView: NestedScrollingChild = currentFragment.view as NestedScrollingChild
currentNestedScrollView.isNestedScrollingEnabled = true
container.requestLayout()
}
}
Я тоже столкнулся с этой проблемой, пытаясь использовать ViewPager с прокруткой просмотров почти на каждой странице, внутри BottomSheetDialog. Я нашел это решение, сделанное laenger ([ https://github.com/laenger/ViewPagerBottomSheet][1]), и приняло его, чтобы оно соответствовало BottomSheetDialog. Надеюсь, что это может помочь тем, кто сталкивается с той же проблемой:)