【问题标题】:Seamless nested scrolling (Android)无缝嵌套滚动 (Android)
【发布时间】:2020-06-08 20:41:22
【问题描述】:

我们都被告知不要嵌套包含滚动机制的视图。然而,在最新的 Android 版本 (5.0) 中,Phone 应用程序引起了我的注意,ListView 内部似乎是 ScrollView

真正让我感兴趣的是滚动机制从ScrollView 无缝切换到ListView

请注意,在实际的 ListView 开始滚动之前,选项卡上方的内容会被推到视野之外。

我试过自己复制这个,但最终没有成功。这是我采用的基本方法...

使用单个连续触摸事件(不抬起手指)...

随着用户滚动,ListView 会慢慢覆盖ImageView。一旦ImageView 100% 被覆盖并且ListView 占据整个屏幕,ListView 开始滚动。

我目前正在ListView 上收听触摸事件,如果已到达顶部,请在ListView 上致电requestDisallowInterceptTouchEvent,即

@Override
public boolean onTouch(View v, MotionEvent event) {
  if (listViewAtTop) {
    v.requestDisallowInterceptTouchEvent(true);
  } else {
    v.requestDisallowInterceptTouchEvent(false);
  }
  return false;
}

只有当您抬起手指并继续滚动时,切换滚动上下文才有效。

是否有不同的方法可以达到预期的效果?

【问题讨论】:

    标签: android listview


    【解决方案1】:

    Android 5.0 Lollipop (API 21) 添加了嵌套滚动支持。

    据我所知,ListView (AbsListView) 和 ScrollView 现在都支持此功能(如果在 API 21 上运行),但必须在滚动视图上启用它。

    有两种方法,通过调用 setNestedScrollingEnabled(true) 或布局属性 android:nestedScrollingEnabled="true" (未记录)

    要了解它的工作原理,或为自定义小部件提供支持,关键方法如下:

    不幸的是,除了 JavaDoc 本身相当简单并且除了 ScrollView 之外没有其他示例之外,没有任何指南或培训可以解释其工作原理。

    【讨论】:

      【解决方案2】:

      将最新的支持包“com.android.support:support-v4:22.1.1”添加到您的项目中。试试这个:

      <android.support.v4.widget.NestedScrollView
              android:id="@+id/nScrollView"
              android:layout_width="match_parent"
              android:layout_height="match_parent"
              android:fillViewport="true">
      
              <FrameLayout ...>
                 <ListView ... />
              </FrameLayout >
          </android.support.v4.widget.NestedScrollView>
      

      默认启用嵌套滚动。

      【讨论】:

      • listview这样填不满高度的问题是什么?
      • @whizzzkey.. 尝试将 android:fillViewport="true" 添加到您的 ScrollView。
      【解决方案3】:

      在自己想办法解决这个问题时,我首先发现了这个问题;但是,答案并没有真正深入。我确实找到了很多好的资源,所以如果其他人发现自己在寻找这个,我会在下面链接它们。这种效果的一个术语是“粘性滚动”。


      一篇关于“同步滚动”的文章。

      http://www.pushing-pixels.org/2011/07/18/android-tips-and-tricks-synchronized-scrolling.html


      一个很好的视频,展示了一些 Android 滚动技巧,“快速返回”和“粘滞滚动”。

      https://www.youtube.com/watch?v=PL9s0IJ9oiI

      代码: https://code.google.com/p/romannurik-code/source/browse/misc/scrolltricks


      最后,这是另一个使用 listView 而不是 ScrollView 展示相同效果的示例。

      https://www.youtube.com/watch?v=rk-tLisxSgM

      代码: https://github.com/jatago/list_sticky_scroll_trick

      【讨论】:

        【解决方案4】:

        我找到了一个非常简单的替代“技巧”...仅使用带有透明标题的ListView

        【讨论】:

          【解决方案5】:

          我也一直想达到同样的效果。我在 GitHub 中找到了一个名为 ObservableScrollView 的相关库,它需要通过 TouchInterceptFramework 在后端进行更多工作,但至少它即使对于棒棒糖之前的设备也能完成这项工作。它不仅支持子滚动视图和列表视图,还支持回收视图。这是链接:

          https://github.com/ksoichiro/Android-ObservableScrollView

          我希望他们尽快考虑将棒棒糖和棒棒糖前设备的嵌套滚动作为其设计标准的一部分。这是一个好兆头。

          【讨论】:

            【解决方案6】:

            这是虚拟布局的经典示例。乍一看并不完全明显。基本上场景是这样的。

            灰色区域->FrameLayout 随后是一个填充整个框架布局的列表视图,然后是一个与列表视图的上半部分重叠的图像视图。列表视图的第一个项目是一个虚拟项目,其高度与图像视图的高度相同。 (注:实际数据从第二个元素开始)

            下一步很简单 根据列表视图的滚动翻译 Imageview。

            我认为这是避免嵌套滚动的最佳方法

            【讨论】:

              【解决方案7】:

              您可以在ListView 上使用以下属性组合来实现此目的:

              <ImageView ... /> <!-- must be before ListView -->
              
              <ListView
                  android:layout_width="match_parent"
                  android:layout_height="match_parent"
                  android:paddingTop="..." <!-- height of imageView -->
                  android:clipToPadding="false"
                  ...
              />
              

              您根本不需要管理代码中的任何滚动,并且它不需要列表适配器中的标题/虚拟视图。

              【讨论】:

                【解决方案8】:

                我正在使用类似的东西,我认为它可以正常工作

                scrollView.onScroll { x, y ->
                            Timber.d("ScrollView offset: ($x, $y)")
                
                            val height = dashboardChart.measuredHeight
                            val recyclerView =  viewPager.findViewById<RecyclerView>(R.id.recyclerView)
                            if(y >= height) {
                                Timber.d("ScrollView enable nested scrolling!")
                                recyclerView.isNestedScrollingEnabled = true
                            } else {
                                Timber.d("ScrollView disable nested scrolling!")
                                recyclerView.isNestedScrollingEnabled = false
                            }
                        }
                

                scrollView 是父级我正在监听 onScroll 事件(它下面的扩展是 viewTreeObserver.addOnScrollListener)。然后取决于我是否滚动了初始偏移量,我正在启用/禁用子 recyclerView(类似于 ListView 或其他 scrollView)滚动。

                【讨论】:

                  猜你喜欢
                  • 2015-08-09
                  • 2015-06-04
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  相关资源
                  最近更新 更多