6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

viewport-fit=cover を設定した時のソフトウェアキーボード対応について

Posted at

画面のフッター部分に入力エリアがある場合、ソフトウェアキーボードが表示されると入力エリアが隠れてしまい、入力することができなくなる場合があります。

そのような場合は、ソフトウェアキーボードが表示される際に、JavaScript からソフトウェアキーボード分、画面の高さを変更する処理を行う必要があります。

#viewport-fit=cover の影響

iPhone X が登場し、iOS 11 からセーフエリアが導入されました。

Monaca で iPhone X の画面に対応する場合は、viewport 設定に viewport-fit=cover を追加する必要があります。(参考:iPhoneXのセーフ エリア対応について)

viewport 設定に viewport-fit=cover を追加した場合、コンテンツ内容を画面全体に表示するため、JavaScript から画面の高さ ( height ) を変更しても設定が反映されない場合があります。

viewport 設定に viewport-fit=cover を追加した場合は、画面の高さを変更するのではなく、フッター要素の margin-bottom にソフトウェアキーボード分の高さを設定することで対応することができます。

ソフトウェアキーボードの高さを取得する

フッター要素の margin-bottom にソフトウェアキーボードの高さを設定するためには、初めにソフトウェアキーボードの高さを取得する必要があります。

JavaScript からは、直接ソフトウェアキーボードの高さを取得することができないため、今回は、cordova-plugin-ionic-keyboard プラグイン ( v2.1.3 ) を利用します。

注意点として、サードパーティー製 Cordova プラグインを利用する場合は、Proプラン 以上が必要になります。また、cordova-plugin-ionic-keyboard プラグインは、カスタムビルドデバッガーでは正常に動作しないため、デバッグビルドをして実機で確認する必要があります。

cordova-plugin-ionic-keyboard プラグインのイベント

cordova-plugin-ionic-keyboard プラグインでは、下記のイベントが用意されています。

イベント名 説明
keyboardWillShow キーボードが表示される前に実行されます。
keyboardWillHide キーボードが閉じる前に実行されます。
keyboardDidShow キーボードが完全に表示された時に実行されます。
keyboardDidHide キーボードが完全に閉じた時に実行されます。

ソフトウェアキーボードの高さは、keyboardWillShowkeyboardDidShow イベントから event.keyboardHeight で取得することができます。

window.addEventListener('keyboardWillShow', (event) => {
  console.log(event.keyboardHeight);
});

keyboardWillShow でフッター要素の margin-bottom にソフトウェアキーボードの高さを設定し、keyboardWillHide でフッター要素の margin-bottom0px に戻すことで対応することができます。

サンプル

Monaca で提供している Onsen UI V2 JS Tabbar テンプレートをベースにサンプルを作成してみました。

サンプルでのフッター要素は、ons-tabbar になります。

ons-tabbarid として tabbar1 を設定し、JavaScript から tabbar1 に対し、マージン設定を行なっています。

<!DOCTYPE HTML>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="viewport-fit=cover, width=device-width, initial-scale=1, maximum-scale=1, user-scalable=no">
  <meta http-equiv="Content-Security-Policy" content="default-src * data: gap: https://ssl.gstatic.com; style-src * 'unsafe-inline'; script-src * 'unsafe-inline' 'unsafe-eval'">
  <script src="components/loader.js"></script>
  <script src="lib/onsenui/js/onsenui.min.js"></script>

  <link rel="stylesheet" href="components/loader.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsenui.css">
  <link rel="stylesheet" href="lib/onsenui/css/onsen-css-components.css">
  <link rel="stylesheet" href="css/style.css">

  <script>
    ons.ready(function() {
      console.log("Onsen UI is ready!");

      // iPhoneX対応
      if (ons.platform.isIPhoneX()) {
        document.documentElement.setAttribute('onsflag-iphonex-portrait', '');
        document.documentElement.setAttribute('onsflag-iphonex-landscape', '');
      }
    });

    document.addEventListener('show', function(event) {
      var page = event.target;
      var titleElement = document.querySelector('#toolbar-title');

      if (page.matches('#page1')) {
        titleElement.innerHTML = 'My app - Page 1';

        //ソフトウェアキーボード表示前イベント処理
        window.addEventListener('keyboardWillShow', (event) => {
          // マージンを追加。
          if (ons.platform.isIOS) {
            document.getElementById("tabbar1").style.marginBottom = event.keyboardHeight + "px";
          }
        });
    
        //ソフトウェアキーボード非表示前イベント処理
        window.addEventListener('keyboardWillHide', () => {
          // マージンを削除。
          if (ons.platform.isIOS) {
            document.getElementById("tabbar1").style.marginBottom = "0px";
          }
        });
      } else if (page.matches('#page2')) {
        titleElement.innerHTML = 'My app - Page 2';
      }
    });
  </script>

    <style>
      html {
        height: 100%;
      }

      #page1 {
        margin: 0;
        padding: 0;
        min-height: 100%;
        height: auto !important;
        height: 100%;
        position: relative;
      }

      .page_bottom {
        position: absolute;
        width: 100%;
        bottom: 0;
        text-align: center;
        overflow: hidden;
      }

      textarea {
        width: 80%;
        height: 8em;
      }
    </style>
</head>
<body>
  <ons-page>
    <ons-toolbar>
      <div class="center" id="toolbar-title"></div>
    </ons-toolbar>
    <ons-tabbar id="tabbar1" position="bottom">
      <ons-tab label="Tab 1" page="tab1.html" active>
      </ons-tab>
      <ons-tab label="Tab 2" page="tab2.html">
      </ons-tab>
    </ons-tabbar>
  </ons-page>

  <ons-template id="tab1.html">
    <ons-page id="page1">
      <div class="content">
        <p style="text-align: center;">
          This is the first page.

          <br /><br />
          <textarea  id="textarea1"></textarea>

          <br /><br />
          <textarea  id="textarea2"></textarea>

          <br /><br />
          <textarea  id="textarea3"></textarea>
        </p>

        <div class="page_bottom">
          <textarea  id="textarea4"></textarea>
        </div>
      </div>
    </ons-page>
  </ons-template>

  <ons-template id="tab2.html">
    <ons-page id="page2">
      <p style="text-align: center;">
        This is the second page.
      </p>
    </ons-page>
  </ons-template>
</body>
</html>

おわりに

viewport 設定に viewport-fit=cover を追加している場合に、画面の高さに対しソフトウェアキーボード分の高さの設定が反映されない場合は、フッター要素に対してマージン設定を試してみてください。

6
4
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
6
4

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?