1 В избранное 0 Ответвления 0

OSCHINA-MIRROR/feifeid-unity-async-uiframe

Присоединиться к Gitlife
Откройте для себя и примите участие в публичных проектах с открытым исходным кодом с участием более 10 миллионов разработчиков. Приватные репозитории также полностью бесплатны :)
Присоединиться бесплатно
Клонировать/Скачать
Внести вклад в разработку кода
Синхронизировать код
Отмена
Подсказка: Поскольку Git не поддерживает пустые директории, создание директории приведёт к созданию пустого файла .keep.
Loading...
README.md

Основные характеристики

(1) Простой и удобный асинхронный фреймворк для UI
(2) Совместимость с различными системами управления ресурсами (Addressable, YooAssets и т.д.)
(3) Поддержка автоматического ссылочного механизма, при этом поля, отображаемые на панели Inspector, автоматически ссылаются на панель Hierarchy
(4) Поддержка вложенных UI (под-UI, под-под-UI и т.д.)
(5) Поддержка пользовательских шаблонов скриптов
(6) Поддержка управления уничтожением UI-панелей для более удобной оптимизации памяти
(7) Высокая расширяемость, позволяющая автоматически привязывать события с помощью пользовательских событий, например, автоматическая привязка события нажатия кнопки

Установка

Способ 1

Использование git URL

https://github.com/feifeid47/Unity-Async-UIFrame.git

Способ 2

Импорт unitypackage

Как использовать

Создайте预制体UIFrame, используя следующую структуру
Режим рендеринга Canvas должен быть установлен на Screen Space - Camera
RectTransform для PanelLayer и WindowLayer должны быть настроены на полный экран (левая, правая, верхняя и нижняя границы должны быть равны 0)

--UIFrame         (RectTransform, Canvas, CanvasScaler, GraphicRaycaster, UIFrame)  
------UICamera    (Transform, Camera, AudioListener)
------PanelLayer  (RectTransform)
------WindowLayer (RectTransform)
------EventSystem (Transform, EventSystem, StandaloneInputModule)

Создайте预制体UIFrame, используя следующую структуру
Режим рендеринга Canvas должен быть установлен на Screen Space - Camera
RectTransform для PanelLayer и WindowLayer должны быть настроены на полный экран (левая, правая, верхняя и нижняя границы должны быть равны 0)

--UIFrame         (RectTransform, Canvas, CanvasScaler, GraphicRaycaster, UIFrame)  
------UICamera    (Transform, Camera, AudioListener)
------PanelLayer  (RectTransform)
------WindowLayer (RectTransform)
------EventSystem (Transform, EventSystem, StandaloneInputModule)
```Инициализация
```C#
private void Awake()
{
    // Регистрация события освобождения ресурсов
    UIFrame.OnAssetRequest += OnAssetRequest;
    UIFrame.OnAssetRelease += OnAssetRelease;
    // Регистрация события "заклинившего" UI
    // Событие "заклинившего" UI срабатывает, если время загрузки превышает 0.5 секунды
    UIFrame.StuckTime = 0.5f;
    UIFrame.OnStuckStart += OnStuckStart;
    UIFrame.OnStuckEnd += OnStuckEnd;
}
``````csharp
// Событие запроса ресурсов, type - тип скрипта UI
// Можно использовать Addressables, YooAssets и другие системы управления ресурсами
private async Task<GameObject> OnAssetRequest(Type type)
{
    if (!handles.ContainsKey(type))
    {
        var handle = Addressables.LoadAssetAsync<GameObject>(type.Name);
        await handle.Task;
        handles[type] = handle;
    }
    return handles[type].Result;
}

// Событие освобождения ресурсов
private void OnAssetRelease(Type type)
{
    if(handles.ContainsKey(type))
    {
        handles[type].Release();
        handles.Remove(type);
    }
}

private void OnStuckStart()
{
    // Если время инициализации UI слишком велико, UI "заклинивается", открываем панель с крутящимся значком
}

private void OnStuckEnd()
{
    // Если UI больше не "заклинивается", закрываем панель с крутящимся значком
}

Создайте скрипт UI, унаследованный от UIComponent и прикрепите его к预制体,具有与脚本相同的名称。

public class UITestData : UIData
{

}

[UIPanel]
public class UITest : UIComponent<UITestData>
{
    [SerializeField] private Image img;
    [SerializeField] private Text content;
    [SerializeField] private Button close;

    // Вызывается при создании, выполняется один раз в течение всего жизненного цикла
    protected override async Task OnCreate()
    {
        // Асинхронный запрос ресурсов
        var completionSource = new TaskCompletionSource<Sprite>();
        var handle = Resources.LoadAsync<Sprite>("sprite");
        handle.completed += _ =>
        {
            completionSource.SetResult(handle.asset as Sprite);
        };
        img.sprite = await completionSource.Task;
    }

