上一篇的加强版:NGUI通过XML布局

前端之家收集整理的这篇文章主要介绍了上一篇的加强版:NGUI通过XML布局前端之家小编觉得挺不错的,现在分享给大家,也给大家做个参考。

反正做都做了,再做一个用XML来布局并生成界面的

运行前它是这个样子:


运行TestXMLloadUI.cs脚本后,就生成了一个UI:


其中,加载XML布局的代码如下:

  1. using UnityEngine;
  2. using System.Collections;
  3.  
  4. public class testXMLloadUI : MonoBehavIoUr {
  5.  
  6. // Use this for initialization
  7. void Start () {
  8. UICreator.GetInstance().LoadFromXML(@"E:\work\cardTools\Assets\XMLFile1.xml");
  9. }
  10. }

XMLFile1.xml的内容如下:
  1. <?xml version="1.0" encoding="utf-8" ?>
  2. <NGUILayout xmlns:UIyang ="983323204">
  3. <UIRoot
  4. name ="UI_TEST"
  5. depth ="0"
  6. parentName ="ui_1">
  7. <Sprite
  8. adpClass = "SpriteAdp"
  9. objName ="tSprite"
  10. depth ="2"
  11. atlasName ="xxx"
  12. spriteName = "Emoticon - Frown"
  13. width = "100"
  14. height = "100"
  15. collider = "false"
  16. updateColByCOM = "true"
  17. cX = "10"
  18. cY = "10">
  19. <Layout
  20. alignParentTop=""
  21. alignParentBaseLineX ="">
  22. </Layout>
  23. </Sprite>
  24.  
  25. <Label
  26. adpClass = "LabelAdp"
  27. objName ="tLabel"
  28. depth ="3"
  29. width ="100"
  30. height ="100"
  31. collider ="false"
  32. text ="xxxx"
  33. updateColByCOM = "true"
  34. cX = "10"
  35. cY = "10">
  36. <Layout
  37. alignParentBottom=""
  38. alignParentBaseLineX="">
  39. </Layout>
  40. </Label>
  41.  
  42. <Texture
  43. adpClass = "NormalCOMAdp"
  44. objName ="tTexture"
  45. depth ="1"
  46. width ="10"
  47. height ="10"
  48. collider ="false"
  49. updateColByCOM = "true"
  50. cX = "10"
  51. cY = "10">
  52. <Layout
  53. fillParent="">
  54. </Layout>
  55. </Texture>
  56.  
  57. <MeteDate
  58. adpClass = "MeteDateAdp"
  59. objName ="md"
  60. depth ="4">
  61. <Layout
  62. centerHorizontal=""
  63. centerVertical="">
  64. </Layout>
  65. </MeteDate>
  66. </UIRoot>
  67. </NGUILayout>

格式是我自己定义的,每个组件有它自己的属性和一个布局,其中布局的string是和上一篇中的布局enum一致的,并且在代码中有互相转换的地方

