欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

UGUI自适应工具

程序员文章站 2022-05-30 17:32:34
...

游戏开发中UI自适应是个非常重要的环节,自适应方式不仅影响游戏的美观,也影响在不同机型上的交互。实际游戏开发中美观方面一般交给美术或策划调整,然闻道有先后,术业有专攻。需要一个简单易用的工具来辅助他们调整,通过代码修改  Scene 下的分辨率。下面是具体工具的代码实现,游戏中使用1334 * 750作为标准分辨率。

 
//*****************************************************************************
//  文件要述:  UI Resolution Tool
//  文件描述:  分辨率适应工具
//  参与编写人 :  Mars
//  参考链接 : https://answers.unity.com/questions/956123/add-and-select-game-view-resolution.html
//*****************************************************************************
using UnityEngine;
using UnityEditor;
using System;
using UnityEngine.UI;
using System.Collections.Generic;
using System.Reflection;

public class ResolutionConfig
{
    public int width = 0;    // 宽
    public int height = 0;   // 高

    public string desc = ""; // 描述

    public ResolutionConfig(int iWidth, int iHeight, string strDesc)
    {
        width = iWidth;
        height = iHeight;
        desc = strDesc;
    }
}
public enum GameViewSizeType
{
    AspectRatio, FixedResolution
}

public class UIResolutionTool : EditorWindow
{
    [MenuItem("工具/自适应工具")]
    private static void Open()
    {
        UIResolutionTool window = (UIResolutionTool)EditorWindow.GetWindow(typeof(UIResolutionTool));
        _Init();
        window.Show();
    }

    private List<ResolutionConfig> _listResolution = new List<ResolutionConfig>() 
    {
        new ResolutionConfig(750, 1334, "iphone6(标准)"),
        new ResolutionConfig(960, 1280, "3:4"),
        new ResolutionConfig(1080, 1920, "9:16"),
        new ResolutionConfig(1125, 2436, "iphoneX"),
    };

    private int _iWidth = 0;
    private int _iHeight = 0;
    private static MethodInfo _getGroup;
    private static object _gameViewSizesInstance;

    private static void _Init()
    {
        var sizesType = typeof(Editor).Assembly.GetType("UnityEditor.GameViewSizes");
        var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
        var instanceProp = singleType.GetProperty("instance");
        _getGroup = sizesType.GetMethod("GetGroup");
        _gameViewSizesInstance = instanceProp.GetValue(null, null);
    }

    void OnGUI()
    {
        int len = _listResolution.Count;
        for (int i = 0; i < len; i++)
        {
            ResolutionConfig item = _listResolution[i];
            EditorGUILayout.BeginHorizontal();
            if (GUILayout.Button("应用", GUILayout.Width(100), GUILayout.Height(20)))
            {
                _SetResolution(item);
            }

            GUILayout.Label(string.Format("{0}x{1}", item.width, item.height), GUILayout.MaxWidth(80));
            GUILayout.Label(item.desc, GUILayout.MaxWidth(200));

            EditorGUILayout.EndHorizontal();
        }



        EditorGUILayout.BeginHorizontal();
        if (GUILayout.Button("应用", GUILayout.Width(100), GUILayout.Height(20)))
        {
            _SetResolution(_iWidth, _iHeight);
        }

        string strWidth = GUILayout.TextField(_iWidth.ToString(), GUILayout.Width(50));
        GUILayout.Label("x", GUILayout.MaxWidth(20));
        string strHeight = GUILayout.TextField(_iHeight.ToString(), GUILayout.Width(50));

        int width = 0;
        if (int.TryParse(strWidth, out width))
        {
            _iWidth = width;
        }

        int height = 0;
        if (int.TryParse(strHeight, out height))
        {
            _iHeight = height;
        }

        GUILayout.Label("自定义分辨率", GUILayout.MaxWidth(80));

        EditorGUILayout.EndHorizontal();
    }


    private static void _SetResolution(ResolutionConfig conf)
    {
        _SetResolution(conf.width, conf.height);
    }

