Yoshiyasu KO

【過去記事】 WebViewのheightがなかなか表示コンテンツのheightに合ってくれなくて困ったお話

2018-09-05

※本記事は、はてなブログに掲載していた記事を移行したものです

WebView周りで少し困ったことがあったので、備忘録で残しておきたいと思います。
重箱の隅をつつくようなTipsですが、温かい目で見ていただけると幸いです。

実現したいこと

AppBarLayoutとBehaviorを連動させたWebViewを表示したい!

困ったこと

AppBarLayoutとWebViewのBehaviorを連動させるには、WebViewをNestedScrollViewでネストさせ、android:isScrollContainer="false"を設定する必要があります↓

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="match_parent">

    <WebView
        android:id="@+id/webView"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:isScrollContainer="false"/>

</android.support.v4.widget.NestedScrollView>

これで、無事AppBarLayoutとBehaviorが連動するようになりましたが、今度はWebViewで表示している表示コンテンツのheightとNestedScrollViewのheightが合ってくれない・・・

じゃあNestedScrollViewのheightをwrap_contentにすればいいんじゃない?

と思い書いてみたら、なんかIDEから嫌な赤線が引かれた。

Placing a <WebView> in a parent element that uses a wrap_content size can lead to subtle bugs; use match_parent

・・・

WebViewをネストするViewはwrap_contentになってるとバグ起こすからmatch_parentを使え!! とのこと・・・

コンパイルエラーを起こすわけじゃなく、tools:ignore="WebViewLayout"をWebViewに追記すれば警告をsuppressすることはできます。
だけど「バグ起こすぞ」って言われたことを無視するまるで反抗期の子供みたいなことはしたくないので、なるべくバグがない安全な方法で実現したいわけです。

試してみたこと

その1: WebViewClient#onPageFinishedでWebView.contentHeightを取得してNestedScrollViewのHeightにセットする

ページのロードが終了したタイミングでコールバックされるonPageFinished()を使ってWebViewのcontentHeightを取得して、それをNestedScrollViewのheightにセットすればいいんじゃないか?

override fun onPageFinished(view: WebView?, url: String?) {
    super.onPageFinished(view, url)
    binding.scrollView.layoutParams = FrameLayout.LayoutParams(
            FrameLayout.LayoutParams.MATCH_PARENT,
            view?.contentHeight ?: 0
    )
}

結果: onPageFinished()で正しいcontentHeightは取得できず撃沈

その2: WebViewのレイアウトが再レンダリングされる時にcontentHeightを捕まえに行く

だったら、WebViewのcontentHeightが変更され、再度レンダリングされるタイミングでNestedScrollViewのHeightにセットすれば・・・!!

結果: そんなコールバックメソッドなんてなかった

こうやってできた

方法: WebViewをScrollViewでネストして、それを丸ごとNestedScrollViewでネストする

<android.support.v4.widget.NestedScrollView
    android:layout_width="match_parent"
    android:layout_height="wrap_content">
    <!-- NestedScrollViewのlayout_heightをwrap_contentにすることで、子のコンテンツに応じてheightを変えるようにする -->

    <ScrollView
        android:id="@+id/scrollView"
        android:layout_width="match_parent"
        android:layout_height="match_parent"> 
       <!-- WebViewの直接ネストしているScrollViewのlayout_heightはmatch_parentにする-->

        <WebView
            android:id="@+id/webView"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:isScrollContainer="false"/>

    </ScrollView>

</android.support.v4.widget.NestedScrollView>

単純だったよ・・・パトラッシュ・・・

おわりに

レイアウト上で簡単に対応できて良かったです。(傷だらけ)

コード上でダイナミックに変更すると、ある条件では動作しなかったり、ヒューマンエラーを起こす可能性も高くなるので。

同じことでお困りの方がいらっしゃれば、手助けになると幸いです。

じゃ、そゆことで〜〜