如何在Activity中监听ViewPager2子Fragment滚动并控制按钮显示?
实现子Fragment滚动控制主Activity控件可见性
核心思路
通过Activity级别的ViewModel实现跨组件通信,子Fragment监听滚动事件并将状态传递给ViewModel,主Activity监听ViewModel的状态变化来控制控件可见性,避免组件间强耦合。
步骤1:创建共享ViewModel
用于传递滚动方向事件:
import androidx.lifecycle.LiveData import androidx.lifecycle.MutableLiveData import androidx.lifecycle.ViewModel class ScrollEventViewModel : ViewModel() { private val _scrollUpEvent = MutableLiveData<Boolean>() val scrollUpEvent: LiveData<Boolean> = _scrollUpEvent // 发送滚动方向事件:true=向上滚动,false=向下滚动 fun sendScrollUpEvent(isScrollingUp: Boolean) { _scrollUpEvent.value = isScrollingUp } }
步骤2:子Fragment监听滚动事件
针对NestedScrollView的实现:
class PickupFragment : Fragment() { private lateinit var scrollEventViewModel: ScrollEventViewModel private var lastScrollY = 0 override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) // 获取Activity级别的ViewModel实例 scrollEventViewModel = ViewModelProvider(requireActivity())[ScrollEventViewModel::class.java] } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val scrollView = view.findViewById<NestedScrollView>(R.id.scrollView) scrollView.setOnScrollChangeListener { _, _, scrollY, _, _ -> val isScrollingUp = scrollY < lastScrollY // 仅当状态变化时发送事件,减少冗余更新 if (isScrollingUp != scrollEventViewModel.scrollUpEvent.value) { scrollEventViewModel.sendScrollUpEvent(isScrollingUp) } lastScrollY = scrollY } } }
针对RecyclerView的实现:
class ListFragment : Fragment() { private lateinit var scrollEventViewModel: ScrollEventViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) scrollEventViewModel = ViewModelProvider(requireActivity())[ScrollEventViewModel::class.java] } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val recyclerView = view.findViewById<RecyclerView>(R.id.recyclerView) recyclerView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrolled(recyclerView: RecyclerView, dx: Int, dy: Int) { super.onScrolled(recyclerView, dx, dy) val isScrollingUp = dy < 0 if (isScrollingUp != scrollEventViewModel.scrollUpEvent.value) { scrollEventViewModel.sendScrollUpEvent(isScrollingUp) } } }) } }
步骤3:主Activity监听状态并控制控件
class MainActivity : AppCompatActivity() { private lateinit var scrollEventViewModel: ScrollEventViewModel private lateinit var bottomNav: BottomNavigationView private lateinit var fab: FloatingActionButton override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) bottomNav = findViewById(R.id.bottom_nav) fab = findViewById(R.id.fab) scrollEventViewModel = ViewModelProvider(this)[ScrollEventViewModel::class.java] // 监听滚动事件,更新控件可见性 scrollEventViewModel.scrollUpEvent.observe(this) { isScrollingUp -> if (isScrollingUp) { bottomNav.visibility = View.VISIBLE fab.show() } else { bottomNav.visibility = View.GONE fab.hide() } } } }
步骤4:处理ViewPager2页面切换(可选)
切换页面时恢复默认控件状态,避免残留之前的滚动状态:
class HomeFragment : Fragment() { private lateinit var scrollEventViewModel: ScrollEventViewModel override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) scrollEventViewModel = ViewModelProvider(requireActivity())[ScrollEventViewModel::class.java] } override fun onViewCreated(view: View, savedInstanceState: Bundle?) { super.onViewCreated(view, savedInstanceState) val viewPager = view.findViewById<ViewPager2>(R.id.viewpager) viewPager.registerOnPageChangeCallback(object : ViewPager2.OnPageChangeCallback() { override fun onPageSelected(position: Int) { super.onPageSelected(position) // 切换页面后默认显示控件 scrollEventViewModel.sendScrollUpEvent(true) } }) } }
内容的提问来源于stack exchange,提问作者mskim96
相关产品推荐
相关产品推荐