那么,重要部分来了,解析XML并生成UI的代码如下:

  1. using UnityEngine;
  2. using System.Collections;
  3. using System.Collections.Generic;
  4. using System.Xml;
  5. using System;
  6. using yang.UI;
  7. using System.Reflection;
  8.  
  9. public class UICreator : MonoBehavIoUr {
  10.  
  11. static UICreator instance;
  12. public static UICreator GetInstance() {
  13. return instance;
  14. }
  15. void Awake() {
  16. instance = this;
  17. }
  18.  
  19. public UIWidget[] template;
  20. public string LastError;
  21. public UIWidget ui;
  22.  
  23. public List<UIWidget> LoadFromXML(string url,Func<string,string> fileHandle = null){
  24. string xmlPath;
  25. if(fileHandle!=null){
  26. xmlPath = fileHandle(url);
  27. }else{
  28. xmlPath = url;
  29. }
  30. List<UIWidget> lst_R_N = null;
  31. //try {
  32. XmlTextReader xTR = new XmlTextReader(xmlPath);
  33. xTR.WhitespaceHandling = WhitespaceHandling.None;
  34. while(xTR.Read()){
  35. xTR.MoveToElement();
  36. int nd = xTR.Depth;
  37. if (xTR.NodeType == XmlNodeType.EndElement)
  38. continue;
  39. //Debug.Log("current: " + xTR.Name+",depth:"+nd);
  40. switch (nd) {
  41. case 0://XML声明,不处理
  42. break;
  43. case 1://UIRoot
  44. if (lst_R_N != null)
  45. return null;
  46. else {
  47. //生成实例
  48. GameObject uiroot = Instantiate(ui.gameObject) as GameObject;
  49. UIWidget R = uiroot.GetComponent<UIWidget>();
  50. //获得属性
  51. string uiName = xTR.GetAttribute("name");
  52. string depth = xTR.GetAttribute("depth");
  53. string parentName = xTR.GetAttribute("parentName");
  54. //放入场景
  55. uiroot.name = uiName;
  56. R.depth = Int32.Parse(depth);
  57. UIRect pHook = getUIParent(parentName);
  58. uiroot.transform.parent = pHook.transform;
  59. uiroot.transform.localScale = Vector3.one;
  60. Dictionary<Layout,string> hLayout = new Dictionary<Layout,string>();
  61. hLayout.Add(Layout.fillParent,"");
  62. UILayoutTool.LayoutUI(R,null,hLayout);
  63. lst_R_N = new List<UIWidget>();
  64. lst_R_N.Add(R);
  65. }
  66. break;
  67. case 2://widget
  68. if (lst_R_N == null) {
  69. Debug.Log("return");
  70. return null;
  71. } else {
  72. string nodeName = xTR.Name;
  73. WidgetType wt;
  74. try {
  75. wt = (WidgetType)Enum.Parse(typeof(WidgetType),nodeName);
  76. } catch {
  77. Debug.Log("转换失败:" + nodeName);
  78. wt = WidgetType.None;
  79. }
  80. //生成实例
  81. int index = (int)wt;
  82. GameObject inst = Instantiate(template[index].gameObject) as GameObject;
  83. UIWidget w = inst.GetComponent<UIWidget>();
  84. //获得适配类名并反射执行
  85. string adpClass = xTR.GetAttribute("adpClass");
  86. //Debug.Log(xTR.Name+","+adpClass+",");
  87. Type adp = Type.GetType(adpClass);
  88. var CInfo = adp.GetConstructor(Type.EmptyTypes);
  89. var objAdp = CInfo.Invoke(null);
  90. MethodInfo minfo = adp.GetMethod("Init");
  91. minfo.Invoke(objAdp,new object[] {xTR,w});
  92. //放入场景
  93. GameObject uiroot = lst_R_N[0].gameObject;
  94. inst.transform.parent = uiroot.transform;
  95. inst.transform.localScale = Vector3.one;
  96. lst_R_N.Add(w);
  97. }
  98. break;
  99. case 3://layout
  100. if (lst_R_N == null) {
  101. return null;
  102. } else {
  103. UIWidget currentWidget = lst_R_N[lst_R_N.Count - 1];
  104. Dictionary<Layout,string> layout = new Dictionary<Layout,string>();
  105. int ac = xTR.AttributeCount;
  106. for (int i = 0; i < ac; i++) {
  107. xTR.MoveToAttribute(i);
  108. string k = xTR.Name;
  109. string v = xTR.Value;
  110. layout.Add((Layout)Enum.Parse(typeof(Layout),k),v);
  111. }
  112. UILayoutTool.LayoutUI(currentWidget,layout);
  113. //xTR.MoveToElement();
  114. }
  115. break;
  116. default://其它层节点,不处理
  117. break;
  118. }
  119. }
  120. return lst_R_N;
  121. //} catch (Exception e){
  122. // Debug.Log(e.ToString());
  123. // return null;
  124. //}
  125. }
  126. public UIRect defaultRoot;
  127. /// <summary>
  128. /// 寻找UI挂接点
  129. /// </summary>
  130. private UIRect getUIParent(string name){
  131. return defaultRoot;
  132. }
  133. }
  134. //UI组件
  135. public class COMAdp {
  136. public virtual void Init(XmlTextReader xTR,UIWidget widget) {
  137. string comName = xTR.GetAttribute("objName");
  138. string depth = xTR.GetAttribute("depth");
  139. widget.gameObject.name = comName;
  140. widget.depth = Int32.Parse(depth);
  141. }
  142. }
  143. public class NormalCOMAdp : COMAdp {
  144. public override void Init(XmlTextReader xTR,UIWidget widget) {
  145. base.Init(xTR,widget);
  146. string width = xTR.GetAttribute("width");
  147. string heigth = xTR.GetAttribute("height");
  148. string collider = xTR.GetAttribute("collider");
  149. string updateColByCOM = xTR.GetAttribute("updateColByCOM");
  150. string cX = xTR.GetAttribute("cX");
  151. string cY = xTR.GetAttribute("cY");
  152. widget.width = Int32.Parse(width);
  153. widget.height = Int32.Parse(heigth);
  154. if(Boolean.Parse(collider)){
  155. var col = widget.gameObject.AddComponent<BoxCollider>();
  156. if (Boolean.Parse(updateColByCOM)) {
  157. widget.autoResizeBoxCollider = true;
  158. } else {
  159. col.size = new Vector3(Int32.Parse(cX),Int32.Parse(cY));
  160. }
  161. }
  162. }
  163. }
  164. public class SpriteAdp : NormalCOMAdp {
  165. public override void Init(XmlTextReader xTR,widget);
  166. string atlasName = xTR.GetAttribute("atlasName");
  167. string spriteName = xTR.GetAttribute("spriteName");
  168. var s = (UISprite)widget;
  169. s.spriteName = spriteName;
  170. }
  171. }
  172. public class LabelAdp : NormalCOMAdp {
  173. public override void Init(XmlTextReader xTR,widget);
  174. string text = xTR.GetAttribute("text");
  175. var l = (UILabel)widget;
  176. l.text = text;
  177. }
  178. }
  179. public class MeteDateAdp : COMAdp {
  180. public override void Init(XmlTextReader xTR,widget);
  181. }
  182. }

