Передовые методы управления элементами
На этой странице описаны рекомендации по управлению элементами в визуальном дереве.
Периодические элементы пулов
Пулирование элементов предназначено для того, чтобы сохранить элементы, которые вы можете воссоздать позже, вместо того, чтобы каждый раз создавать элементы с new() и отпускать их.
Реализуя собственный пул объектов для VisualElement, полностью контролируйте все элементы пула и сбрасывайте их перед возвратом. Для таких систем, как события, UI Toolkit использует внутренние пулы (EventBase) для повышения производительности, но он не включает встроенный пул для VisualElements. Если вы создаете свой собственный пул, вы должны обрабатывать очистку. Например, если вы зарегистрируете обратный вызов события на элементе и вернете его в свой пул без отмены регистрации, обратный вызов останется. Это может привести к нестабильности, неожиданному поведению и утечке памяти при повторном использовании элемента.
Небольшое количество видимых элементов
Чтобы уменьшить количество визуальных элементов, используйте ListView, когда это возможно. ListView объединяет элементы и повторно использует элементы по мере прокрутки пользователя.
В качестве альтернативы, вы можете реализовать свой собственный пул и механизм переработки, подобный ListView, и использовать следующее для управления видимой областью:
- Для наблюдения за размером контейнера используйте
GeometryChangedEvent - Для вычисления размера дочерей используйте свойство
VisualElement.layout
Различные подходы к скрытию элемента
Когда вы используете VisualElement.RemoveFromHierarchy() для удаления элемента из иерархии и устранения ссылок на него, элемент является мусором. Это снижает стоимость CPU и GPU до нуля и высвобождает значительное количество памяти. Однако, это медленная и дорогостоящая операция для повторного создания элементов и перезагрузки их в иерархии. Чтобы избежать этого, вы можете предварительно создать элементы в иерархии, использовать свойства Стиль USS для их скрытия и отображать их только при необходимости. Хотя применение стилей обычно происходит быстрее, это может привести к увеличению использования памяти, если вы создаете большое количество элементов одновременно.
Ниже описаны различные подходы к скрытию элементов и последствия для процессоров и использования памяти. См. следующую таблицу для краткого описания различных подходов:
Скрыть с USS стиля visibility: hidden;
При таком подходе потомки могут переопределить visibility стиль.
Расходы на одну рамку
В следующей таблице описаны различные аспекты стоимости одного кадра при скрытии или отображении визуального элемента со стилем visibility:
| Аспект | visibility: hidden; |
visibility: visible; |
|---|---|---|
| Стилы | Оценка элемента и потомков для распространения видимости. | Оценка для него и потомков, для распространения видимости. |
| Данные макета | Сохранено | Нет |
| Команды отображения | Убраны и перераспределены | Воссоздан и включен в цепочку командования. |
| Меши | Запланировано для перераспределения. | Ре-тесселято |
Поведение по кадрам
В следующей таблице описывается поведение CPU и GPU на кадр при скрытии визуального элемента с помощью стиля visibility:
| Процессор | Аспект | Поведение по кадрам |
|---|---|---|
| CPU | Стилы | Полная оценка элемента и его потомков. |
| Данные макета | Обновленные данные | |
| Тесселяция | Минимальное воздействие, которое включает только маскировочные меши шаблона, если это применимо. | |
| Команды отображения | Нет команд для рисования обычной видимой геометрии. Тем не менее, меши маскировки шаблона по-прежнему отображаются, чтобы выдвигаться или выпадать из шаблона, обеспечивая маскировку потенциальных видимых потомков. | |
| GPU | Меши | Затенение вершин и фрагментов на мешах маскировки шаблона. |
Скрыть с USS стиля opacity: 0;
При таком подходе можно ожидать некоторого воздействия GPU, так как вершинный шейдер обрабатывает все элементы.
Расходы на одну рамку
В следующей таблице описана стоимость одного кадра при скрытии или отображении визуального элемента со стилем opacity:
| Действия | Расходы на одну рамку |
|---|---|
opacity: 0; |
В первый раз, когда вы устанавливаете для opacity значение, отличное от 1, рендер UI Toolkit модифицирует вершины, чтобы ускорить применение непрозрачности на GPU.. Это вызывает единовременную, минимальную стоимость CPU. Хотя обычно эта стоимость незначительна, она может стать заметной, если элемент имеет большое количество потомков или если требуется модифицировать много вершин. Эта стоимость не возникает снова, если элемент не удален из визуального дерева и не добавлен снова. |
opacity: 1; |
Нет |
Поведение по кадрам
В следующей таблице описывается поведение CPU и GPU на кадр при скрытии визуального элемента с помощью стиля opacity:
| Процессор | Аспект | Поведение по кадрам |
|---|---|---|
| CPU | Стилы | Полная оценка элемента и его потомков. |
| Тесселяция | Работает нормально и реагирует на изменения. | |
| Команды отображения | Приведено в исполнение | |
| GPU | Меши | Вершинный шейдер работает так, как будто visibility установлен на 1, что может быть неблагоприятно в проектах, связанных с GPU, если есть много вершин для обработки. Треугольники перемещаются вне экрана, так что нет затрат на фрагментный шейдер. |
Скрыть с USS стиля display: none;
При таком подходе элемент ведет себя так, как будто он удалён из дерева макета, что потенциально может повлиять на макет других элементов.
Расходы на одну рамку
В следующей таблице описаны различные аспекты стоимости одного кадра при скрытии или отображении визуального элемента со стилем display:
| Аспект | display: none; |
display: flex; |
|---|---|---|
| Данные макета | Может перерассчитать макет других элементов. | Ожидаемые изменения макета обрабатываются. |
| Команды отображения/Сетки | Регенерированы для элементов, затронутых изменением макета. |
|
Поведение по кадрам
В следующей таблице описывается поведение CPU на кадр, когда вы скрываете визуальный элемент стилем display. Обратите внимание, что стоимость GPU отсутствует.
| Аспект | Поведение по кадрам |
|---|---|
| Данные макета | Сохраняется, но может стать недействительным и не обновляться. |
| Команды отображения | Хотя они и сохраняются, их можно пропустить во время выполнения. Способ их пропуска очень дешев, но не полностью бесплатный. Стоимость пропорциональна количеству команд. |
| Меши | Сохраняется, но может стать недействительным и не обновляться. |
Перевод вне окна просмотра
Вы можете использовать translate: -5000px -5000px; в сочетании с подсказками DynamicTransform для перемещения элементов из Viewport. Геометрия остается полностью активной, что приводит к минимальному использованию CPU при возвращении элемента на экран. Однако GPU продолжает обработку вершин, что может быть приемлемым в зависимости от сценария.
Расходы на одну рамку
Преобразование вычисляется и загружается в память GPU, которая обычно работает быстро.
Поведение по кадрам
В следующей таблице описывается поведение CPU и GPU на уровне кадра при скрытии визуального элемента путем перевода его за пределы окна просмотра:
| Процессор | Аспект | Поведение по кадрам |
|---|---|---|
| CPU | Стилы | Обновленные данные |
| Дата оформления | Обновленные данные | |
| Вызовы на выигрыш | Приведено в исполнение | |
| GPU | Меши | Вершины затенены. |
Удалить из иерархии
Когда вы используете метод VisualElement.RemoveFromHierarchy() для удаления элемента из иерархии, вы высвобождаете память CPU и GPU, тем самым устраняя любые расходы на вычисления.
Расходы на одну рамку
В следующей таблице описана стоимость одного кадра при скрытии или отображении визуального элемента путем его удаления из иерархии:
| Аспект | Удалить | Добавить |
|---|---|---|
| Стилы | Нет | Обновлено для поддеревья. |
| Компоновка | Нет | Пересчитано для поддеревья и, возможно, других элементов. |
| Команды рендеринга/сетки | Регенерированы для элементов, затронутых изменением макета. |
|
Использование памяти после скрытия
В следующей таблице показано использование памяти после скрытия элемента при различных подходах:
| Процессор | Аспект | visibility:hidden; |
opacity:0; |
display:None; |
Переведено из Viewport | Убраны из иерархии |
|---|---|---|---|---|---|---|
| CPU | Стилы | Удержанные | Удержанные | Удержанные | Удержанные | Пятница |
| Компоновка | Удержанные | Удержанные | Удержанные | Удержанные | Удержанные[1] | |
| Команды рендеринга/сетки | Пятница | Удержанные | Удержанные | Удержанные | Пятница | |
| GPU | Меши | Пятница | Удержанные | Удержанные | Удержанные | Пятница |
[1] Память макета сохраняется, так как она остается зарезервированной для элемента. Когда VisualElement собирает мусор, память макета возвращается в пул, делая ее доступной для использования другими элементами.