#if UNITY_EDITOR using System.IO; using System.Text; using UnityEditor; using UnityEngine; namespace U3DExtends { [RequireComponent(typeof(Canvas))] [ExecuteInEditMode] public class LayoutInfo : MonoBehaviour { //[HideInInspector] [SerializeField] private string _layoutPath = string.Empty; public static bool IsShowLayoutName = false; Vector3 _lastRealLayoutPos = new Vector3(-1, -1); Vector2 _lastRealLayoutSize = Vector2.zero; UnityEngine.UI.Text _viewNameLabel = null; const string RealPosStartStr = "RealLayoutPosStart "; const string RealPosEndStr = " RealLayoutPosEnd\n"; static string configPath = string.Empty; static string ConfigPath { get { if (configPath == string.Empty) configPath = Application.temporaryCachePath + "/Decorates"; return configPath; } } public string LayoutPath { get { return _layoutPath; } set { _layoutPath = value; } } public GameObject EditingView { get { for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); if (child.GetComponent() != null || (_viewNameLabel!=null && _viewNameLabel.transform==child)) continue; return child.gameObject; } return null; } } private void Start() { Transform name_trans = transform.Find("ViewName"); if (name_trans!=null) _viewNameLabel = name_trans.GetComponent(); } //本来坐标或大小变更时也需要再保存一下,但是需要监听pos size等变更又要io保存,怕太多参照图时影响性能,所以还是界面保存时再一起保存吧 public bool SaveToConfigFile() { string select_path = FileUtil.GetProjectRelativePath(LayoutPath); string layout_path_md5 = UIEditorHelper.GenMD5String(select_path); RectTransform real_layout = UIEditorHelper.GetRealLayout(gameObject) as RectTransform;//先拿到真实的界面prefab if (select_path == "" || real_layout == null) { //界面还未保存,等保存时再调用本函数 return false; } RectTransform curTrans = transform as RectTransform; bool hadDecorateTransChanged = false; bool hadTransChanged = true; if (real_layout.localPosition == _lastRealLayoutPos && real_layout.sizeDelta == _lastRealLayoutSize) hadTransChanged = false; _lastRealLayoutPos = real_layout.localPosition; _lastRealLayoutSize = real_layout.sizeDelta; if (!Directory.Exists(ConfigPath)) Directory.CreateDirectory(ConfigPath); string savePath = ConfigPath + "/" + layout_path_md5 + ".txt"; StringBuilder content = new StringBuilder(); content.Append(RealPosStartStr); content.Append(real_layout.localPosition.x.ToString()); content.Append(' '); content.Append(real_layout.localPosition.y.ToString()); content.Append(RealPosEndStr); Decorate[] decorates = transform.GetComponentsInChildren(); for (int i = 0; i < decorates.Length; i++) { RectTransform rectTrans = decorates[i].GetComponent(); if (rectTrans != null) { content.Append(decorates[i].SprPath); content.Append('#'); content.Append(rectTrans.localPosition.x.ToString()); content.Append(' '); content.Append(rectTrans.localPosition.y.ToString()); content.Append('#'); content.Append(rectTrans.sizeDelta.x.ToString()); content.Append(' '); content.Append(rectTrans.sizeDelta.y.ToString()); content.Append('*');//分隔不同的参照图 if (decorates[i].IsChangedTrans()) { decorates[i].SaveTrans(); hadDecorateTransChanged = true; } } } if (hadTransChanged || hadDecorateTransChanged) { if (content[content.Length - 1] == '*') content.Remove(content.Length - 1, 1);//删掉最后一个分隔符 File.WriteAllText(savePath, content.ToString()); return true; } //当真实界面的坐标和参照图的变换没变的话就不需要保存了 return false; } public Decorate GetDecorateChild(string picPath) { for (int i = 0; i < transform.childCount; i++) { Transform child = transform.GetChild(i); Decorate decor = child.GetComponent(); if (decor != null && decor.SprPath == picPath) { return decor; } } return null; } //打开界面时,从项目临时文件夹找到对应界面的参照图配置,然后生成参照图 public void ApplyConfig(string view_path) { string layout_path_md5 = UIEditorHelper.GenMD5String(view_path); string confighFilePath = ConfigPath + "/" + layout_path_md5 + ".txt"; if (!File.Exists(confighFilePath)) return; string content = File.ReadAllText(confighFilePath); int pos_end_index = content.IndexOf(RealPosEndStr); if (pos_end_index == -1) { Debug.Log("cannot find real layout pos config on ApplyConfig : " + view_path); return; } string real_layout_pos_str = content.Substring(RealPosStartStr.Length, pos_end_index - RealPosStartStr.Length); string[] pos_cfg = real_layout_pos_str.Split(' '); if (pos_cfg.Length == 2) { RectTransform real_layout = UIEditorHelper.GetRealLayout(gameObject) as RectTransform;//先拿到真实的界面prefab if (real_layout == null) { Debug.Log("cannot find real layout on ApplyConfig : " + view_path); return; } real_layout.localPosition = new Vector3(float.Parse(pos_cfg[0]), float.Parse(pos_cfg[1]), real_layout.localPosition.z); } else { Debug.Log("cannot find real layout pos xy config on ApplyConfig : " + view_path); return; } content = content.Substring(pos_end_index + RealPosEndStr.Length); if (content == "") return;//有些界面没参考图也是正常的,直接返回 string[] decorate_cfgs = content.Split('*'); for (int i = 0; i < decorate_cfgs.Length; i++) { string[] cfgs = decorate_cfgs[i].Split('#'); if (cfgs.Length == 3) { string decorate_img_path = cfgs[0]; if (!File.Exists(decorate_img_path)) { Debug.Log("LayoutInfo:ApplyConfig() cannot find decorate img file : " + decorate_img_path); continue; } Decorate decor = GetDecorateChild(decorate_img_path); if (decor == null) decor = UIEditorHelper.CreateEmptyDecorate(transform); decor.SprPath = decorate_img_path; RectTransform rectTrans = decor.GetComponent(); if (rectTrans != null) { //IFormatter formatter = new BinaryFormatter();//使用序列化工具的话就可以保存多点信息,但实现复杂了,暂用简单的吧 string[] pos = cfgs[1].Split(' '); if (pos.Length == 2) rectTrans.localPosition = new Vector2(float.Parse(pos[0]), float.Parse(pos[1])); string[] size = cfgs[2].Split(' '); if (size.Length == 2) rectTrans.sizeDelta = new Vector2(float.Parse(size[0]), float.Parse(size[1])); } } else { Debug.Log("warning : detect a wrong decorate config file!"); return; } } } private void OnDrawGizmos() { if (_viewNameLabel==null) return; // bool is_show_name = Event.current!=null && (Event.current.control) && !Event.current.alt && !Event.current.shift; if (IsShowLayoutName) { string show_name = transform.name.Substring(0, transform.name.Length-("_Canvas").Length); _viewNameLabel.text = show_name; _viewNameLabel.transform.SetAsLastSibling(); _viewNameLabel.gameObject.SetActive(true); } else { _viewNameLabel.gameObject.SetActive(false); } } } } #endif