30
21

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.

【Unity】これ以上iOSのSafeAreaで消耗したくない人のため『Unity-SafeAreaCanvas』

Last updated at Posted at 2018-12-23

はじめに

この記事はUnity Advent Calendar 201817日目の記事の代理投稿です!16日目は@namazuchinさんのUnityでTwilioを利用して固定電話に架電するでした。

先日、iPhone X/XSのSafeAreaに対応したOSSをリリースしました。
今回は、使い方の紹介と、実装の解説をしていこうと思います。

リポジトリ: https://github.com/nkjzm/Unity-SafeAreaCanvas

使い方

UnityのSafeArea対応に関する記事は、実機での反映のみに言及したものが多いですが、実際に開発する際には、SafeAreaが適用された場合の見え方をプレビューしながら進めたいと感じました。そのため、プレビューと実機対応の両方に対応したのが今回のアセットになります。

sample (1) (1).gif

  1. ReleasesからSafeAreaCanvas.unitypackageをダウンロードしてください。
  2. プロジェクトにSafeAreaCanvas.unitypackageをインポートしてください。
  3. シーンにSafeAreaCanvas/Prefabs/SafeAreaCanvas.prefabをドラッグしてください。

あとはSafeAreaCanvas.prefabの子のSafeArea以下にUIなどを作成・配置していけば良いです。
その状態でGameビューのサイズを変更すると、自動的にSafeAreaの余白が更新されます。
また、実機でも同じように動作するはずです。

実装

シンプルな実装なのですが、簡単に紹介していきます。

iOS実機実行時のCanvasサイズ調整機能

SetCanvasBounds.cs
using UnityEngine;

namespace nkjzm.SafeAreaCanvas
{
    [ExecuteInEditMode()]
    public class SetCanvasBounds : MonoBehaviour
    {
        public RectTransform panel;
        Rect lastSafeArea = new Rect(0, 0, 0, 0);

        void ApplySafeArea(Rect area)
        {
            panel.anchoredPosition = Vector2.zero;
            panel.sizeDelta = Vector2.zero;

            var anchorMin = area.position;
            var anchorMax = area.position + area.size;
            anchorMin.x /= Screen.width;
            anchorMin.y /= Screen.height;
            anchorMax.x /= Screen.width;
            anchorMax.y /= Screen.height;
            panel.anchorMin = anchorMin;
            panel.anchorMax = anchorMax;

            lastSafeArea = area;
        }

        void Update()
        {
            if (panel == null) { return; }

            Rect safeArea = Screen.safeArea;
#if UNITY_EDITOR
            if (Screen.width == 1125 && Screen.height == 2436)
            {
                safeArea.y = 102;
                safeArea.height = 2202;
            }
            if (Screen.width == 2436 && Screen.height == 1125)
            {
                safeArea.x = 132;
                safeArea.y = 63;
                safeArea.height = 1062;
                safeArea.width = 2172;
            }
#endif
            if (safeArea != lastSafeArea)
            {
                ApplySafeArea(safeArea);
            }
        }
    }
}

panelのサイズがSafeAreaのサイズと一致するようになっています。
Unity2017.3くらいから、Rect safeArea = Screen.safeAreaでsafeAreaのサイズが取得できるようになりました。その値をApplySafeArea関数でpanelに反映させています。

void ApplySafeArea(Rect area)
{
    panel.anchoredPosition = Vector2.zero;
    panel.sizeDelta = Vector2.zero;
    var anchorMin = area.position;
    var anchorMax = area.position + area.size;
    anchorMin.x /= Screen.width;
    anchorMin.y /= Screen.height;
    anchorMax.x /= Screen.width;
    anchorMax.y /= Screen.height;
    panel.anchorMin = anchorMin;
    panel.anchorMax = anchorMax;
    lastSafeArea = area;
}