    private static void _SetResolution(int width, int height)
    {
        CanvasScaler canScaler = GameObject.FindObjectOfType<CanvasScaler>();

        //CanvasScaler canScaler = resMgr.UIParent.transform.parent.GetComponent<CanvasScaler>();
        // 适配方案 1334 * 750 iphone6 分辨率 1.7787  16:9 = 1.7778 4:3 = 1.3333  
        if (null != canScaler)
        {
            if (width > height)
            {
                // 高适配
                //canScaler.scaleFactor = ((float)Screen.width) / 1334.0f;
                // 宽适配
                //canScaler.scaleFactor = ((float)Screen.height) / 750.0f;
                float scaleWidth = ((float)height) / 750.0f;
                float scaleHeight = ((float)width) / 1334.0f;
                canScaler.scaleFactor = Mathf.Min(scaleWidth, scaleHeight);
            }
            else
            {
                // 高适配
                //canScaler.scaleFactor = ((float)Screen.height) / 1334.0f;
                // 宽适配
                //canScaler.scaleFactor = ((float)Screen.width) / 750.0f;
                float scaleWidth = ((float)width) / 750.0f;
                float scaleHeight = ((float)height) / 1334.0f;
                canScaler.scaleFactor = Mathf.Min(scaleWidth, scaleHeight);
            }
        }

        int index = FindSize(GameViewSizeGroupType.Standalone, string.Format("{0}x{1}", width, height));
        //Debug.LogError("----------------------------- index " + index);
        if (-1 != index)
        {
            SetSize(index);
        }
        else
        {
            AddCustomSize(GameViewSizeType.FixedResolution, GameViewSizeGroupType.Standalone, width, height, "");
            index = FindSize(GameViewSizeGroupType.Standalone, string.Format("{0}x{1}", width, height));
            if (-1 != index)
            {
                SetSize(index);
            }
        }

        Camera camera = GameObject.FindObjectOfType<Camera>();
        if (null != camera)
        {
            camera.enabled = false;
            camera.enabled = true;
        }
    }

    public static void AddCustomSize(GameViewSizeType viewSizeType, GameViewSizeGroupType sizeGroupType, int width, int height, string text)
    {
        // goal:
        // var group = ScriptableSingleton<GameViewSizes>.instance.GetGroup(sizeGroupType);
        // group.AddCustomSize(new GameViewSize(viewSizeType, width, height, text);

        var asm = typeof(Editor).Assembly;
        var sizesType = asm.GetType("UnityEditor.GameViewSizes");
        var singleType = typeof(ScriptableSingleton<>).MakeGenericType(sizesType);
        var instanceProp = singleType.GetProperty("instance");
        var getGroup = sizesType.GetMethod("GetGroup");
        var instance = instanceProp.GetValue(null, null);
        var group = getGroup.Invoke(instance, new object[] { (int)sizeGroupType });
        var addCustomSize = getGroup.ReturnType.GetMethod("AddCustomSize"); // or group.GetType().
        var gvsType = asm.GetType("UnityEditor.GameViewSize");
        var ctor = gvsType.GetConstructor(new Type[] { typeof(int), typeof(int), typeof(int), typeof(string) });
        var newSize = ctor.Invoke(new object[] { (int)viewSizeType, width, height, text });
        addCustomSize.Invoke(group, new object[] { newSize });
    }

    public static void SetSize(int index)
    {
        var gvWndType = typeof(Editor).Assembly.GetType("UnityEditor.GameView");
        var selectedSizeIndexProp = gvWndType.GetProperty("selectedSizeIndex",
                BindingFlags.Instance | BindingFlags.Public | BindingFlags.NonPublic);
        var gvWnd = EditorWindow.GetWindow(gvWndType);
        selectedSizeIndexProp.SetValue(gvWnd, index, null);
    }

    public static int FindSize(GameViewSizeGroupType sizeGroupType, string text)
    {
        // GameViewSizes group = gameViewSizesInstance.GetGroup(sizeGroupType);
        // string[] texts = group.GetDisplayTexts();
        // for loop...

        var group = GetGroup(sizeGroupType);
        var getDisplayTexts = group.GetType().GetMethod("GetDisplayTexts");
        var displayTexts = getDisplayTexts.Invoke(group, null) as string[];
        for (int i = 0; i < displayTexts.Length; i++)
        {
            string display = displayTexts[i];
            //Debug.LogError("---------------- display " + display);

            // the text we get is "Name (W:H)" if the size has a name, or just "W:H" e.g. 16:9
            // so if we're querying a custom size text we substring to only get the name
            // You could see the outputs by just logging
            // Debug.Log(display);
            int pren = display.IndexOf('(');
            if (pren != -1)
            {
                display = display.Substring(0, pren - 1); // -1 to remove the space that's before the prens. This is very implementation-depdenent
            }

            if (display == text)
            {
                return i;
            }
        }
        return -1;
    }

    static object GetGroup(GameViewSizeGroupType type)
    {
        return _getGroup.Invoke(_gameViewSizesInstance, new object[] { (int)type });
    }
}



 

编译完成后在菜单栏  “工具/自适应工具” 即可打开,效果图如下:

UGUI自适应工具