UGUI源码分析-编辑器右键创建Image的过程

在一个空的scene,UGUI是如何创建一个Image组件的?

简单的介绍

  1. Canvas 画布,所有的UI显示元素必须在canvas中,Canvas 是UGUI组织界面的根节点。
  2. Image 创建的图片。
  3. EventSystem 事件系统,所有的点击,拖拽,按钮都是在这里处理完转发给UI组件的。

初始化的这部分代码都在MenuOptions.cs中,任何右键相关的创建命令都在这里编写,我们这里就看下Image的创建过程,其他都是类似的。

MenuOptions.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119

[MenuItem("GameObject/UI/Image", false, 2001)]
static public void AddImage(MenuCommand menuCommand)
{
GameObject go = DefaultControls.CreateImage(GetStandardResources());
PlaceUIElementRoot(go, menuCommand);
}

private static void PlaceUIElementRoot(GameObject element, MenuCommand menuCommand)
{
GameObject parent = menuCommand.context as GameObject;
bool explicitParentChoice = true;
if (parent == null)
{
parent = GetOrCreateCanvasGameObject();
explicitParentChoice = false;

// If in Prefab Mode, Canvas has to be part of Prefab contents,
// otherwise use Prefab root instead.
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null && !prefabStage.IsPartOfPrefabContents(parent))
parent = prefabStage.prefabContentsRoot;
}
if (parent.GetComponentsInParent<Canvas>(true).Length == 0)
{
// Create canvas under context GameObject,
// and make that be the parent which UI element is added under.
GameObject canvas = MenuOptions.CreateNewUI();
canvas.transform.SetParent(parent.transform, false);
parent = canvas;
}

// Setting the element to be a child of an element already in the scene should
// be sufficient to also move the element to that scene.
// However, it seems the element needs to be already in its destination scene when the
// RegisterCreatedObjectUndo is performed; otherwise the scene it was created in is dirtied.
SceneManager.MoveGameObjectToScene(element, parent.scene);

Undo.RegisterCreatedObjectUndo(element, "Create " + element.name);

if (element.transform.parent == null)
{
Undo.SetTransformParent(element.transform, parent.transform, "Parent " + element.name);
}

GameObjectUtility.EnsureUniqueNameForSibling(element);

// We have to fix up the undo name since the name of the object was only known after reparenting it.
Undo.SetCurrentGroupName("Create " + element.name);

GameObjectUtility.SetParentAndAlign(element, parent);
if (!explicitParentChoice) // not a context click, so center in sceneview
SetPositionVisibleinSceneView(parent.GetComponent<RectTransform>(), element.GetComponent<RectTransform>());

Selection.activeGameObject = element;
}

//创建canvas
static public GameObject CreateNewUI()
{
// Root for the UI
var root = new GameObject("Canvas");
root.layer = LayerMask.NameToLayer(kUILayerName);
Canvas canvas = root.AddComponent<Canvas>();
canvas.renderMode = RenderMode.ScreenSpaceOverlay;
root.AddComponent<CanvasScaler>();
root.AddComponent<GraphicRaycaster>();

// Works for all stages.
StageUtility.PlaceGameObjectInCurrentStage(root);
bool customScene = false;
PrefabStage prefabStage = PrefabStageUtility.GetCurrentPrefabStage();
if (prefabStage != null)
{
root.transform.SetParent(prefabStage.prefabContentsRoot.transform, false);
customScene = true;
}

Undo.RegisterCreatedObjectUndo(root, "Create " + root.name);

// If there is no event system add one...
// No need to place event system in custom scene as these are temporary anyway.
// It can be argued for or against placing it in the user scenes,
// but let's not modify scene user is not currently looking at.
if (!customScene)
CreateEventSystem(false);
return root;
}


private static void CreateEventSystem(bool select)
{
CreateEventSystem(select, null);
}

//创建事件系统
private static void CreateEventSystem(bool select, GameObject parent)
{
StageHandle stage = parent == null ? StageUtility.GetCurrentStageHandle() : StageUtility.GetStageHandle(parent);
var esys = stage.FindComponentOfType<EventSystem>();
if (esys == null)
{
var eventSystem = new GameObject("EventSystem");
if (parent == null)
StageUtility.PlaceGameObjectInCurrentStage(eventSystem);
else
GameObjectUtility.SetParentAndAlign(eventSystem, parent);
esys = eventSystem.AddComponent<EventSystem>();
eventSystem.AddComponent<StandaloneInputModule>();

Undo.RegisterCreatedObjectUndo(eventSystem, "Create " + eventSystem.name);
}

if (select && esys != null)
{
Selection.activeGameObject = esys.gameObject;
}
}