Unity GUI.Window 笔记
根据官方文档2021版本的,点击链接跳转记录
概述
GUI.Window
是 Unity IMGUI 系统中用于创建弹出窗口的核心方法,具有以下关键特性:
- 浮动窗口:浮于普通 GUI 控件之上
- 焦点控制:可通过点击获得焦点
- 可拖拽:支持拖拽移动位置
- 独立绘制:需要专门的函数来绘制窗口内容
方法签名
public static Rect Window(int id, Rect clientRect, GUI.WindowFunction func, string text, GUIStyle style
);
参数说明
参数 | 类型 | 描述 | 是否必需 |
---|---|---|---|
id | int | 窗口唯一标识符(必须保证唯一) | ✅ 必需 |
clientRect | Rect | 窗口初始位置和大小(屏幕矩形) | ✅ 必需 |
func | GUI.WindowFunction | 窗口内容绘制函数(接收窗口ID作为参数) | ✅ 必需 |
text | string | 窗口标题栏显示的文本 | ❌ 可选 |
image | Texture | 窗口标题栏显示的图像 | ❌ 可选 |
content | GUIContent | 窗口标题栏显示的内容(文本+图像) | ❌ 可选 |
style | GUIStyle | 窗口自定义样式(默认使用当前GUISkin的window样式) | ❌ 可选 |
返回值
Rect
:表示窗口当前位置和大小的矩形
核心机制
1. 多窗口管理
void OnGUI()
{// 多个窗口使用相同绘制函数windowRect0 = GUI.Window(0, windowRect0, DoMyWindow, "Window 0");windowRect1 = GUI.Window(1, windowRect1, DoMyWindow, "Window 1");
}void DoMyWindow(int windowID)
{// 根据ID区分窗口if (GUI.Button(new Rect(10, 20, 100, 20), "Click Me")){Debug.Log("Clicked in window: " + windowID);}
}
- 关键点:使用不同的ID区分窗口
- 优势:复用绘制函数减少代码冗余
2. 窗口显示控制
bool showWindow = true;void OnGUI()
{// 控制开关showWindow = GUI.Toggle(new Rect(10, 10, 100, 20), showWindow, "Show Window");if (showWindow){windowRect = GUI.Window(0, windowRect, DoMyWindow, "My Window");}
}
- 开启窗口:在OnGUI中调用GUI.Window
- 关闭窗口:停止调用GUI.Window
注意,到目前写这边博文25年六月并没有函数可以关闭,只可以通过类似这样的条件来控制
3. GUI状态保存
Unity自动保存/恢复以下状态:
GUI.skin
GUI.enabled
GUI.color
GUI.backgroundColor
GUI.contentColor
GUI.matrix
- 作用域:在调用
func
时恢复调用GUI.Window时的状态 - 应用场景:
void OnGUI() {GUI.color = Color.red;windowRect = GUI.Window(0, windowRect, DoMyWindow, "Red Window"); }void DoMyWindow(int id) {// 此处GUI.color为红色(被保存的状态) }
4. 透明效果
void DoMyWindow(int id)
{// 设置透明度GUI.color = new Color(1, 1, 1, 0.5f); // 50%透明// 窗口内容...
}
- 使用
GUI.color
的Alpha分量实现淡入淡出效果
最佳实践
1. 拖拽实现
void DoMyWindow(int id)
{// 顶部20像素为拖拽区域GUI.DragWindow(new Rect(0, 0, 10000, 20));// 窗口内容...
}
注意,这里的GUI.DragWindow只能在窗口回调函数(即GUI.Window的第三个参数所指定的函数)内部调用。
为什么必须在回调函数内调用?(我的疑惑)
是因为Unity IMGUI 事件处理流程
2. 窗口层级管理
void OnGUI()
{// 先绘制底层窗口bottomWindowRect = GUI.Window(1, bottomWindowRect, DrawBottom, "Bottom");// 后绘制顶层窗口(显示在上方)topWindowRect = GUI.Window(2, topWindowRect, DrawTop, "Top");
}
- 绘制顺序:后绘制的窗口显示在前
3. 自动布局窗口
void OnGUI()
{// 使用GUILayout.Window替代windowRect = GUILayout.Window(0, windowRect, DoWindowWithLayout, "Layout Window");
}void DoWindowWithLayout(int id)
{// 使用GUILayout自动布局GUILayout.Label("Auto layout content");if (GUILayout.Button("Button")){// ...}
}
限制与注意事项
-
GUILayout兼容性:
- 当
MonoBehaviour.useGUILayout = false
时,GUI.Window无效 - 使用GUILayout控件时,应使用
GUILayout.Window
- 当
-
绘制顺序:
- 窗口从后往前绘制(Z轴顺序)
- 不要依赖窗口函数的调用顺序
-
性能考虑:
- 频繁创建/销毁窗口可能影响性能
- 考虑复用窗口对象
-
移动平台:
- 触摸设备上拖拽体验可能不佳
- 需要增加热区大小
高级技巧
1. 窗口聚焦控制
void DoMyWindow(int id)
{if (GUILayout.Button("Focus Me")){GUI.FocusWindow(id);}
}
2. 窗口动画
IEnumerator AnimateWindow()
{float duration = 1f;for (float t = 0; t < duration; t += Time.deltaTime){windowRect.y = Mathf.Lerp(-100, 100, t/duration);yield return null;}
}
3. 模态窗口
void OnGUI()
{// 禁用背景GUI.enabled = !modalActive;// 绘制普通UI...// 启用并绘制模态窗口GUI.enabled = true;if (modalActive){modalRect = GUI.Window(0, modalRect, DrawModal, "Modal");}
}
总结
GUI.Window
是 Unity IMGUI 系统的核心组件,用于创建交互式窗口:
- 唯一ID是窗口系统的基础
- 返回值保存窗口位置状态
- GUI状态在窗口间自动保存/恢复
- 拖拽通过
GUI.DragWindow
实现 - 层级由绘制顺序决定