はじめに
ViewPager内で横スクロールするWebViewを表示すると、スクロールが全然効かなくなる。
これはWebViewの横スクロールが、ViewPagerの横スクロールに取られてしまうため。

ViewPagerのタブの切り替えをタブタップのみにすれば解決はするのだけど、横スワイプも諦めたくないので、WebViewをカスタマイズして対応した。
解決方法
1.WebViewをカスタマイズする。
WebViewを継承したクラスを作成して、onOverScrolled
とonTouchEvent
をオーバーライドする。
class MyWebView @JvmOverloads constructor(
context: Context,
attrs: AttributeSet? = null,
defStyleAttr: Int = 0,
) : WebView(context, attrs, defStyleAttr) {
var onPagingStateChanged: ((Boolean) -> Unit)? = null
override fun onOverScrolled(scrollX: Int, scrollY: Int, clampedX: Boolean, clampedY: Boolean) {
super.onOverScrolled(scrollX, scrollY, clampedX, clampedY)
onPagingStateChanged?.invoke(true)
}
override fun onTouchEvent(event: MotionEvent?): Boolean {
super.onTouchEvent(event)
if (event?.action == MotionEvent.ACTION_DOWN) {
onPagingStateChanged?.invoke(false)
}
return true
}
}
onOverScrolled
を修正して、オーバースクロール時にonPagingStateChanged
にtrueが流れるようにする。
onTouchEvent
を修正して、ACTION_DOWNが来たときはonPagingStateChanged
にfalseが流れるようにする。
この値を使ってViewPagerスワイプの許可・非許可を切り替えることで、いい感じにスクロールできるようになる。
2.ViewPagerのスワイプを制御する。
onPagingStateChanged
から来た真偽値をViewModelのFlowやコールバック経由でViewPager2.isUserInputEnabled
に流してあげることで、制御ができる。
class MyActivity : AppCompatActivity() {
private val viewModel: MyViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
viewModel.isPagingEnabled.collectWhenStarted(this) {
binding.viewPager.isUserInputEnabled = it
}
}
}
こんな感じで実装すれば、WebViewの横スクロールが限界までいって、オーバースクロールになった瞬間のみタブの切り替えが発生する。
やってしまえば簡単だけど、前例があんまりなくて困ってしまったね。
今回はViewPager2でやったけど、似たような感じでViewPagerにも応用できると思う。
まとめ
- ViewPager2内で横スクロールするWebViewを表示したい場合は、WebViewをカスタマイズする。
- オーバースクロールの時だけスワイプでタブ切り替えを許可してあげるとできる。
おわり。