AppBarLayoutにViewPagerを入れてその中にNestedScrollViewやRecyclerViewで縦スクロールしたい場合、そのまま配置しただけではスクロールした際にAppBarLayoutの縦スクロールが優先されてしまい、内包するコンポーネントのスクロールが動作しませんでした。
やったこと
Viewが階層構造になってる際に子ViewにOnTouchListenerが設定されていないと親Viewにイベントが伝搬されるため、対象のViewにOnTouchListenerを設定し、requestDisallowInterceptTouchEventで親Viewへの伝搬を止めることで実現できました。
ただし、ViewPagerの中にある場合は横スクロールを止めるわけにはいかないので縦スクロールを判定できた場合のみ伝搬を止めています。
val minDistance = 100
var downY: Float = 0F
var upY: Float = 0F
nestedScrollView.setOnTouchListener(View.OnTouchListener { v, event ->
when (event.action) {
MotionEvent.ACTION_DOWN -> {
downY = event.y
return@OnTouchListener true
}
MotionEvent.ACTION_UP -> {
upY = event.y
return@OnTouchListener true
}
}
val deltaY = downY - upY
if (Math.abs(deltaY) > minDistance) {
// 一定以上縦方向にスワイプした場合は親に対してタッチイベントを伝搬しない
// これによりAppBarLayoutのスクロールと競合せずにスクロールできるようになる
v.parent.requestDisallowInterceptTouchEvent(true)
}
return@OnTouchListener false
}
サンプル
misoca12/VerticalScrollInAppBarLayout
参考
https://stackoverflow.com/questions/7449799/how-are-android-touch-events-delivered
https://qiita.com/takahirom/items/2978ede8e7d40b888832
http://blog.lciel.jp/blog/2013/12/03/android-touch-event