Найти визуальные элементы с UQuery
Вы можете использовать UQuery чтобы найти элементы из визуальное дерево. UQuery был вдохновлен JQuery и Linq, и предназначен для ограничения динамического выделения памяти. Это позволяет оптимально использовать мобильные платформы.
Методы запроса
Вы можете использовать UQuery через следующие методы расширения:
Внутренне методы Q и Query используют UQueryBuilder для построения запроса. Эти методы расширения уменьшают подробность создания UQueryBuilder.
Чтобы использовать UQuery для поиска элементов, вы должны загрузить и экземпляр UXML, а затем использовать Query или Q для построения правил выбора на корневом визуальном элементе.
Query возвращает список элементов, которые соответствуют правилам выбора. Вы можете фильтровать возвращаемые результаты Query открытыми методами UQueryBuilder, например First, Last, AtIndex, Children, и Where.
Q — это сокращение от Query<T>.First(). Он возвращает первый элемент, который соответствует правилам выбора.
Элементы запроса
Вы можете запрашивать элементы по их имени, их USS классуили их типу элемента (C# типу). Вы также можете запрашивать с предикатом или делать сложные иерархические запросы.
В следующих разделах используется пример UXML, чтобы продемонстрировать, как найти элементы:
<UXML xmlns="UnityEngine.UIElements">
<VisualElement name="container1">
<Button name="OK" text="OK" />
<Button name="Cancel" text="Cancel" />
</VisualElement>
<VisualElement name="container2">
<Button name="OK" class="yellow" text="OK" />
<Button name="Cancel" text="Cancel" />
</VisualElement>
<VisualElement name="container3">
<Button name="OK" class="yellow" text="OK" />
<Button name="Cancel" class="yellow" text="Cancel" />
</VisualElement>
</UXML>
Запрос по имени
Чтобы найти элементы по их имени, используйте Query(name: "element-name") или Q(name: "element-name"). Вы можете опустить name, так как это первый аргумент. Например:
Следующий пример находит список элементов с именем OK:
List<VisualElement> result = root.Query("OK").ToList();
В следующем примере используется Query для поиска первого элемента с именем OK:
VisualElement result = root.Query("OK").First(); //or VisualElement result = root.Q("OK");
В следующем примере используется Q для поиска первого элемента с именем OK:
VisualElement result = root.Q("OK");
Следующий пример находит второй элемент с именем OK:
VisualElement result3 = root.Query("OK").AtIndex(1);
Следующий пример находит последний элемент с именем OK:
VisualElement result4 = root.Query("OK").Last();
Запрос по классу USS
Чтобы найти элементы по классу USS, используйте Query(className: "class-name") или Q(className: "class-name").
Следующий пример находит все элементы, у которых есть класс yellow и включает их в список:
List<VisualElement> result = root.Query(className: "yellow").ToList();
Следующий пример находит первый элемент, у которого есть класс yellow:
VisualElement result = root.Q(className: "yellow");
Запрос по типу элемента
Чтобы найти элементы по их типу элемента(тип C#), используйте Query<Type> или Q<Type>.
Следующий пример находит первую кнопку и добавляет к ней tooltip:
VisualElement result = root.Q<Button>();
result.tooltip = "This is a tooltip!";
Следующий пример находит третью кнопку:
VisualElement result = root.Query<Button>().AtIndex(2);
Примечание: Вы можете запрашивать только по фактическому типу элемента, а не по базовым классам.
Запрос с предикатом
Помимо поиска элементов по имени, классу и типу, можно также использовать Where метод для выбора всех элементов, которые удовлетворяют предикат. Предикат должен быть обратным вызовом функции, которая принимает один VisualElement аргумент.
Следующий пример находит все элементы с yellowUSS-классы, у которых нет всплывающих подсказок:
List<VisualElement> result = root.Query(className: "yellow").Where(elem => elem.tooltip == "").ToList();
Комплексные иерархические запросы
Имя, класс и тип можно комбинировать, чтобы строить сложные иерархические запросы.
В следующем примере найдена первая кнопка с именем OK у которого класс yellow:
VisualElement result = root.Query<Button>(className: "yellow", name: "OK").First();
В следующем примере найдена дочерняя кнопка отмены container2:
VisualElement result = root.Query<VisualElement>("container2").Children<Button>("Cancel").First();
Примечание: UQuery включает сам запрошенный элемент в результаты поиска, если он соответствует критериям. Например:
var list = myElement.Query<VisualElement>("nameOrClass").ToList();
Она может вернуться myElement самого себя, если он соответствует селектору. Это поведение отличается от Element.querySelectorAll() в сети, которая явно возвращает только потомственные узлы.
Ориентация на результаты
Вы можете использовать методы ForEach для работы непосредственно с результатами запроса.
Следующий пример добавляет tooltip для любых элементов, которые не имеют подсказок:
root.Query().Where(elem => elem.tooltip == "").ForEach(elem => elem.tooltip="This is a tooltip!");
Передовая практика
При использовании UQuery учитывайте следующее:
- UQuery обходит иерархию, отыскивая элементы по имени, классу или типу. Кэшируйте результаты UQuery при инициализации.
- Чтобы найти элементы-предки или проверить отношения родитель-ребёнок, вручную продвигайтесь вверх по цепи
.parentдо тех пор, пока не найдете целевой элемент или не достигнете нуля. - Если вам нужно извлечь несколько элементов, используйте
QueryStateструктура (возвращаемаяelement.Query()метод) и перечислить его, чтобы избежать создания списков. Вы также можете построить запрос один раз и выполнить его на различных элементах. - UI Toolkit не уничтожает ненужные больше визуальные элементы — их собирает сборщик мусора C#. Следите за тем, чтобы случайно не сохранить ссылки на визуальные элементы в классе, который живёт дольше, чем UIDocument или окно, откуда эти элементы взялись.
- При создании или выпуске большого количества элементов, включите постепенную сборку мусора, чтобы избежать пиков сборки мусора.
- Захватывайте переменные
VisualElementвнутри закрытий. Когда вы используете обратные вызова событий или делегации с визуальными элементами, захватывайте конкретные элементы, которые вам нужны в локальных переменных, прежде чем создавать закрытие. Это предотвращает закрытие от захвата большей области (например, всей ссылкиthis), что может привести к утечке памяти. Например:
// Good: Capture only what you need.
var button = root.Q<Button>("myButton");
button.clicked += () => Debug.Log($"Button {button.name} clicked");
// Avoid: This captures the entire 'this' reference.
button.clicked += () => Debug.Log($"Button {this.myButton.name} clicked");