【问题标题】:How to disable overscroll effect on RecyclerView ONLY when you can't scroll anyway ?仅当您无法滚动时,如何在 RecyclerView 上禁用过度滚动效果?
【发布时间】:2017-05-13 21:24:35
【问题描述】:

背景

有时,recyclerView 的所有项目都已经对用户可见。

在这种情况下,用户看到过度滚动效果并不重要,因为实际滚动并看到更多项目是不可能的。

问题

我知道为了禁用 RecyclerView 的过度滚动效果,我可以使用:

recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);

但我不知道什么时候触发这个,反正滚动是不可能的。

问题

如何确定所有项目都完全可见并且用户不能真正滚动?

如果假设有什么帮助,我总是将 LinearLayoutManager(垂直和水平)用于 RecyclerView。

【问题讨论】:

    标签: android android-recyclerview overscroll


    【解决方案1】:

    更长的解决方法,基于here(解决this issue),处理更多的情况,但仍然是一种解决方法:

    /**a temporary workaround to make RecyclerView handle android:overScrollMode="ifContentScrolls"  */
    class NoOverScrollWhenNotNeededRecyclerView : RecyclerView {
        private var enableOverflowModeOverriding: Boolean? = null
        private var isOverFlowModeChangingAccordingToSize = false
    
        constructor(context: Context) : super(context)
        constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)
        constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)
    
        override fun setOverScrollMode(overScrollMode: Int) {
            if (!isOverFlowModeChangingAccordingToSize)
                enableOverflowModeOverriding = overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS
            else isOverFlowModeChangingAccordingToSize = false
            super.setOverScrollMode(overScrollMode)
        }
    
        override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
            super.onLayout(changed, l, t, r, b)
            if (enableOverflowModeOverriding == null)
                enableOverflowModeOverriding = overScrollMode == View.OVER_SCROLL_IF_CONTENT_SCROLLS
            if (enableOverflowModeOverriding == true) {
                val canScrollVertical = computeVerticalScrollRange() > height
                val canScrollHorizontally = computeHorizontalScrollRange() > width
                isOverFlowModeChangingAccordingToSize = true
                overScrollMode = if (canScrollVertical || canScrollHorizontally) OVER_SCROLL_ALWAYS else OVER_SCROLL_NEVER
            }
        }
    }
    

    【讨论】:

      【解决方案2】:

      由于android:overScrollMode="ifContentScrolls" 不适用于RecyclerView(参见https://issuetracker.google.com/issues/37076456),我找到了某种解决方法,想与您分享:

      class MyRecyclerView @JvmOverloads constructor(
      context: Context, attrs: AttributeSet? = null, defStyleAttr: Int = 0
      ) : RecyclerView(context, attrs, defStyleAttr) {
      
          override fun onLayout(changed: Boolean, l: Int, t: Int, r: Int, b: Int) {
              super.onLayout(changed, l, t, r, b)
              val canScrollVertical = computeVerticalScrollRange() > height
              overScrollMode = if (canScrollVertical) OVER_SCROLL_ALWAYS else OVER_SCROLL_NEVER
          }
      }
      

      【讨论】:

      • 你能在 Github 上分享一个示例项目吗?也许您也可以在问题跟踪器上写下它
      • 另外,R.styleable.MyRecyclerView 呢?它的定义在哪里?
      • 似乎运作良好。但是是否有可能避免修改属性?似乎在这里你总是处理它,并且总是修改属性,所以原始文件丢失了。您还只垂直处理,但忘记了水平处理,忘记使用 R.attr.recyclerViewStyle 作为 defStyleAttr,或者只使用所有 CTOR(这是安全扩展的推荐方式,因为此资源被标记为私有)。
      • 如果您愿意,我在这里对这段代码进行了一些更改:stackoverflow.com/a/62621912/878126。不过,这仍然是一种解决方法。我已经为你的努力 +1 了。
      【解决方案3】:
      <android.support.v7.widget.RecyclerView
          android:layout_width="match_parent"
          android:layout_height="wrap_content"
          android:overScrollMode="never"/>
      

      只需在 XML 中添加 android:overScrollMode="never"

      【讨论】:

      • 这将使它永远不会出现。我要求避免仅在我无法滚动时才显示它。
      • 我猜“从不”也会禁用垂直滚动条。
      • 还有android:overScrollMode="ifContentScrolls"
      • @DariuszBacinski 它不起作用issuetracker.google.com/issues/37076456
      【解决方案4】:

      你可以试试这样的:

      totalItemCount = linearLayoutManager.getItemCount();
      firstVisibleItem = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
      lastVisibleItem = linearLayoutManager.findLastCompletelyVisibleItemPosition();
      
      if(firstVisibleItem == 0 && lastVisibleItem -1 == totalItemCount){
          // trigger the overscroll effect
      }
      

      您可以在OnScrollListeneronScrolled() 中添加您在RecyclerView 中添加的内容。

      【讨论】:

        【解决方案5】:

        你可以试试OVER_SCROLL_IF_CONTENT_SCROLLS。根据文档

        仅当内容很大时才允许用户过度滚动此视图 足以进行有意义的滚动,前提是它是一个可以滚动的视图。

        或者您可以检查是否有足够的项目来触发滚动并启用/禁用过度滚动模式,具体取决于它。例如

        boolean notAllVisible = layoutManager.findLastCompletelyVisibleItemPosition() < adapter.getItemCount() - 1;
        if (notAllVisible) {
           recyclerView.setOverScrollMode(allVisible ? View.OVER_SCROLL_NEVER);
        }
        

        【讨论】:

        • 旗帜完美!谢谢。但出于好奇,我应该在哪个阶段使用 findLastCompletelyVisibleItemPosition 的检查?毕竟,只要不显示任何内容,这不会返回一个好的结果......
        • 只有一次。我会在 RecyclerView 上发布一个 Runnable(在调用 setLayoutManager 和 setAdapter 之后),并在那里检查它。发布 runnable 应该让 RecyclerView 布置它的孩子
        • 对于那些想知道为什么 View.OVER_SCROLL_IF_CONTENT_SCROLLS 不起作用的人。 issuetracker.google.com/issues/37076456
        • 在将数据集设置为适配器后,对下一个布局进行检查非常重要,以确保呈现项目。在 Kotlin 中我会这样写 adapter.data = data recyclerView.doOnNextLayout { val areAllItemsVisible = viewManager.findLastCompletelyVisibleItemPosition() == viewAdapter.itemCount - 1 if (areAllItemsVisible) { recyclerView.overScrollMode = View.OVER_SCROLL_NEVER } }
        猜你喜欢
        • 1970-01-01
        • 2015-08-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2020-12-05
        • 2015-02-27
        相关资源
        最近更新 更多