    // Привязка событий
    protected override void OnBind()
    {
        close.onClick.AddListener(OnClose);
    }

    // Отвязка событий
    protected override void OnUnbind()
    {
        close.onClick.RemoveListener(OnClose);
    }
}
```    // Обновление
    protected override async Task OnRefresh()
    {
        // Асинхронный запрос данных из сети
        var completionSource = new TaskCompletionSource<string>();
        using var request = UnityWebRequest.Get("http://xxxx");
        request.SendWebRequest().completed += _ =>
        {
            completionSource.SetResult(request.downloadHandler.text);
        };
        var data = await completionSource.Task;
        content.text = data;
    }

    // Вызывается при отображении
    protected override void OnShow()
    {

    }

    // Вызывается при скрытии
    protected override void OnHide()
    {

    }

    // Вызывается при удалении, выполняется один раз в течение всего жизненного цикла
    protected override void OnDied()
    {

    }    private void OnClose()
    {
        // Закрытие текущей панели
        UIFrame.Hide(this);
    }
}

Используйте атрибуты [UIPanel] или [UIWindow] для маркировки UI
Атрибут [UIPanel] обычно используется для обозначения полноразмерных панелей, которые управляются стеком. Отображение следующей панели приводит к закрытию текущей панели, а скрытие текущей панели приводит к отображению предыдущей панели
Атрибут [UIWindow] обычно используется для обозначения всплывающих окон, которые отображаются поверх панелей
Одно UI-окно не может одновременно быть панелью и окном```C# // Отображение UI UIFrame.Show(new TestUIData()); // Отображение под-UI UIFrame.Show(UIBase uibase); // Скрытие UI UIFrame.Hide(); // Скрытие под-UI UIFrame.Hide(UIBase uibase); // Обновление UI UIFrame.Refresh(); // Обновление под-UI UIFrame.Refresh(UIBase uibase); // Освобождение ресурсов UIFrame.Release(); // Инстанцирование ресурсов UI UIFrame.Instantiate(gameObject, parent); // Уничт Yöndürme UI kaynakları UIFrame.Destroy(gameObject); // Немедленное уничтожение ресурсов UI UIFrame.DestroyImmediate(gameObject);

# Лифт-цикл UIBaseВот последовательность выполнения при вызове UIFrame.Show для отображения следующего Panel

