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 });
}
}
编译完成后在菜单栏 “工具/自适应工具” 即可打开,效果图如下:
下一篇: Flutter-Text使用