【问题标题】:NestedScrolling inside a Viewpager inside a BottomSheetDialog在 BottomSheetDialog 内的 Viewpager 内的 NestedScrolling
【发布时间】:2017-01-02 09:34:06
【问题描述】:

短版:

如何设置NestedScrollingParentNestedScrollingChild 与多个这样的孩子。

加长版

我实现了一个BottomSheetDialogFragment,它的布局由一个ViewPager组成,这个viewpager的适配器包含一个RecyclerView

现在的问题是,由于NestedScrollingParent,此时底部表的协调器布局仅支持一个直接 NestedScrollingChild,因此只能嵌套适配器的第一个片段-滚动。

我的意思是,每当在 viewpager 上调用 setAdapter 时,第一项支持嵌套滚动。但是在我更改页面后,新页面现在不会滚动。然后当我回到上一页时,它仍然支持滚动。

另外,我注意到如果片段或可以滚动的页面被破坏,后续页面现在可以滚动,这意味着后面的页面成为底部工作表的滚动子。问题是现在获得滚动能力的页面不是当前项目而是前一个项目(我的适配器必须维护3个片段)。

总结:

setAdapter之后

  • 片段 0 可以滚动
  • 然后将页面更改为片段 1 后,片段 1 无法滚动
  • 但切换到片段 2,然后返回片段 1 允许片段 1 滚动(因为我猜片段 0 已被破坏)

【问题讨论】:

    标签: android android-fragments scroll android-viewpager android-nestedscrollview


    【解决方案1】:

    在深入研究源代码后,我发现问题在于用于查找底部表的NestedScrollingChild 的错误算法(谷歌的人们没有考虑底部表内ViewPager 的可能性) .

    方法见这里:findScrollingChild()

    此方法的作用是返回它在给定视图(在本例中为底页)遇到的第一个NestedScrollingChild,对于具有 3 页的 viewpager 来说,它是当前页面之前的那个。此外,此方法在底部表的CoordinatorLayout 包装器的子级的布局阶段触发。

    考虑到这一点,人们可以设计许多解决方案,包括对行为本身进行子类化。

    此外,可以通过添加和删除此类子项的一个实例(从旧页面中删除,然后在当前页面中添加)来限制 viewpager 内的 NestedScrollingChild,这就是我所做的。您可以在适配器的setPrimaryItemOnPageChangeListener 上执行此操作。请务必在底页的协调器布局上致电requestLayout。 (此解决方案取决于寻呼机适配器的布局/结构类型,因此我不会发布确切的解决方案)。

    【讨论】:

      【解决方案2】:

      我对这些之前的回复有些不满意。 实际上,在我的情况下,setPrimaryItem 方法中的 @NonNull Object object 返回一个片段,并且不能转换为 NestedScrollView

      这是我的 XML 中的内容:

      • 一个BottomSheet 包含一个ViewPager
      • ViewPager 有两个页面,每个页面包含一个 Fragment
      • 每个Fragment 在根视图中包含一个NestedScrollView

      这是我的ViewPagerAdapter (Kotlin)

      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()
              }
          }
      }
      

      【讨论】:

        【解决方案3】:

        我遇到了完全相同的问题,并找到了非常相似的解决方案。
        提供我的解决方案供参考:

        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();
        }
        ...
        

        另外,我写了一篇关于这个主题的博文:Cannot scroll scrollable content inside ViewPager as BottomSheet of CoordinatorLayout

        【讨论】:

          【解决方案4】:

          我稍微简化了saiday's 解决方案。重要的是要知道我返回的是 ViewBindings 而不是来自 instantiateItem 的 Views。

          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();
          }
          

          【讨论】:

            【解决方案5】:

            我也遇到了这个问题,尝试在 BottomSheetDialog 内的几乎每个页面中使用带有滚动视图的 ViewPager。 我找到了由 laenger (https://github.com/laenger/ViewPagerBottomSheet) 提出的解决方案,并采用了它,因此它适合于 BottomSheetDialog。 希望它可以帮助一些遇到同样问题的人:)

            【讨论】:

              【解决方案6】:

              使用 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()
                      }
                  }
              

              【讨论】:

                【解决方案7】:

                除了@saiday 的回答之外,这些代码对我来说非常有效(API 21 及更高版本);

                这是我的 XML 中的内容:

                一个包含 ViewPager 的 BottomSheet。

                ViewPager 有两个页面,每个页面包含一个 Fragment。

                每个 Fragment 在根视图中包含一个 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();
                    }
                }
                

                我的第一个和第二个布局(只是 ID 不同):

                <?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>
                

                【讨论】:

                  猜你喜欢
                  • 2021-12-14
                  • 1970-01-01
                  • 2011-10-29
                  • 2015-12-03
                  • 2016-08-17
                  • 1970-01-01
                  • 2015-08-05
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多