Unity:如何在运行时更改UI元素布局(即更改RectTransform)?

时间:2019-05-02 09:01:08

标签: c# user-interface unity3d

我正在使用Unity构建应在电话和平板电脑上运行的应用程序。根据应用程序是在电话上还是在平板电脑上运行,UI的布局应有所不同(即某些UI元素的RectTransform应该具有不同的值)。最后,我将提出一种逻辑来检测应用程序的启动情况,然后触发相应保存的布局配置的应用程序。我想避免构建两个不同版本的应用程序。

到目前为止,我的想法是

  • LayoutController全局控制不同布局的保存和加载:
    using UnityEngine;

    public class LayoutController : MonoBehaviour
    {
        public static LayoutController instance;
        public LayoutConfigurationDatabase layoutConfigurationDatabase;
        public string  currentLayoutName = "Default";

        private void Awake()
        {
            instance = this;
        }

        public void Load(string layoutName)
        {
            var objects = FindObjectsOfType<LayoutHelper>();
            foreach(var o in objects)
            {
                o.currentLayoutName = layoutName;
                layoutConfigurationDatabase.Get((RectTransform)o.transform, currentLayoutName);
            }
        }

        public void SaveAll()
        {
            var objects = FindObjectsOfType<LayoutHelper>();
            foreach (var o in objects)
            {
                layoutConfigurationDatabase.Put((RectTransform) o.transform, currentLayoutName);
            }

        }
    }
  • LayoutConfigurationData可编写脚本的对象为所有相关元素保存LayoutConfiguration
    [Serializable]
    public class LayoutConfiguration
    {
        public string layoutName;
        public RectTransform transform;
        public Dictionary<string, object> data = new Dictionary<string, object>();
    }

    [CreateAssetMenu(fileName = "LayoutConfigurationDatabase", menuName = "Data/LayoutConfigurationDatabase")]
    public class LayoutConfigurationDatabase : ScriptableObject
    {
        public List<LayoutConfiguration> data = new List<LayoutConfiguration>();

        public bool Put(RectTransform from, string layoutName)
        {
            var item = data.Find(i => i.transform == from && i.layoutName == layoutName);
            if(item != null)
            {
                data.Remove(item);
            }

            LayoutConfiguration configuration = new LayoutConfiguration() { transform = from, layoutName = layoutName };
            var type = from.GetType();
            PropertyInfo[] fields = from.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var field in fields)
            {
                try
                {
                    var value = field.GetValue(from, null);
                    configuration.data[field.Name] = value;
                }
                catch(Exception){ }
            }

            data.Add(configuration);
            return true;
        }

        public bool Get(RectTransform to, string layoutName)
        {
            var configuration = data.Find(i => i.transform == to && i.layoutName == layoutName);
            if(configuration == null)
            {
                Debug.Log("Cannot find configuration");
                return false;
            }
            PropertyInfo[] fields = to.GetType().GetProperties(BindingFlags.Public | BindingFlags.Instance);
            foreach (var field in fields)
            {
                if (configuration.data.ContainsKey(field.Name) && field.CanWrite && field.Name.ToLower() != "parent")
                    field.SetValue(to, configuration.data[field.Name], null);
            }
            return true;
        }
    }
  • 每个必须具有不同行为的元素都将获得组件LayoutHelper
    using UnityEngine;

    public class LayoutHelper : MonoBehaviour
    {
        public string currentLayoutName;
        [HideInInspector]
        public string status = "";

        public void Save()
        {
            LayoutController.instance.layoutConfigurationDatabase.Put((RectTransform)transform, currentLayoutName);
            status = string.Format("Saved layout name {0}", currentLayoutName);
        }

        public void Load()
        {
            if (!LayoutController.instance.layoutConfigurationDatabase.Get((RectTransform) transform, currentLayoutName))
            {
                status = string.Format("Cannot load orientation {0}!", currentLayoutName);
            }
        }

        public void Set(string layoutName)
        {
            this.currentLayoutName = layoutName;
            Load();
        }
    }

问题
只要我不更改场景,此方法就起作用。更改场景后,对RectTransform中UI元素的LayoutConfiguration的引用始终为 Missing

问题
我的想法在概念上可行吗?
我该如何工作?

0 个答案:

没有答案