繁体   English   中英

仅当您无论如何都无法滚动时,如何在 RecyclerView 上禁用过度滚动效果?

[英]How to disable overscroll effect on RecyclerView ONLY when you can't scroll anyway ?

背景

有时,用户已经可以看到 recyclerView 的所有项目。

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

问题

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

recyclerView.setOverScrollMode(View.OVER_SCROLL_NEVER);

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

问题

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

如果它有助于假设任何事情,我总是将 LinearLayoutManager(垂直和水平)用于 RecyclerView。

<android.support.v7.widget.RecyclerView
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:overScrollMode="never"/>

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

你可以试试OVER_SCROLL_IF_CONTENT_SCROLLS 根据文档

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

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

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

由于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
    }
}

你可以尝试这样的事情:

totalItemCount = linearLayoutManager.getItemCount();
firstVisibleItem = linearLayoutManager.findFirstCompletelyVisibleItemPosition()
lastVisibleItem = linearLayoutManager.findLastCompletelyVisibleItemPosition();

if(firstVisibleItem == 0 && lastVisibleItem -1 == totalItemCount){
    // trigger the overscroll effect
}

您可以将其添加到您添加到RecyclerView上的OnScrollListeneronScrolled()中。

更长的解决方法,基于这里(解决这个问题),处理更多的情况,但仍然是一个解决方法:

/**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
        }
    }
}

编写自定义RecyclerView.OnScrollListener()以使用overScrollMode

/**
 * Workaround because [View.OVER_SCROLL_IF_CONTENT_SCROLLS] not working properly.
 *
 * [showHeader]/[showFooter] - for customization, if need show only specific scroll edge.
 */
class RecyclerOverScrollListener(
    private val showHeader: Boolean = true,
    private val showFooter: Boolean = true
) : RecyclerView.OnScrollListener() {

    override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) {
        super.onScrolled(recyclerView, dx, dy)

        val lm = recyclerView.layoutManager as? LinearLayoutManager ?: return

        val isFirstVisible = lm.findFirstCompletelyVisibleItemPosition() == 0
        val isLastVisible = lm.findLastCompletelyVisibleItemPosition() == lm.itemCount - 1
        val allVisible = isFirstVisible && isLastVisible

        recyclerView.overScrollMode = if (allVisible) {
            View.OVER_SCROLL_NEVER
        } else {
            val showHeaderEdge = showHeader && isFirstVisible && !isLastVisible
            val showFooterEdge = showFooter && !isFirstVisible && isLastVisible

            if (showHeader && showFooter || showHeaderEdge || showFooterEdge) {
                View.OVER_SCROLL_ALWAYS
            } else {
                View.OVER_SCROLL_NEVER
            }
        }
    }
}

如何实现RecyclerView

recyclerView.addOnScrollListener(RecyclerOverScrollListener(showFooter = false))

也不要忘记在 styles 中指定边缘颜色:

<item name="android:colorEdgeEffect">@color/yourRippleColor</item>

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM