zoukankan      html  css  js  c++  java
  • 懒人的UI变量序列化

      今天翻到一个以前写的序列化代码, 感觉有点惊艳啊, 懒人的典范, 必须记录一下才行.

      事情是这样的, 比如有一个模拟, 每次打开都要往面板里面设置数据才能开始, 本来要求是每次都填的, 然后直接逻辑就读取了UI变量了, 然后要改成能够保存的方式, 于是有了这个脚本...

    比如一个界面如图 : 

      

      怎样把界面序列化, 很简单, 把UI元素的 Toggle, Text, DropDown 这些的变量找出来就行了...

    using System.Collections;
    using System.Collections.Generic;
    using UnityEngine;
    using UnityEngine.UI;
    using System;
    using System.Linq;
    
    namespace Tools
    {
        /// <summary>
        /// 运行时 UI 序列化工具, 通过节点相对路径获取UI数值, 保存Json
        /// 运行时 UI 反序列化工具, 通过相对路径对UI赋值
        /// </summary>
        public class CustomUISerializer
        {
            public class SerializeData
            {
                public WrappedSerializeData<Text, string> Text = new WrappedSerializeData<Text, string>();
                public WrappedSerializeData<InputField, string> InputField = new WrappedSerializeData<InputField, string>();
    
                public WrappedSerializeData<Toggle, bool> Toggles = new WrappedSerializeData<Toggle, bool>();
                public WrappedSerializeData<SwitchButton, bool> SwitchButton = new WrappedSerializeData<SwitchButton, bool>();
                public WrappedSerializeData<Slider, float> Slider = new WrappedSerializeData<Slider, float>();
                public WrappedSerializeData<Dropdown, int> Dropdown = new WrappedSerializeData<Dropdown, int>();
            }
    
            public class WrappedSerializeData<TComp, TVal> where TComp : UnityEngine.Component where TVal : IConvertible
            {
                public Dictionary<string, List<TVal>> Datas = new Dictionary<string, List<TVal>>();
    
                #region Main Funcs
                /// <summary>
                /// Serialize UI in runtime to json
                /// </summary>
                /// <param name="root"></param>
                /// <param name="serializeFunc"></param>
                public void SerializeUI(Transform root, System.Func<TComp, TVal> serializeFunc)
                {
                    Datas.Clear();
                    var collections = CustomUISerializer.GetComponentCollections<TComp>(root);
                    WrappedGetComponentCollections(collections, serializeFunc);
                }
                /// <summary>
                /// Deserialize UI runtime from json
                /// </summary>
                /// <param name="root"></param>
                /// <param name="applyFunc"></param>
                public void DeserializeUI(Transform root, System.Action<TComp, TVal> applyFunc)
                {
                    if(applyFunc != null)
                    {
                        CustomUISerializer.ApplyToComponentCollections<TComp, TVal>(root, Datas, applyFunc);
                    }
                }
                #endregion
    
                #region Help Funcs
                private void WrappedGetComponentCollections(Dictionary<string, List<TComp>> collections, System.Func<TComp, TVal> serializeFunc)
                {
                    foreach(var collection in collections)
                    {
                        Datas[collection.Key] = collection.Value.Select(_item => serializeFunc.Invoke(_item)).ToList();
                    }
                }
                #endregion
            }
    
            private static System.Text.StringBuilder _sb = new System.Text.StringBuilder();
    
            /// <summary>
            /// Serialize UI Data to Json
            /// </summary>
            /// <param name="root"></param>
            /// <returns></returns>
            public static string SerializeUIToJson<T>(Transform root) where T : SerializeData, new()
            {
                T data = SerializeUIToData<T>(root);
                var json = LitJson.JsonMapper.ToJson(data);
                return json;
            }
    
            /// <summary>
            /// Serialize UI Data to intermediate data
            /// </summary>
            /// <param name="root"></param>
            /// <returns></returns>
            public static T SerializeUIToData<T>(Transform root) where T : SerializeData, new()
            {
                T data = new T();
    
                // Text
                data.Text.SerializeUI(root, (_comp) => { return _comp.text; });
                // InputField
                data.InputField.SerializeUI(root, (_comp) => { return _comp.text; });
    
                // Toggle
                data.Toggles.SerializeUI(root, (_comp) => { return _comp.isOn; });
                // SwitchButton
                data.SwitchButton.SerializeUI(root, (_comp) => { return _comp.isOn; });
                // Slider
                data.Slider.SerializeUI(root, (_comp) => { return _comp.value; });
                // Dropdown
                data.Dropdown.SerializeUI(root, (_comp) => { return _comp.value; });return data;
            }
    
            /// <summary>
            /// DeSerialize UI data from SerializeData
            /// </summary>
            /// <param name="root"></param>
            /// <param name="data"></param>
            public static void ApplySerializedDataToUI<T>(Transform root, T data) where T : SerializeData, new()
            {
                // Text
                data.Text.DeserializeUI(root, (_comp, _str) => { _comp.text = _str; });
                // InputField
                data.InputField.DeserializeUI(root, (_comp, _str) => { _comp.text = _str; });
    
                // Toggle
                data.Toggles.DeserializeUI(root, (_comp, _bool) => { _comp.isOn = _bool; });
                // SwitchButton
                data.SwitchButton.DeserializeUI(root, (_comp, _bool) => { _comp.isOn = _bool; });
                // Slider
                data.Slider.DeserializeUI(root, (_comp, _float) => { _comp.value = _float; });
                // Dropdown
                data.Dropdown.DeserializeUI(root, (_comp, _int) => { _comp.value = _int; });
            }
            /// <summary>
            /// DeSerialize UI data from Json
            /// </summary>
            /// <param name="root"></param>
            /// <param name="json"></param>
            public static void ApplySerializedDataToUI(string json, Transform root)
            {
                ApplySerializedDataToUI(root, LitJson.JsonMapper.ToObject<SerializeData>(json));
            }
    
            #region Help Funcs
            // wrapped get component data to serialized value
            public static Dictionary<string, List<TVal>> GetComponentCollections<T, TVal>(Transform root, System.Func<T, TVal> serializeFunc) where T : UnityEngine.Component
            {
                var collections = GetComponentCollections<T>(root);
                var tagCollectoins = GetComponentCollections(collections, serializeFunc);
                return tagCollectoins;
            }
            // get component data to serialized value
            public static Dictionary<string, List<TVal>> GetComponentCollections<T, TVal>(Dictionary<string, List<T>> collections, System.Func<T, TVal> serializeFunc) where T : UnityEngine.Component
            {
                Dictionary<string, List<TVal>> retVal = new Dictionary<string, List<TVal>>();
                foreach(var collection in collections)
                {
                    retVal[collection.Key] = collection.Value.Select(_item => serializeFunc.Invoke(_item)).ToList();
                }
                return retVal;
            }
            // get real components from hierarchy
            public static Dictionary<string, List<T>> GetComponentCollections<T>(Transform root) where T : UnityEngine.Component
            {
                Dictionary<string, List<T>> retVal = new Dictionary<string, List<T>>();
                var comps = root.GetComponentsInChildren<T>(true);
                foreach(var comp in comps)
                {
                    var path = GetRelativePath(root, comp);
                    retVal.GetValue(path).Add(comp);
                }
                return retVal;
            }
    
            public static void ApplyToComponentCollections<T, TVal>(Transform root, Dictionary<string, List<TVal>> collections, System.Action<T, TVal> access) where T : UnityEngine.Component
            {
                foreach(var collection in collections)
                {
                    Transform node = string.IsNullOrEmpty(collection.Key) ? root : root.Find(collection.Key);
                    if(node)
                    {
                        var comps = node.GetComponents<T>();
                        if(comps != null)
                        {
                            var list = collection.Value;
                            for(int i = 0, imax = Mathf.Min(comps.Length, list.Count); i < imax; i++)
                            {
                                access.Invoke(comps[i], list[i]);
                            }
                        }
                    }
                }
            }
    
            private static string GetRelativePath<T>(Transform root, T comp) where T : UnityEngine.Component
            {
                if(comp.transform == root)
                {
                    return "";
                }
                _sb.Length = 0;
                string path = comp.name;
                _sb.Append(comp.name);
                var parent = comp.transform.parent;
                while(parent && parent != root)
                {
                    _sb.Insert(0, "/");
                    _sb.Insert(0, parent.name);
                    parent = parent.parent;
                }
                return _sb.ToString();
            }
            #endregion
    
        }
    }

      这里的核心数据使用了 Dictionary<string, List<TVal>> 这样的结构, Key 是UI层级路径, List<TVal> 是数据序列化, 使用了列表就说明路径是可以相同的, 比如同一个节点下的UI对象都叫TEXT, 没有问题. 直接调 SerializeUIToJson 就行了, 反序列化直接 ApplySerializedDataToUI 就行了.

      没什么扩展性, 应该把功能写在 SerializeData 基类里的, 这样就可以扩展了...

      

  • 相关阅读:
    js中验证身份证号码是否正确支持15位和18位身份证号
    vue-element-admin-i18n 前端框架的使用
    根据年份选择周数-js
    js 计算开始日期和结束日期跨度几个月份的方法
    Java上传图片到服务器
    c# List<Object>和List<实体>相互转化
    GC 相关详细参数
    Groovy脚本和Groovy类反编译文件
    dev 控件中点击TreeList节点高亮显示GridControl中存在的行
    spring容器
  • 原文地址:https://www.cnblogs.com/tiancaiwrk/p/15234099.html
Copyright © 2011-2022 走看看