加入收藏 | 设为首页 | 会员中心 | 我要投稿 李大同 (https://www.lidatong.com.cn/)- 科技、建站、经验、云计算、5G、大数据,站长网!
当前位置: 首页 > 百科 > 正文

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

发布时间:2020-12-16 06:25:35 所属栏目:百科 来源:网络整理
导读:反正做都做了,再做一个用XML来布局并生成界面的 运行前它是这个样子: 运行TestXMLloadUI.cs脚本后,就生成了一个UI: 其中,加载XML布局的代码如下: using UnityEngine;using System.Collections;public class testXMLloadUI : MonoBehaviour {// Use thi

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

运行前它是这个样子:


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


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

using UnityEngine;
using System.Collections;

public class testXMLloadUI : MonoBehaviour {

	// Use this for initialization
	void Start () {
        UICreator.GetInstance().LoadFromXML(@"E:workcardToolsAssetsXMLFile1.xml");
	}
}

XMLFile1.xml的内容如下:
<?xml version="1.0" encoding="utf-8" ?>
<NGUILayout xmlns:UIyang ="983323204">
  <UIRoot
    name ="UI_TEST"
    depth ="0"
    parentName ="ui_1">
    
    <Sprite
      adpClass = "SpriteAdp"
      objName ="tSprite"
      depth ="2"
      atlasName ="xxx"
      spriteName = "Emoticon - Frown"
      width = "100"
      height = "100"
      collider = "false"
      updateColByCOM = "true"
      cX = "10"
      cY = "10">
      <Layout
        alignParentTop=""
        alignParentBaseLineX ="">
      </Layout>
    </Sprite>

    <Label
      adpClass = "LabelAdp"
      objName ="tLabel"
      depth ="3"
      width ="100"
      height ="100"
      collider ="false"
      text ="xxxx"
      updateColByCOM = "true"
      cX = "10"
      cY = "10">
      <Layout
        alignParentBottom=""
        alignParentBaseLineX="">
      </Layout>
    </Label>

    <Texture
      adpClass = "NormalCOMAdp"
      objName ="tTexture"
      depth ="1"
      width ="10"
      height ="10"
      collider ="false"
      updateColByCOM = "true"
      cX = "10"
      cY = "10">
      <Layout
        fillParent="">
      </Layout>
    </Texture>

    <MeteDate
      adpClass = "MeteDateAdp"
      objName ="md"
      depth ="4">
      <Layout
        centerHorizontal=""
        centerVertical="">
      </Layout>
    </MeteDate>
    
  </UIRoot>
</NGUILayout>

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

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

using UnityEngine;
using System.Collections;
using System.Collections.Generic;
using System.Xml;
using System;
using yang.UI;
using System.Reflection;

public class UICreator : MonoBehaviour {

    static UICreator instance;
    public static UICreator GetInstance() {
        return instance;
    }
    void Awake() {
        instance = this;
    }

    public UIWidget[] template;
    public string LastError;
    public UIWidget ui;

    public List<UIWidget> LoadFromXML(string url,Func<string,string> fileHandle = null){ 
        string xmlPath;
        if(fileHandle!=null){
            xmlPath = fileHandle(url);
        }else{
            xmlPath = url;
        }
        List<UIWidget> lst_R_N = null;
        //try {
            XmlTextReader xTR = new XmlTextReader(xmlPath);
            xTR.WhitespaceHandling = WhitespaceHandling.None;
            while(xTR.Read()){
                xTR.MoveToElement();
                int nd = xTR.Depth;
                if (xTR.NodeType == XmlNodeType.EndElement)
                    continue;
                //Debug.Log("current: " + xTR.Name+",depth:"+nd);
                switch (nd) { 
                    case 0://XML声明,不处理
                        break;
                    case 1://UIRoot
                        if (lst_R_N != null)
                            return null;
                        else {
                            //生成实例
                            GameObject uiroot = Instantiate(ui.gameObject) as GameObject;
                            UIWidget R = uiroot.GetComponent<UIWidget>();
                            //获得属性
                            string uiName = xTR.GetAttribute("name");
                            string depth = xTR.GetAttribute("depth");
                            string parentName = xTR.GetAttribute("parentName");
                            //放入场景
                            uiroot.name = uiName;
                            R.depth = Int32.Parse(depth);
                            UIRect pHook = getUIParent(parentName);
                            uiroot.transform.parent = pHook.transform;
                            uiroot.transform.localScale = Vector3.one;
                            Dictionary<Layout,string> hLayout = new Dictionary<Layout,string>();
                            hLayout.Add(Layout.fillParent,"");
                            UILayoutTool.LayoutUI(R,null,hLayout);
                            lst_R_N = new List<UIWidget>();
                            lst_R_N.Add(R);
                        }
                        break;
                    case 2://widget
                        if (lst_R_N == null) {
                            Debug.Log("return");
                            return null;
                        } else { 
                            string nodeName = xTR.Name;
                            WidgetType wt;
                            try {
                                wt = (WidgetType)Enum.Parse(typeof(WidgetType),nodeName);
                            } catch {
                                Debug.Log("转换失败:" + nodeName);
                                wt = WidgetType.None;
                            }
                            //生成实例
                            int index = (int)wt;
                            GameObject inst = Instantiate(template[index].gameObject) as GameObject;
                            UIWidget w = inst.GetComponent<UIWidget>();
                            //获得适配类名并反射执行
                            string adpClass = xTR.GetAttribute("adpClass");
                            //Debug.Log(xTR.Name+","+adpClass+",");
                            Type adp = Type.GetType(adpClass);
                            var CInfo = adp.GetConstructor(Type.EmptyTypes);
                            var objAdp = CInfo.Invoke(null);
                            MethodInfo minfo = adp.GetMethod("Init");
                            minfo.Invoke(objAdp,new object[] {xTR,w});
                            //放入场景
                            GameObject uiroot = lst_R_N[0].gameObject;
                            inst.transform.parent = uiroot.transform;
                            inst.transform.localScale = Vector3.one;
                            lst_R_N.Add(w);
                        }
                        break;
                    case 3://layout
                        if (lst_R_N == null) {
                            return null;
                        } else {
                            UIWidget currentWidget = lst_R_N[lst_R_N.Count - 1];
                            Dictionary<Layout,string> layout = new Dictionary<Layout,string>();
                            int ac = xTR.AttributeCount;
                            for (int i = 0; i < ac; i++) {
                                xTR.MoveToAttribute(i);
                                string k = xTR.Name;
                                string v = xTR.Value;
                                layout.Add((Layout)Enum.Parse(typeof(Layout),k),v);
                            }
                            UILayoutTool.LayoutUI(currentWidget,layout);
                            //xTR.MoveToElement();
                        }
                        break;
                    default://其它层节点,不处理
                        break;
                }
            }
            return lst_R_N;
        //} catch (Exception e){
        //    Debug.Log(e.ToString());
        //    return null;
        //}
    }
    public UIRect defaultRoot;
    /// <summary>
    /// 寻找UI挂接点
    /// </summary>
    private UIRect getUIParent(string name){
        return defaultRoot;
    }
}
//UI组件
public class COMAdp {
    public virtual void Init(XmlTextReader xTR,UIWidget widget) {
        string comName = xTR.GetAttribute("objName");
        string depth = xTR.GetAttribute("depth");
        widget.gameObject.name = comName;
        widget.depth = Int32.Parse(depth);
    }
}
public class NormalCOMAdp : COMAdp {
    public override void Init(XmlTextReader xTR,UIWidget widget) {
        base.Init(xTR,widget);
        string width = xTR.GetAttribute("width");
        string heigth = xTR.GetAttribute("height");
        string collider = xTR.GetAttribute("collider");
        string updateColByCOM = xTR.GetAttribute("updateColByCOM");
        string cX = xTR.GetAttribute("cX");
        string cY = xTR.GetAttribute("cY");
        widget.width = Int32.Parse(width);
        widget.height = Int32.Parse(heigth);
        if(Boolean.Parse(collider)){
            var col = widget.gameObject.AddComponent<BoxCollider>();
            if (Boolean.Parse(updateColByCOM)) {
                widget.autoResizeBoxCollider = true;
            } else {
                col.size = new Vector3(Int32.Parse(cX),Int32.Parse(cY));
            }
        }
    }
}
public class SpriteAdp : NormalCOMAdp {
    public override void Init(XmlTextReader xTR,widget);
        string atlasName = xTR.GetAttribute("atlasName");
        string spriteName = xTR.GetAttribute("spriteName");
        var s = (UISprite)widget;
        s.spriteName = spriteName;
    }
}
public class LabelAdp : NormalCOMAdp {
    public override void Init(XmlTextReader xTR,widget);
        string text = xTR.GetAttribute("text");
        var l = (UILabel)widget;
        l.text = text;
    }
}
public class MeteDateAdp : COMAdp {
    public override void Init(XmlTextReader xTR,widget);
    }
}

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

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

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

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

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

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

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

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

