Unity | レスポンシブUIデザイン用サンプルスクリプト

Unityで複数解像度への対応(レスポンシブUIデザイン)をする場合、アンカー・ピボットの配置、Layoutによる配置が一般的ですが、最近のWebページのようにUIの配置・形を変更する場合はスクリーンのサイズを取得し、変化が有れば更新する形になります。

コンポーネントがそれぞれ一定時間毎に確認処理を行う事でも実装出来ますが、コールバックに登録するだけで使用できるようなサンプルを書いてみたので紹介します。

機能

  1. 何フレームごとに画面サイズ・UI更新の確認処理を行うか設定したマネージャーを配置します。
  2. デモスクリプトのような、描画の更新が必要な時に呼び出す必要がある関数をマネージャーに登録します。

デモスクリプト

アスペクト比が変わった時に呼び出す関数と、コールバック登録の定型文2行で実装出来ます。

using UnityEngine;
using SM = BlueBreath.Screen.ScreenManager;
/// <summary>
/// Unityレスポンシブデザイン用のDEMOスクリプト
/// アスペクト比が変化した時、コールバック関数を実行します。
/// </summary>
public class UnityResponsiveDemo : MonoBehaviour
{
    /// <summary>
    /// UIの位置・サイズなどの変更を行う処理を書きます。
    /// 引数にウインドウのアスペクト比(幅/高さ)が必要です。
    /// </summary>
    void ResponsiveMethod(float ratio){
        if(1 <= ratio){
            Debug.Log("横長デザインに更新 Aspect Ratio W/H : "+ratio);
        }else{
            Debug.Log("縦長デザインに更新 Aspect Ratio W/H : "+ratio);
        }
    }
    /// <summary>
    /// オブジェクトが有効になった時コールバック関数を登録します。
    /// </summary>
    private void OnEnable() => SM.RegisterAspectRatioCallback(ResponsiveMethod);
    /// <summary>
    /// オブジェクトが無効になった時コールバック関数を抹消します。
    /// </summary>
    private void OnDisable() => SM.UnRegisterAspectRatioCallback(ResponsiveMethod);
}

ScreenManagerスクリプト

ウインドウの縦横が変化した時にコールバック関数を呼び出すスクリプトです。

このコンポーネントはシーンに1つだけ配置します。

using System;
using UnityEngine;
namespace BlueBreath.Screen
{
    [DefaultExecutionOrder(-10)]
    public class ScreenManager : MonoBehaviour
    {
        private static int screenWidth;
        private static int screenHeight;
        private static float aspectRatio;
        [SerializeField][Range(1,60)]
        int upDatePerFrame = 30;
        int frameCount = 0;
        public int UpdatePerFrame
        {
            get => upDatePerFrame;
            set => upDatePerFrame = value <= 0 ? 1 : value;
        }
        //Singleton
        static BlueBreath.Screen.ScreenManager Instance;
        private void Awake(){
            Instance = this;
            CacheScreenData();
            /*
            Debug.Log("ScreenWidth:"+screenWidth);
            Debug.Log("ScreenHeight:"+screenHeight);
            Debug.Log("AspectRatio:"+aspectRatio);
            */
        }
        private static Action<float> aspectRatioCallback;
        /// <summary>
        /// ウインドウアスペクト比が変化した時に呼び出すコールバックを登録します。
        /// </summary>
        /// <param name="callback">引数にfloat:[アスペクト比(幅/高さ)]を持ったコールバック関数</param>
        /// <param name="repaint">初回更新</param>
        public static void RegisterAspectRatioCallback(Action<float> callback, bool repaint = true){
            if(repaint)callback(aspectRatio);
            aspectRatioCallback += callback;
        } 
        public static void UnRegisterAspectRatioCallback(Action<float> callback) => aspectRatioCallback -= callback;
        private static Action<int,int> whCallback;
        /// <summary>
        /// ウインドウ幅もしくは高さが更新された時に呼び出すコールバックを登録します。
        /// </summary>
        /// <param name="callback">引数にint:[幅]とint[高さ]を持ったコールバック関数</param>
        /// <param name="repaint">初回更新</param>
        public static void RegisterWidthHeightCallback(Action<int,int> callback, bool repaint = true){
            if(repaint)callback(screenWidth,screenHeight);
            whCallback += callback;
        } 
        public static void UnRegisterWidthHeightCallback(Action<int,int> callback) => whCallback -= callback;
        private static Action<int> widthCallback;
        /// <summary>
        /// ウインドウ幅が更新された時に呼び出すコールバックを登録します。
        /// </summary>
        /// <param name="callback">引数にint:[幅]を持ったコールバック関数</param>
        /// <param name="repaint">初回更新</param>
        public static void RegisterWidthCallback(Action<int> callback, bool repaint = true){
            if(repaint)callback(screenWidth);
            widthCallback += callback;
        } 
        public static void UnRegisterWidthCallback(Action<int> callback) => widthCallback -= callback;
        private bool wChanged = false, hChanged = false;
        void Update()
        {
            frameCount ++;
            if(frameCount <= upDatePerFrame)return;
            frameCount = 0;
            RepaintScreen();
        }
        void RepaintScreen(){
            if(screenHeight != UnityEngine.Screen.height)hChanged = true;
            if(screenWidth != UnityEngine.Screen.width)wChanged = true;
            if(!wChanged && !hChanged)return;
            CacheScreenData();
            if(widthCallback != null && wChanged )widthCallback(screenWidth);
            if(whCallback != null && wChanged || hChanged)whCallback(screenWidth,screenHeight);
            if(aspectRatioCallback != null && wChanged || hChanged)aspectRatioCallback(aspectRatio);
            wChanged = false;
            hChanged = false;
            return;
        }
        void CacheScreenData(){
            screenHeight = UnityEngine.Screen.height;
            screenWidth = UnityEngine.Screen.width;
            aspectRatio = (float)screenWidth / (float)screenHeight;
        }
    }
}

コールバックに登録可能な関数

using SM = BlueBreath.Screen.ScreenManager//名前空間.クラス

アスペクト比の変化

void ResponsiveMethod(float ratio){/* 更新処理 */}
private void OnEnable() => SM.RegisterAspectRatioCallback(ResponsiveMethod);
private void OnDisable() => SM.UnRegisterAspectRatioCallback(ResponsiveMethod);

幅の変化

void ResponsiveMethod(int width){/* 更新処理 */}
private void OnEnable() => SM.RegisterWidthCallback(ResponsiveMethod);
private void OnDisable() => SM.UnRegisterWidthCallback(ResponsiveMethod);

幅と高さの変化

void ResponsiveMethod(int width, int height){/* 更新処理 */}
private void OnEnable() => SM.RegisterWidthHeightCallback(ResponsiveMethod);
private void OnDisable() => SM.UnRegisterWidthHeightCallback(ResponsiveMethod);

用途

アプリケーションのUI配置をアスペクト比によって動的に変更する場合に使用できます。

コメント

タイトルとURLをコピーしました