You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用MotionLayout仅在RecyclerView超屏滚动时隐藏/显示视图

解决方案

要实现仅在RecyclerView内容超出屏幕时才允许折叠搜索栏和TextView,核心是动态控制MotionLayout的滑动触发权限——只在RecyclerView可滚动时启用折叠交互,否则禁用。以下是具体实现步骤:

1. 编写判断RecyclerView是否可滚动的工具方法

在你的SearchFragment中添加方法,用来检测RecyclerView内容是否超出屏幕:

private fun isRecyclerViewScrollable(): Boolean {
    val recyclerView = binding.listaDeportistasRv
    // 先判断RecyclerView是否可见且有数据
    if (recyclerView.visibility != View.VISIBLE || recyclerView.adapter?.itemCount ?: 0 == 0) {
        return false
    }

    val layoutManager = recyclerView.layoutManager as LinearLayoutManager
    val firstVisibleItem = layoutManager.findFirstCompletelyVisibleItemPosition()
    val lastVisibleItem = layoutManager.findLastCompletelyVisibleItemPosition()
    
    // 检查是否所有item都能完全显示在屏幕内
    return !(firstVisibleItem == 0 && lastVisibleItem == recyclerView.adapter!!.itemCount - 1)
}

2. 动态控制MotionLayout的滑动交互

在Fragment的onViewCreated中,监听RecyclerView的内容和状态变化,实时更新MotionLayout的交互权限:

override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
    super.onViewCreated(view, savedInstanceState)
    val binding = SearchFragmentBinding.bind(view)
    val motionLayout = binding.root as MotionLayout
    val recyclerView = binding.listaDeportistasRv

    // 初始化时先判断一次状态
    updateMotionLayoutScrollEnabled(motionLayout)

    // 监听Adapter数据变化
    recyclerView.adapter?.registerAdapterDataObserver(object : RecyclerView.AdapterDataObserver() {
        override fun onChanged() = updateMotionLayoutScrollEnabled(motionLayout)
        override fun onItemRangeInserted(positionStart: Int, itemCount: Int) = updateMotionLayoutScrollEnabled(motionLayout)
        override fun onItemRangeRemoved(positionStart: Int, itemCount: Int) = updateMotionLayoutScrollEnabled(motionLayout)
    })

    // 监听RecyclerView布局完成事件
    recyclerView.viewTreeObserver.addOnGlobalLayoutListener(object : ViewTreeObserver.OnGlobalLayoutListener {
        override fun onGlobalLayout() {
            recyclerView.viewTreeObserver.removeOnGlobalLayoutListener(this)
            updateMotionLayoutScrollEnabled(motionLayout)
        }
    })
}

private fun updateMotionLayoutScrollEnabled(motionLayout: MotionLayout) {
    val isScrollable = isRecyclerViewScrollable()
    // 启用/禁用展开<->折叠的滑动Transition
    motionLayout.setTransitionEnabled(R.id.expandido, R.id.recogido, isScrollable)
    motionLayout.setTransitionEnabled(R.id.recogido, R.id.expandido, isScrollable)
    
    // 如果不可滚动,强制回到展开状态
    if (!isScrollable && motionLayout.currentState == R.id.recogido) {
        motionLayout.transitionToState(R.id.expandido)
    }
}

3. 优化MotionScene配置(可选)

给Transition添加进度阈值,避免轻微滑动就触发动画,提升交互体验:

<Transition
    motion:constraintSetEnd="@id/recogido"
    motion:constraintSetStart="@id/expandido"
    motion:progressThreshold="0.2">

    <OnSwipe
        motion:dragDirection="dragUp"
        motion:moveWhenScrollAtTop="false"
        motion:touchAnchorId="@id/lista_deportistas_Rv"
        motion:touchAnchorSide="top" />

</Transition>

关键说明

  • 当RecyclerView为空(itemCount=0)或所有内容完全显示在屏幕内时,会直接禁用折叠滑动,并强制回到展开状态
  • 针对Adapter数据变化、RecyclerView布局完成的监听,确保每次内容更新后都能正确判断交互权限
  • 若使用GridLayoutManager,需修改isRecyclerViewScrollable方法中的判断逻辑,通过计算总行数与可见行数的对比来判断是否可滚动

内容的提问来源于stack exchange,提问作者xerez

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.25 05:24:58