using UnityEngine;
using System.Collections;
using UnityEditor;

[CustomEditor(typeof(UICreator),true)]
public class UICreatorEditor : Editor {

    protected UICreator mUICreator;
    void OnEnable() {
        mUICreator = target as UICreator;
        if(mUICreator.template == null)
            mUICreator.template = new UIWidget[10];
    }
    public override void OnInspectorGUI() {
        //base.OnInspectorGUI();
        serializedObject.Update();
        mUICreator.defaultRoot = (UIRect)EditorGUILayout.ObjectField("默认UI挂接点",mUICreator.defaultRoot,typeof(UIRect));
        mUICreator.ui = (UIWidget)EditorGUILayout.ObjectField("UI根",mUICreator.ui,typeof(UIWidget));
        EditorGUILayout.Separator();
        if (NGUIEditorTools.DrawHeader("prefab")) {
            NGUIEditorTools.BeginContents();
            mUICreator.template[0] = (UIWidget)EditorGUILayout.ObjectField("MeteDate(自定义)",mUICreator.template[0],typeof(UIWidget));
            mUICreator.template[1] = (UIWidget)EditorGUILayout.ObjectField("Sprite(精灵)",mUICreator.template[1],typeof(UIWidget));
            mUICreator.template[2] = (UIWidget)EditorGUILayout.ObjectField("Label(字符串)",mUICreator.template[2],typeof(UIWidget));
            mUICreator.template[3] = (UIWidget)EditorGUILayout.ObjectField("Texture(纹理)",mUICreator.template[3],typeof(UIWidget));
            mUICreator.template[4] = (UIWidget)EditorGUILayout.ObjectField("Button(按钮)",mUICreator.template[4],typeof(UIWidget));
            mUICreator.template[5] = (UIWidget)EditorGUILayout.ObjectField("Toggle(选择框)",mUICreator.template[5],typeof(UIWidget));
            mUICreator.template[6] = (UIWidget)EditorGUILayout.ObjectField("ProgressBar(进度条)",mUICreator.template[6],typeof(UIWidget));
            mUICreator.template[7] = (UIWidget)EditorGUILayout.ObjectField("Slider(滑动条)",mUICreator.template[7],typeof(UIWidget));
            mUICreator.template[8] = (UIWidget)EditorGUILayout.ObjectField("Input(输入框)",mUICreator.template[8],typeof(UIWidget));
            mUICreator.template[9] = (UIWidget)EditorGUILayout.ObjectField("ScrollBar(滚动条)",mUICreator.template[9],typeof(UIWidget));
            NGUIEditorTools.EndContents();
        }
        EditorGUILayout.Separator();
        serializedObject.ApplyModifiedProperties();
    }
}

(编辑:李大同)

【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容!

    推荐文章
      热点阅读