![](./README/lifecycle.png)Взять `UITest` в качестве примера, `TestUI` наследуется от `UIComponent<T>`. При отображении `UITest` будут последовательно выполнены следующие шаги:
```
(1) UITest.OnCreate
(2) OnCreate всех компонентов, наследующихся от UIBase, в UITest
(3) UITest.OnRefresh
(4) OnRefresh всех активных объектов, наследующихся от UIBase, в UITest
(5) UITest.OnBind
(6) OnBind всех активных объектов, наследующихся от UIBase, в UITest
(7) UITest.OnShow
(8) OnShow всех активных объектов, наследующихся от UIBase, в UITest
```
При скрытии `TestUI` будут последовательно выполнены следующие шаги:
```
(1) OnUnbind всех активных объектов, наследующихся от UIBase, в UITest
(2) UITest.OnUnbind
(3) OnHide всех активных объектов, наследующихся от UIBase, в UITest
(4) UITest.OnHide
(5) OnDied всех компонентов, наследующихся от UIBase, в UITest
(6) UITest.OnDied
```
Метод `OnCreate` и жизненный цикл `OnDied` выполняются только один раз.
Только после выполнения `OnCreate` и `OnRefresh` объект становится активным, то есть метод `Awake` класса `MonoBehaviour` выполняется после `OnCreate` и `OnRefresh`.
Не рекомендуется использовать методы жизненного цикла `MonoBehaviour`.
Важно отметить, что привязка и отвязка событий UI должны быть выполнены в `OnBind` и `OnUnbind` соответственно, чтобы избежать множественного отклика в процессе асинхронной работы, что может привести к непредсказуемым ошибкам. В процессе асинхронной работы UI временно прекращает отклики. Если время отклика превышает `UIFrame.StuckTime`, будет сработано событие зависания.# Автоматическая ссылка
Сначала создайте `UIFrameSetting`, правый клик мыши -> Создать -> UIFrame -> UIFrameSetting
Вы можете переместить файл `UIFrameSetting` в другое место, не обязательно в директории Assets.
Включите `Auto Reference` в `UIFrameSetting`
Если вы хотите отключить автоматическую ссылку, просто выключите `Auto Reference` в `UIFrameSetting`
Пример:
```C#
[SerializeField] private UIRed uiRed;
[SerializeField] private UIBlue uiBlue;
[SerializeField] private Button btnRed;
[SerializeField] private Button btnBlue;
[SerializeField] private Button btnBack;
[SerializeField] private List<Image> listImg;
```
Необходимо изменить имя объекта в Hierarchy на имя поля (не учитывая регистр букв) и добавить к нему префикс @.
После изменения имени дополнительные действия не требуются, при сохранении Prefab значения из Hierarchy будут автоматически присвоены полям в Inspector.
Для полей типа List достаточно, чтобы имя родительского объекта совпадало с именем поля.
При включении автоматической ссылки, поля, которые участвуют в ссылке, будут заблокированы, и вы не сможете удалить их или изменить их значения.
```![](./README/autoref1.png)```# ПодUI
Иногда на одной панели может быть несколько подпанелей и некоторые элементы UI, и вы хотите, чтобы при отображении одного UI, подпанели и элементы UI были инициализированы и обновлены одновременно.  
Например, `UITest` имеет два подUI: `UIRed` и `UIBlue`. Оба `UIRed` и `UIBlue` имеют компонент Text, который отображает Data = xxx.  
При отображении `UITest` вы хотите инициализировать и обновлять `UIRed` и `UIBlue`, обновлять значение Data = xxx и иметь возможность открывать подUI через две кнопки на `UITest`, а также иметь кнопку закрытия на каждом подUI, чтобы закрыть его.  
![](./README/testui2.png)  
Структура панели `UITest` следующая:  
`UITest` содержит скрипт `UITest`, ссылается на @UIRed, @UIBlue, @BtnRed, @BtnBlue.  
`@UIRed` содержит скрипт `UIRed`, ссылается на @DataTxt, @BtnClose.  
`@UIBlue` содержит скрипт `UIBlue`, ссылается на @DataTxt, @BtnClose.  
В соответствии с жизненным циклом UIBase, при отображении `UITest`, все компоненты, наследующие от UIBase, будут выполнены одновременно, и выполнение будет происходить в определенном порядке, сначала выполняются методы родительского объекта, а затем методы дочерних объектов.```C#
[UIPanel]
public class UITest : UIBase
{
    [SerializeField] private UIRed uiRed;
    [SerializeField] private UIBlue uiBlue;
    [SerializeField] private Button btnRed;
    [SerializeField] private Button btnBlue;
    [SerializeField] private Button btnBack;

    protected override void OnBind()
    {
        btnRed.onClick.AddListener(OnBtnRed);
        btnBlue.onClick.AddListener(OnBtnBlue);
        btnBack.onClick.AddListener(OnBack);
    }

    protected override void OnUnbind()
    {
        btnRed.onClick.RemoveListener(OnBtnRed);
        btnBlue.onClick.RemoveListener(OnBtnBlue);
        btnBack.onClick.RemoveListener(OnBack);
    }

    private void OnBtnRed()
    {
        // Это правильный шаг для отображения подUI, неправильный шаг: UIFrame.Show<UIRed>(data);
        var data = new UIRedData() { Content = "Это UIRed" };
        UIFrame.Show(uiRed, data);
    }

    private void OnBtnBlue()
    {
        var data = new UIBlueData() { Content = "Это UIBlue" };
        UIFrame.Show(uiBlue, data);
    }

    private void OnBack()
    {
        UIFrame.Hide(this);
    }
}
```
```C#
public class UIRedData : UIData
{
    public string Content;
}

public class UIRed : UIComponent<UIRedData>
{
    [SerializeField] private Text dataTxt;
    [SerializeField] private Button btnClose;

    protected override Task OnRefresh()
    {
        dataTxt.text = $"Данные = {Data.Content}";
        return Task.CompletedTask;
    }

    protected override void OnBind()
    {
        btnClose.onClick.AddListener(OnBtnClose);
    }

    protected override void OnUnbind()
    {
        btnClose.onClick.RemoveListener(OnBtnClose);
    }

    protected void OnBtnClose()
    {
        UIFrame.Hide(this);
    }
}
```# Пользовательский шаблон скрипта
Сначала создайте `UIFrameSetting`, правый клик -> Создать -> UIFrame -> UIFrameSetting  
Вы можете переместить `UIFrameSetting` в любое место, а не только в директорию Assets  
По умолчанию шаблон скрипта находится в директории UIFrame/Editor/Resources, который можно изменить по необходимости  
Перетащите файл шаблона (.txt) в `UIFrameSetting`  
Имя файла заменит `#SCRIPTNAME#` в шаблоне файла  
![](./README/menu.png)    
![](./README/template.png)# Управление разрушением UI
![](./README/testui.png)  
Скрипты, наследующие от `UIComponent<T>`, будут иметь в Inspector панели свойство `Auto Destroy`  
При активации `Auto Destroy`, объект будет уничтожен и освобождены используемые им ресурсы при невидимости UI  
Эту переменную можно управлять в коде во время выполнения  

