Android の WebView にキーボードが被る問題

WebView で Webページを表示した時に、form をクリックすると、キーボードが表示されます。 その時に、入力したい部分が見えない問題が起こる時があります。

  • キーボードが出た時に、フォーム自体が隠れる。入力内容が見えない。
    キーボードが出た時に、下までスクロールできない

  • 想定していた動き

    1. "input 9" というラベルのテキストフィールドをクリックする
    2. キーボードが出る瞬間に、WebView が上に避けるように見える
      • ちなみにこの時は、キーボードだけなく予測変換も避けて、下までスクロールできる

f:id:sea_mountain:20130923224909p:plain f:id:sea_mountain:20130923224921p:plain

  • おかしい動き
    1. "input 9" というラベルのテキストフィールドをクリックする
    2. 入力したい "input 9" の上に被った状態でキーボードが表示される。下までスクロールもできないので見えない。

f:id:sea_mountain:20130923224909p:plain f:id:sea_mountain:20130923224945p:plain

この状態が起こるのは、Android OS バージョンにも関係あるようです。4.1 以上で起こっています。

解決法

条件

この問題を解決するためには条件があります。

  1. not fullscreen モード
    • つまり、ステータスバーが見える状態
  2. WebView が 以下の 2 つどちらかの状態になっている
    • WebView 自身とその下のレイアウトもすべて MATCH_PARENT
    • WebView の下に RelativeLayout(MATCH_PARENT状態の) がある
      • (MATCH_PARENT などの指定であり、数値で直接指定していない状態である)
  3. activity の windowSoftInputMode が adjustResize になっていること(adjustPan を設定していないこと)

1.の fullscreen モード "ではないとき" という条件は公式に書かれています。
http://developer.android.com/reference/android/view/WindowManager.LayoutParams.html#FLAG_FULLSCREEN

つまりは、"SOFT_INPUT_ADJUST_RESIZE" という状態が有効になっていないと、キーボードが WebView に被ってしまい、 SOFT_INPUT_ADJUST_RESIZE は FLAG_FULLSCREEN の状態では無視されます。

2.の View 構造ですが、一言で言うならば以下になります。

  • RelativeLayout(レイアウトはMATCH_PARENT)の上に、WebView を載せる。その状態なら WebView のレイアウトは MATCH_PARENT でなくて構わない

色々試しましたが、レイアウトの条件が複雑です。手元で幾つか試した結果を載せます。 上記で直らない場合は以下を参考に直してみてください。

実行結果

一番シンプルに動く形が以下です。 MATCH_PARENT のレイアウト状態の RelativeLayout の上に、サイズ指定有りの WebView が載っています。

 RelativeLayout MATCH_PAERNT x MATCH_PARENT
  |
  --WebView 300dp x 550dp

以下の結果は、Android プロジェクト作成時にデフォルトで作成されている LinearLayout の上に載せる View 構造です。
LinearLayout の上に載せている状態ですが、以下図では LinearLayout の記述を省略しています。

  • 成功例

    • すべて MATCH_PARENT

      FrameLayout(RelativeLayout) MATCH_PAERNT x MATCH_PARENT
        |
        -- WebView MATCH_PAERNT x MATCH_PARENT
      
    • RelativeLayout(MATCH_PARENT) の上にサイズ指定 WebView

      RelativeLayout MATCH_PAERNT x MATCH_PARENT
        |
        -- WebView 300 x 550
      
    • サイズ指定は真ん中の RelativeLayout で

      RelativeLayout MATCH_PAERNT x MATCH_PARENT
        |
        -- RelativeLayout 300dp x 550dp
          |
          -- WebView MATCH_PAERNT x MATCH_PARENT
      
  • 失敗例

    • FrameLayout(MATCH_PARENT) の上にサイズ指定 WebView

      FrameLayout  MATCH_PAERNT x MATCH_PARENT
        |
        --WebView 300dp x 550dp 
      
    • 一番親の LinearLayout の上に直接サイズ指定 WebView を置く

      WebView 300dp x 550dp
      

参考サイト

http://d.hatena.ne.jp/mihuyuchan/20130115/1358260567
http://blog.thevery.info/2010/11/showhide-status-bar-in-fullscreen.html
http://stackoverflow.com/questions/8398102/androidwindowsoftinputmode-adjustresize-doesnt-make-any-difference