同时在调试的过程中发现上一篇的UILayoutTool.cs是存在问题的,就是上次是布局已经存在于场景中的UIWidget,而这一次是从prefab生成的,所以72-75行的获取组件父物体方法是失败的,大概原因是prefab的脚本缓存了错误的父物体,改为如下则没有问题了:
  1. <span style="white-space:pre"> </span>if (NGUITools.FindInParents<UIRect>(widget.transform.parent.gameObject).GetType() == typeof(UIPanel)) {
  2. ptarget = (UIPanel)NGUITools.FindInParents<UIRect>(widget.transform.parent.gameObject);
  3. } else {
  4. target = (UIWidget)NGUITools.FindInParents<UIRect>(widget.transform.parent.gameObject);
  5. }

写得比较粗糙,目前还存在的问题有:

XML的格式要求比较严格,没做缺省参数检查,必须写完所有参数;在XML中也不支持注释等

Sprite没有做加载图集部分,现在只能用prefab指定的图集

Textrue同样没有做设置mainTexture的部分,需要手动在其它地方设置

MeteData类型的UI组件要自己写XML属性提取

不过,LoadFromXML函数返回了UI的根和所有的组件的list,可以利用它做更多的事情,也可以结合一些动态脚本什么的,做更多东西

哦,对了,还有个UICreatorEditor.cs,就是UICreator的面板显示脚本:

  1. using UnityEngine;
  2. using System.Collections;
  3. using UnityEditor;
  4.  
  5. [CustomEditor(typeof(UICreator),true)]
  6. public class UICreatorEditor : Editor {
  7.  
  8. protected UICreator mUICreator;
  9. void OnEnable() {
  10. mUICreator = target as UICreator;
  11. if(mUICreator.template == null)
  12. mUICreator.template = new UIWidget[10];
  13. }
  14. public override void OnInspectorGUI() {
  15. //base.OnInspectorGUI();
  16. serializedObject.Update();
  17. mUICreator.defaultRoot = (UIRect)EditorGUILayout.ObjectField("默认UI挂接点",mUICreator.defaultRoot,typeof(UIRect));
  18. mUICreator.ui = (UIWidget)EditorGUILayout.ObjectField("UI根",mUICreator.ui,typeof(UIWidget));
  19. EditorGUILayout.Separator();
  20. if (NGUIEditorTools.DrawHeader("prefab")) {
  21. NGUIEditorTools.BeginContents();
  22. mUICreator.template[0] = (UIWidget)EditorGUILayout.ObjectField("MeteDate(自定义)",mUICreator.template[0],typeof(UIWidget));
  23. mUICreator.template[1] = (UIWidget)EditorGUILayout.ObjectField("Sprite(精灵)",mUICreator.template[1],typeof(UIWidget));
  24. mUICreator.template[2] = (UIWidget)EditorGUILayout.ObjectField("Label(字符串)",mUICreator.template[2],typeof(UIWidget));
  25. mUICreator.template[3] = (UIWidget)EditorGUILayout.ObjectField("Texture(纹理)",mUICreator.template[3],typeof(UIWidget));
  26. mUICreator.template[4] = (UIWidget)EditorGUILayout.ObjectField("Button(按钮)",mUICreator.template[4],typeof(UIWidget));
  27. mUICreator.template[5] = (UIWidget)EditorGUILayout.ObjectField("Toggle(选择框)",mUICreator.template[5],typeof(UIWidget));
  28. mUICreator.template[6] = (UIWidget)EditorGUILayout.ObjectField("ProgressBar(进度条)",mUICreator.template[6],typeof(UIWidget));
  29. mUICreator.template[7] = (UIWidget)EditorGUILayout.ObjectField("Slider(滑动条)",mUICreator.template[7],typeof(UIWidget));
  30. mUICreator.template[8] = (UIWidget)EditorGUILayout.ObjectField("Input(输入框)",mUICreator.template[8],typeof(UIWidget));
  31. mUICreator.template[9] = (UIWidget)EditorGUILayout.ObjectField("ScrollBar(滚动条)",mUICreator.template[9],typeof(UIWidget));
  32. NGUIEditorTools.EndContents();
  33. }
  34. EditorGUILayout.Separator();
  35. serializedObject.ApplyModifiedProperties();
  36. }
  37. }

猜你在找的XML相关文章