UIのAnchorサイズをSafeAreaに合わせて更新しています。AnchorはVector2型で各値が0-1の範囲で表現されています。RectTransformの左下が(0,0)で右上が(1,1)です(下記画像参照)。Areaの座標を代入した後にScreen.widthScreen.heightで割ることで、0-1に正規化しているイメージです。

スクリーンショット 2018-12-24 4.39.38.png

ちなみにScreen.safeAreaRect型として返ってきます。矩形を表現するクラスで、Vector2型のPositionxyなどで直接アクセス出来たりする便利なクラスなのですが、Rect本来の座標系は左上が原点である点に注意してください。

Unityエディタ上でのプレビュー機能

上記コードでiPhone X/XSを判定する部分がこちらです(めちゃめちゃハードコーディングですみません)。

#if UNITY_EDITOR
if (Screen.width == 1125 && Screen.height == 2436)
{
    safeArea.y = 102;
    safeArea.height = 2202;
}
if (Screen.width == 2436 && Screen.height == 1125)
{
    safeArea.x = 132;
    safeArea.y = 63;
    safeArea.height = 1062;
    safeArea.width = 2172;
}
#endif

エディタ上ではScreen.safeAreaが値を返してくれないため、自前で値を入れています。大した処理じゃないのでUpdate()でやっています(ApplySafeArea()は繰り返し呼ばれません)

逆に言うと、エディタプレビュー機能はこんなに短いコードのみで対応しています。簡単ですね。

GameビューにiPhone X/XS用サイズの追加機能

インポート時、GameビューのサイズにiPhone X/XSの設定を追加する機能を入れています。Build TagetをiOSにしている場合はすでに含まれているので不要なのですが、別プラットフォームの設定で作業をする場合などに便利です。

スクリーンショット 2018-12-24 4.49.55.png

実装にはunity-GameViewSizeHelperというアセットを利用させていただいています。「ScriptからGameViewSizeを作成、また設定するヘルパークラス」とあり、まさにやりたいことでした。

GameViewSizeAdder.cs
using UnityEditor;
using UnityEngine;

namespace nkjzm.SafeAreaCanvas
{
    public class GameViewSizeAdder
    {
        [InitializeOnLoadMethod]
        static void Init()
        {
            var wide = new GameViewSizeHelper.GameViewSize
            {
                type = GameViewSizeHelper.GameViewSizeType.FixedResolution,
                width = 2436,
                height = 1125,
                baseText = "iPhone X/XS Landscape"
            };
            var tall = new GameViewSizeHelper.GameViewSize
            {
                type = GameViewSizeHelper.GameViewSizeType.FixedResolution,
                width = 1125,
                height = 2436,
                baseText = "iPhone X/XS Portrait"
            };
            GameViewSizeHelper.AddCustomSize(GameViewSizeGroupType.Standalone, wide);
            GameViewSizeHelper.AddCustomSize(GameViewSizeGroupType.Standalone, tall);
            GameViewSizeHelper.AddCustomSize(GameViewSizeGroupType.Android, wide);
            GameViewSizeHelper.AddCustomSize(GameViewSizeGroupType.Android, tall);
        }
    }
}

[InitializeOnLoadMethod]というアトリビュートを使って自動的にサイズ追加をしています。コンパイルが終わった後などにエディタ上で呼び出されるものです。複数回AddCustomSizeを呼び出していますが、GameViewSizeHelperでは同一の設定は追加されないようになっているみたいなので、大丈夫でした。ありがたいですね!

iOSと同じプロジェクトで使う可能性が高そうなStandAloneとAndroidの対応を入れています。

最後に

『Unity-SafeAreaCanvas』は、私がSafeArea対応で消耗した時に作成したアセットです。ぜひ多くの方に使っていただきたいですし、気になった点のIssueやPull Requestもお待ちしております!

Unity Advent Calendar 201818日目の記事は@kaiware007さんのThetaのストリーミング映像をリアルタイムにリフレクションさせてみたです。

30
21
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
30
21

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?