FragmentStatePagerAdapterがdeprecatedになったのでViewPager2に移行作業中。
新しいFragmentStateAdapterからRecyclerView.Adapterを継承するようになったのだけど、 そのせいかPageコンテンツである子Fragmentの縦スクロール中に横スワイプが反応しやすくなっている。つまり操作性が悪くなっている。
フリックならいいんだけど、指を離さずに上下スクロールをしようとするとどうしてもX軸もずれてしまい、そうするとViewPager側が出しゃばってくるのだ。 こういう話題ってエラーとかと違って英語で検索しにくいから話題になってるかどうかも良く分からないのだけど(Sensitiveという指摘は散見)、Swipeをdisabledにする方法を質問している人がいたので多分縦スクロール発動中は disabledにするような対応がいいんだろうな...って結構面倒なんだけど!
対策
- ViewPager2を持つFragmentのViewModelにisChildScrolling的なLiveDataを用意
- 子Fragmentのスクロールが開始(newState == `SCROLL_STATE_DRAGGING )したらisChildScrollingをtrueにする
- isChildScrollingをobserveしてtrueになったらsetUserInputEnabledをfalseにする
- スクロールが止まったらtrueに戻す。
// ViewModel /** * 子Fragmentがスクロール中かどうか */ private val _isChildScrolling: MutableLiveData<Boolean> by lazy { MutableLiveData<Boolean>() } val isChildScrolling: LiveData<Boolean> get() = _isChildScrolling fun setIsChildScrolling(b: Boolean) { _isChildScrolling = b }
// addOnScrollListenerの一部 gridView.addOnScrollListener(object : RecyclerView.OnScrollListener() { override fun onScrollStateChanged(recyclerView: RecyclerView, newState: Int) { super.onScrollStateChanged(recyclerView, newState) viewModel.setIsChildScrolling( newState == RecyclerView.SCROLL_STATE_DRAGGING ) } }
// observer viewModel.isChildScrolling.observe(this) { pagerBinding.viewPager.isUserInputEnabled = !it }
雑感
この対策すると上下にスクロールさせながらスワイプさせてみたいなグリグリした操作感はなくなる。 ただ意図せず横スワイプに操作を持っていかれるくらいならこの方が良いだろう。
参考
敏感過ぎるよ!って投稿もあった。 stackoverflow.com