| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237 |
- using System.Globalization;
- using UnityEditor;
- using UnityEngine;
- using UnityEngine.UI;
- namespace AppUI.Editor
- {
- /// <summary>
- /// 设计稿尺寸与 Canvas Reference Resolution 之间的换算工具窗口。
- /// </summary>
- public class DesignResolutionConverterWindow : EditorWindow
- {
- private const string PrefDesignW = "AppUI.DesignResolutionConverter.DesignW";
- private const string PrefDesignH = "AppUI.DesignResolutionConverter.DesignH";
- private const string PrefCanvasW = "AppUI.DesignResolutionConverter.CanvasW";
- private const string PrefCanvasH = "AppUI.DesignResolutionConverter.CanvasH";
- private Vector2 _designArtboard = new Vector2(DesignResolutionConverter.DefaultDesignWidth, DesignResolutionConverter.DefaultDesignHeight);
- private Vector2 _canvasReference = new Vector2(DesignResolutionConverter.DefaultDesignWidth, DesignResolutionConverter.DefaultDesignHeight);
- private Vector2 _sampleDesignSize = new Vector2(100f, 40f);
- private Vector2 _sampleCanvasSize = new Vector2(100f, 40f);
- private const string PrefScalarValue = "AppUI.DesignResolutionConverter.ScalarValue";
- private const string PrefScalarDir = "AppUI.DesignResolutionConverter.ScalarDir";
- private const string PrefScalarAxis = "AppUI.DesignResolutionConverter.ScalarAxis";
- private float _scalarInput = 100f;
- private int _scalarDirection; // 0: 设计稿→Canvas, 1: Canvas→设计稿
- private int _scalarAxis; // 0: 宽度轴 scaleX, 1: 高度轴 scaleY
- private Vector2 _scroll;
- [MenuItem("Tools/AppUI/设计稿与 Canvas 分辨率换算")]
- public static void Open()
- {
- var win = GetWindow<DesignResolutionConverterWindow>();
- win.titleContent = new GUIContent("设计稿 ↔ Canvas 换算");
- win.minSize = new Vector2(380f, 420f);
- }
- private void OnEnable()
- {
- _designArtboard.x = EditorPrefs.GetFloat(PrefDesignW, DesignResolutionConverter.DefaultDesignWidth);
- _designArtboard.y = EditorPrefs.GetFloat(PrefDesignH, DesignResolutionConverter.DefaultDesignHeight);
- _canvasReference.x = EditorPrefs.GetFloat(PrefCanvasW, DesignResolutionConverter.DefaultDesignWidth);
- _canvasReference.y = EditorPrefs.GetFloat(PrefCanvasH, DesignResolutionConverter.DefaultDesignHeight);
- _scalarInput = EditorPrefs.GetFloat(PrefScalarValue, 100f);
- _scalarDirection = EditorPrefs.GetInt(PrefScalarDir, 0);
- _scalarAxis = EditorPrefs.GetInt(PrefScalarAxis, 0);
- }
- private void SavePrefs()
- {
- EditorPrefs.SetFloat(PrefDesignW, _designArtboard.x);
- EditorPrefs.SetFloat(PrefDesignH, _designArtboard.y);
- EditorPrefs.SetFloat(PrefCanvasW, _canvasReference.x);
- EditorPrefs.SetFloat(PrefCanvasH, _canvasReference.y);
- }
- private void OnGUI()
- {
- _scroll = EditorGUILayout.BeginScrollView(_scroll);
- EditorGUILayout.LabelField("基准尺寸", EditorStyles.boldLabel);
- EditorGUILayout.HelpBox(
- "设计稿宽高:你在 Figma / Sketch 等中的画板像素尺寸(默认 402×874)。\n" +
- "Canvas 参考分辨率:当前场景 CanvasScaler 的 Reference Resolution。",
- MessageType.Info);
- EditorGUI.BeginChangeCheck();
- _designArtboard = EditorGUILayout.Vector2Field("设计稿宽高 (px)", _designArtboard);
- _canvasReference = EditorGUILayout.Vector2Field("Canvas Reference Resolution", _canvasReference);
- if (EditorGUI.EndChangeCheck())
- SavePrefs();
- EditorGUILayout.BeginHorizontal();
- if (GUILayout.Button("从选中对象读取 CanvasScaler"))
- PullFromSelection();
- if (GUILayout.Button("将设计稿尺寸填到 Canvas(与左栏相同)"))
- {
- _canvasReference = _designArtboard;
- SavePrefs();
- }
- EditorGUILayout.EndHorizontal();
- bool valid = _designArtboard.x > 0f && _designArtboard.y > 0f && _canvasReference.x > 0f && _canvasReference.y > 0f;
- if (!valid)
- EditorGUILayout.HelpBox("设计稿与 Canvas 的宽高均需大于 0。", MessageType.Warning);
- Vector2 scale = valid
- ? DesignResolutionConverter.GetScaleFactors(_designArtboard, _canvasReference)
- : Vector2.one;
- EditorGUILayout.Space(6f);
- EditorGUILayout.LabelField("轴向缩放系数", EditorStyles.boldLabel);
- if (valid)
- {
- EditorGUILayout.LabelField($"scaleX = {_canvasReference.x:F4} / {_designArtboard.x:F4} = {scale.x:F6}");
- EditorGUILayout.LabelField($"scaleY = {_canvasReference.y:F4} / {_designArtboard.y:F4} = {scale.y:F6}");
- }
- EditorGUILayout.Space(10f);
- EditorGUILayout.LabelField("单值换算", EditorStyles.boldLabel);
- EditorGUILayout.HelpBox("输入一个数,按所选轴向换算;结果可复制到剪贴板(Inspector / 代码中粘贴)。", MessageType.None);
- EditorGUI.BeginChangeCheck();
- _scalarDirection = GUILayout.Toolbar(_scalarDirection, new[] { "设计稿 → Canvas", "Canvas → 设计稿" });
- _scalarAxis = GUILayout.Toolbar(_scalarAxis, new[] { "按宽度轴 (scaleX)", "按高度轴 (scaleY)" });
- _scalarInput = EditorGUILayout.FloatField(_scalarDirection == 0 ? "输入值 (设计稿 px)" : "输入值 (Canvas 单位)", _scalarInput);
- if (EditorGUI.EndChangeCheck())
- {
- EditorPrefs.SetFloat(PrefScalarValue, _scalarInput);
- EditorPrefs.SetInt(PrefScalarDir, _scalarDirection);
- EditorPrefs.SetInt(PrefScalarAxis, _scalarAxis);
- }
- if (valid)
- {
- bool useWidthAxis = _scalarAxis == 0;
- float scalarResult = _scalarDirection == 0
- ? DesignResolutionConverter.DesignLengthToCanvas(_scalarInput, useWidthAxis, _designArtboard, _canvasReference)
- : DesignResolutionConverter.CanvasLengthToDesign(_scalarInput, useWidthAxis, _designArtboard, _canvasReference);
- string resultLabel = _scalarDirection == 0 ? "Canvas 单位" : "设计稿 px";
- EditorGUILayout.LabelField($"换算结果 ({resultLabel})", EditorStyles.boldLabel);
- string resultText = scalarResult.ToString("G9", CultureInfo.InvariantCulture);
- EditorGUILayout.SelectableLabel(resultText, GUILayout.Height(18f));
- EditorGUILayout.BeginHorizontal();
- if (GUILayout.Button("复制结果"))
- {
- EditorGUIUtility.systemCopyBuffer = resultText;
- ShowNotification(new GUIContent("已复制到剪贴板"));
- }
- if (GUILayout.Button("复制(保留 4 位小数)"))
- {
- string rounded = scalarResult.ToString("F4", CultureInfo.InvariantCulture);
- EditorGUIUtility.systemCopyBuffer = rounded;
- ShowNotification(new GUIContent("已复制(F4)"));
- }
- EditorGUILayout.EndHorizontal();
- }
- EditorGUILayout.Space(10f);
- EditorGUILayout.LabelField("尺寸换算", EditorStyles.boldLabel);
- _sampleDesignSize = EditorGUILayout.Vector2Field("设计稿上的宽×高 (px)", _sampleDesignSize);
- if (valid)
- {
- Vector2 toCanvas = DesignResolutionConverter.DesignSizeToCanvasUnits(_sampleDesignSize, _designArtboard, _canvasReference);
- EditorGUILayout.SelectableLabel($"→ Canvas 单位: ({toCanvas.x:F4}, {toCanvas.y:F4})", GUILayout.Height(18f));
- if (GUILayout.Button("将换算结果应用到选中 RectTransform(宽×高)"))
- ApplyCanvasSizeToSelection(toCanvas);
- }
- EditorGUILayout.Space(6f);
- _sampleCanvasSize = EditorGUILayout.Vector2Field("Canvas 上的宽×高", _sampleCanvasSize);
- if (valid)
- {
- Vector2 toDesign = DesignResolutionConverter.CanvasUnitsToDesignSize(_sampleCanvasSize, _designArtboard, _canvasReference);
- EditorGUILayout.SelectableLabel($"→ 设计稿 px: ({toDesign.x:F4}, {toDesign.y:F4})", GUILayout.Height(18f));
- if (GUILayout.Button("将当前 Canvas 宽×高应用到选中 RectTransform"))
- ApplyCanvasSizeToSelection(_sampleCanvasSize);
- }
- EditorGUILayout.Space(10f);
- EditorGUILayout.LabelField("文档", EditorStyles.boldLabel);
- if (GUILayout.Button("打开说明文档 (AppUI/Docs)"))
- {
- const string docPath = "Assets/AppUI/Docs/UI设计稿与Canvas分辨率换算.md";
- var obj = AssetDatabase.LoadAssetAtPath<Object>(docPath);
- if (obj != null)
- AssetDatabase.OpenAsset(obj);
- else
- EditorUtility.DisplayDialog("未找到", $"请确认文件存在:{docPath}", "确定");
- }
- EditorGUILayout.EndScrollView();
- }
- private void PullFromSelection()
- {
- GameObject go = Selection.activeGameObject;
- if (go == null)
- {
- EditorUtility.DisplayDialog("未选中", "请选中带有 CanvasScaler 的 GameObject(通常为 Canvas)。", "确定");
- return;
- }
- var scaler = go.GetComponent<CanvasScaler>();
- if (scaler == null)
- scaler = go.GetComponentInParent<CanvasScaler>();
- if (scaler == null)
- {
- EditorUtility.DisplayDialog("未找到 CanvasScaler", "选中对象及其父级上都没有 CanvasScaler。", "确定");
- return;
- }
- _canvasReference = scaler.referenceResolution;
- SavePrefs();
- ShowNotification(new GUIContent("已读取 Reference Resolution"));
- }
- /// <summary>
- /// 使用 RectTransform.SetSizeWithCurrentAnchors,在保持当前锚点的前提下写入宽、高。
- /// </summary>
- private void ApplyCanvasSizeToSelection(Vector2 sizeCanvasUnits)
- {
- GameObject[] gos = Selection.gameObjects;
- if (gos == null || gos.Length == 0)
- {
- EditorUtility.DisplayDialog("未选中", "请选中一个或多个带 RectTransform 的 UI 对象。", "确定");
- return;
- }
- int applied = 0;
- foreach (GameObject go in gos)
- {
- var rt = go.GetComponent<RectTransform>();
- if (rt == null)
- continue;
- Undo.RecordObject(rt, "Apply UI size from design converter");
- rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Horizontal, sizeCanvasUnits.x);
- rt.SetSizeWithCurrentAnchors(RectTransform.Axis.Vertical, sizeCanvasUnits.y);
- EditorUtility.SetDirty(rt);
- if (PrefabUtility.IsPartOfPrefabInstance(rt))
- PrefabUtility.RecordPrefabInstancePropertyModifications(rt);
- applied++;
- }
- if (applied == 0)
- EditorUtility.DisplayDialog("无 RectTransform", "选中对象中没有任何 RectTransform 组件。", "确定");
- else
- ShowNotification(new GUIContent($"已更新 {applied} 个对象的宽×高"));
- }
- }
- }
|