Unity 6.3
0 онлайн 20 гостей 3 в системе
Вход

Найти визуальные элементы с 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");

Дополнительные ресурсы