Unity: Как изменить расположение элементов пользовательского интерфейса во время выполнения (т.е. изменить RectTransform)? - PullRequest
2 голосов
/ 02 мая 2019

Я создаю приложение с использованием Unity, которое должно работать на телефоне и планшете. Пользовательский интерфейс должен быть размещен по-разному (т. Е. RectTransform некоторых элементов пользовательского интерфейса должны иметь разные значения) в зависимости от того, работает ли приложение на телефоне или планшете. В конце я добавлю логику, чтобы определить при запуске приложения, в каком случае это происходит, и, следовательно, запустить приложение соответствующих сохраненных конфигураций макета. Я хочу избежать создания двух разных версий приложения.

Моя идея пока что :

  • A 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 s для всех соответствующих элементов:
    [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 элемента пользовательского интерфейса в LayoutConfiguration s всегда равна Missing .

Вопросы :
Возможна ли моя идея концептуально?
Как я могу сделать эту работу?

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...