```
Внимание: при активации Auto Destroy, при закрытии и повторном открытии панели будет вызван метод OnCreate  
Рекомендация: для часто используемых UI отключите этот параметр для ускорения открытия UI. Для редко используемых UI или UI, использующих много памяти, активируйте этот параметр для оптимизации памяти  
```

# Динамическое создание или разрушение UI gameObject

Если вы хотите динамически создавать UI gameObject во время выполнения, используйте следующие методы

```C#
UIFrame.Instantiate(gameObject, parent);
UIFrame.Destroy(gameObject);
UIFrame.DestroyImmediate(gameObject);
```

Использование `UIFrame.Instantiate` и `UIFrame.Destroy` для создания или разрушения объектов автоматически заполняет дерево отношений `UIBase`.  
Это гарантирует, что динамически созданные или разрушенные объекты будут правильно контролироваться `UIFrame`.  
```    public static void Отключить()
    {
        UIFrame.OnCreate -= OnCreate;
        UIFrame.OnBind -= OnBind;
        UIFrame.OnUnbind -= OnUnbind;
        UIFrame.OnDied -= OnDied;
    }```    private static void OnCreate(UIBase uibase)
    {
        var methods = uibase.GetType()
            .GetMethods(BindingFlags.Instance | BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static)
            .Where(item => Attribute.IsDefined(item, typeof(UGUIButtonEventAttribute)));
        binds[uibase] = new Dictionary<string, (Button, UnityAction)>();
        var bind = binds[uibase];
        var buttons = new Dictionary<string, Button>();
    }```markdown
    [UGUIButtonEvent]
    protected void OnBtnRed()
    {
        var data = new UIRedData() { Content = "Это UIRed" };
        UIFrame.Show(uiRed, data);
    }

    [UGUIButtonEvent]
    protected void OnBtnBlue()
    {
        var data = new UIBlueData() { Content = "Это UIBlue" };
        UIFrame.Show(uiBlue, data);
    }
```

Таким образом, не требуется вручную добавлять события в методы `OnBind` и `OnUnbind` для `UIBase`.  

Можно напрямую указать методы с атрибутами, и они будут автоматически привязываться и отвязываться, как показано ниже: предварительно загруженный объект `UITest` имеет дочерние объекты `@BtnRed`, `@BtnBlue`, `@BtnBack`.

```C#
[UIPanel]
public class UITest : UIBase
{
    [SerializeField] private UIRed uiRed;
    [SerializeField] private UIBlue uiBlue;
}
```

```C#
[UGUIButtonEvent]
protected void OnBtnRed()
{
    var data = new UIRedData() { Content = "Это UIRed" };
    UIFrame.Show(uiRed, data);
}

[UGUIButtonEvent]
protected void OnBtnBlue()
{
    var data = new UIBlueData() { Content = "Это UIBlue" };
    UIFrame.Show(uiBlue, data);
}
```    [UGUIButtonEvent]
    protected void OnBtnBack()
    {
        UIFrame.Hide(this);
    }
}
```

Другие события можно расширить, зарегистрировав `UIFrame.OnCreate`, `UIFrame.OnRefresh`, `UIFrame.OnBind`, `UIFrame.OnUnbind`, `UIFrame.OnShow`, `UIFrame.OnHide`, `UIFrame.OnDied`.

Комментарии ( 0 )

Вы можете оставить комментарий после Вход в систему

Введение

Простой и удобный асинхронный фреймворк для UI в Unity. Достаточно легковесен, без зависимостей от третьих сторон. Совместим с различными системами управления ресурсами (Addressable, YooAssets и др.). Поддерживает горячую перезагрузку с использованием HybridCLR. Поддерживает автоматическое управление зависимостями. Поддерживает контроль за уничт... Развернуть Свернуть
C#
Apache-2.0
Отмена

Обновления

Пока нет обновлений

Участники

все

Недавние действия

Загрузить больше
Больше нет результатов для загрузки
1
https://api.gitlife.ru/oschina-mirror/feifeid-unity-async-uiframe.git
git@api.gitlife.ru:oschina-mirror/feifeid-unity-async-uiframe.git
oschina-mirror
feifeid-unity-async-uiframe
feifeid-unity-async-uiframe
master