Работа с полями текста и поиска tvOS в Xamarin
При необходимости приложение Xamarin.tvOS может запрашивать небольшие фрагменты текста от пользователя (например, идентификаторы пользователей и пароли), используя текстовое поле и экранную клавиатуру:
При необходимости можно предоставить возможность поиска ключевое слово содержимого приложения с помощью поля поиска:
В этом документе рассматриваются сведения о работе с полями текста и поиска в приложении Xamarin.tvOS.
Сведения о полях текста и поиска
Как указано выше, при необходимости ваш Xamarin.tvOS может представить один или несколько текстовых полей для сбора небольших объемов текста от пользователя с помощью экранной клавиатуры (или необязательной клавиатуры Bluetooth в зависимости от установленной версии tvOS).
Кроме того, если приложение предоставляет пользователю большое количество содержимого (например, музыку, фильмы или коллекцию рисунков), может потребоваться включить поле поиска, позволяющее пользователю ввести небольшой объем текста для фильтрации списка доступных элементов.
Текстовые поля
В tvOS текстовое поле представлено как поле с фиксированной высотой, закругляемое угловое поле, которое откроет экранную клавиатуру, когда пользователь щелкает его:
Когда пользователь перемещает фокус на заданное текстовое поле, он будет увеличиваться и отображать глубокую тень. Это необходимо учитывать при проектировании пользовательского интерфейса, так как текстовые поля могут перекрывать другие элементы пользовательского интерфейса при фокусе.
Apple предлагает следующие предложения по работе с текстовыми полями:
- Используйте запись текста в разреженном режиме. Из-за характера экранной клавиатуры ввод длинных разделов текста или заполнение нескольких текстовых полей неуловим для пользователя. Лучше всего ограничить объем записи текста с помощью списков выделения или кнопок.
- Используйте подсказки для обмена данными. Текстовое поле может отображать заполнитель "подсказки" при пустом значении. Если применимо, используйте указания, чтобы описать назначение текстового поля вместо отдельной метки.
- Выберите подходящий тип клавиатуры по умолчанию — tvOS предоставляет несколько различных встроенных типов клавиатуры, которые можно указать для текстового поля. Например, клавиатура адреса электронной почты может упростить запись, позволяя пользователю выбирать из списка недавно введенных адресов.
- При необходимости используйте безопасные текстовые поля — безопасное текстовое поле представляет символы, введенные как точки (вместо реальных букв). Всегда используйте безопасное текстовое поле при сборе конфиденциальных данных, таких как пароли.
Клавиатуры
Когда пользователь щелкает текстовое поле в пользовательском интерфейсе, отображается линейная клавиатура на экране. Пользователь использует Сенсорный surface siri Remote для выбора отдельных букв на клавиатуре и ввода запрошенных сведений:
Если в текущем представлении существует несколько текстовых полей, кнопка "Далее" будет автоматически отображаться, чтобы перейти к следующему текстовому полю. Кнопка "Готово " будет отображаться для последнего текстового поля, которое завершит запись текста и вернет пользователя на предыдущий экран.
В любой момент пользователь также может нажать кнопку меню в записи удаленного текста Siri и снова вернуться на предыдущий экран.
Apple предлагает следующие предложения по работе с клавиатурами на экране:
- Выберите подходящий тип клавиатуры по умолчанию — tvOS предоставляет несколько различных встроенных типов клавиатуры, которые можно указать для текстового поля. Например, клавиатура адреса электронной почты может упростить запись, позволяя пользователю выбирать из списка недавно введенных адресов.
- При необходимости используйте представления аксессуаров клавиатуры. Помимо стандартных сведений, которые всегда отображаются, дополнительные представления аксессуаров (например, изображения или метки) можно добавить на экранную клавиатуру, чтобы уточнить назначение записи текста или помочь пользователю в вводе необходимых сведений.
Дополнительные сведения о работе с экранной клавиатурой см. в документации по iOS по управлению клавиатурой, пользовательским представлениям для ввода данных и программирования текста в документации по iOS.
Поиск (Search)
Поле поиска представляет специализированный экран, предоставляющий текстовое поле и экранную клавиатуру, которая позволяет пользователю фильтровать коллекцию элементов, отображаемых под клавиатурой:
Когда пользователь вводит буквы в поле поиска, приведенные ниже результаты автоматически отражают результаты поиска. В любое время пользователь может переместить фокус на результаты и выбрать один из представленных элементов.
Apple предлагает следующие предложения по работе с полями поиска:
- Укажите последние поисковые запросы . Так как ввод текста с помощью Siri Remote может быть емким, и пользователи, как правило, повторяют поисковые запросы, рассмотрите возможность добавления раздела "Последние результаты поиска" перед текущими результатами в области клавиатуры.
- По возможности ограничить количество результатов . Так как большой список элементов может быть сложным для пользователя для синтаксического анализа и навигации, рассмотрите возможность ограничения количества возвращаемых результатов.
- При необходимости укажите фильтры результатов поиска. Если содержимое, предоставленное приложением, предоставляется, попробуйте добавить область полосы, чтобы разрешить пользователю дополнительно фильтровать возвращаемые результаты поиска.
Дополнительные сведения см. в справочнике по классу UISearchController Apple.
Работа с текстовыми полями
Самый простой способ работы с текстовыми полями в приложении Xamarin.tvOS — добавить их в дизайн пользовательского интерфейса с помощью конструктора iOS.
Выполните следующие действия.
На панели решений дважды щелкните
Main.storyboard
файл, чтобы открыть его для редактирования.Перетащите одну или несколько текстовых полей в область конструктора в представление:
Выберите текстовые поля и присвойте каждому уникальному имени на вкладке "Мини-приложение" панели свойств:
В разделе "Текстовое поле" можно определить такие элементы, как указание заполнителя и значение по умолчанию:
Прокрутите вниз, чтобы определить такие свойства, как проверка орфографии, прописная буква и тип клавиатуры по умолчанию:
Сохраните изменения в раскадровке.
В коде можно получить или задать значение текстового поля с помощью его Text
свойства:
Console.WriteLine ("User ID {0} and Password {1}", UserId.Text, Password.Text);
При необходимости можно использовать Started
события и Ended
события текстового поля для реагирования на запись текста, начиная и заканчивая.
Работа с полями поиска
Самый простой способ работы с полями поиска в приложении Xamarin.tvOS — добавить их в дизайн пользовательского интерфейса с помощью конструктора интерфейсов.
Выполните следующие действия.
На панели решений дважды щелкните
Main.storyboard
файл, чтобы открыть его для редактирования.Перетащите новый контроллер представления коллекции в раскадровку, чтобы представить результаты поиска пользователя:
На вкладке "Мини-приложение" панели свойств используйте
SearchResultsViewController
класс иSearchResults
идентификатор раскадровки:Выберите прототип ячейки на поверхности конструктора.
На вкладке "Мини-приложение" Обозреватель свойств используйте
SearchResultCell
для класса иImageCell
идентификатора:Макет макета прототипа ячейки и предоставление каждого элемента с уникальным именем на вкладке "Мини-приложение" Обозреватель свойств:
Сохраните изменения в раскадровке.
Предоставление модели данных
Затем необходимо предоставить класс, который будет выступать в качестве модели данных для результатов, которые пользователь будет искать. В Обозреватель решений щелкните правой кнопкой мыши имя проекта и выберите "Добавить>новый файл" ...>Общий>пустой класс и укажите имя:
Например, приложение, которое позволяет пользователю искать коллекцию изображений по заголовку и ключевому слову, может выглядеть следующим образом:
using System;
using Foundation;
namespace tvText
{
public class PictureInformation : NSObject
{
#region Computed Properties
public string Title { get; set;}
public string ImageName { get; set;}
public string Keywords { get; set;}
#endregion
#region Constructors
public PictureInformation (string title, string imageName, string keywords)
{
// Initialize
this.Title = title;
this.ImageName = imageName;
this.Keywords = keywords;
}
#endregion
}
}
Ячейка представления коллекции
На месте модели данных измените ячейку прототипа (SearchResultViewCell.cs
) и сделайте ее выглядят следующим образом:
using Foundation;
using System;
using UIKit;
namespace tvText
{
public partial class SearchResultViewCell : UICollectionViewCell
{
#region Private Variables
private PictureInformation _pictureInfo = null;
#endregion
#region Computed Properties
public PictureInformation PictureInfo {
get { return _pictureInfo; }
set {
_pictureInfo = value;
UpdateUI ();
}
}
#endregion
#region Constructors
public SearchResultViewCell (IntPtr handle) : base (handle)
{
// Initialize
UpdateUI ();
}
#endregion
#region Private Methods
private void UpdateUI ()
{
// Anything to process?
if (PictureInfo == null) return;
try {
Picture.Image = UIImage.FromBundle (PictureInfo.ImageName);
Picture.AdjustsImageWhenAncestorFocused = true;
Title.Text = PictureInfo.Title;
TextColor = UIColor.LightGray;
} catch {
// Ignore errors if view isn't fully loaded
}
}
#endregion
}
}
Метод UpdateUI
будет использоваться для отображения отдельных полей элементов PictureInformation ( PictureInfo
свойство) в именованных элементах пользовательского интерфейса при каждом обновлении свойства. Например, изображение и заголовок, связанные с рисунком.
Контроллер представления коллекции
Затем измените контроллер представления коллекции результатов поиска (SearchResultsViewController.cs
) и сделайте его следующим образом:
using Foundation;
using System;
using UIKit;
using System.Collections.Generic;
namespace tvText
{
public partial class SearchResultsViewController : UICollectionViewController , IUISearchResultsUpdating
{
#region Constants
public const string CellID = "ImageCell";
#endregion
#region Private Variables
private string _searchFilter = "";
#endregion
#region Computed Properties
public List<PictureInformation> AllPictures { get; set;}
public List<PictureInformation> FoundPictures { get; set; }
public string SearchFilter {
get { return _searchFilter; }
set {
_searchFilter = value.ToLower();
FindPictures ();
CollectionView?.ReloadData ();
}
}
#endregion
#region Constructors
public SearchResultsViewController (IntPtr handle) : base (handle)
{
// Initialize
this.AllPictures = new List<PictureInformation> ();
this.FoundPictures = new List<PictureInformation> ();
PopulatePictures ();
FindPictures ();
}
#endregion
#region Private Methods
private void PopulatePictures ()
{
// Clear list
AllPictures.Clear ();
// Add images
AllPictures.Add (new PictureInformation ("Antipasta Platter","Antipasta","cheese,grapes,tomato,coffee,meat,plate"));
AllPictures.Add (new PictureInformation ("Cheese Plate", "CheesePlate", "cheese,plate,bread"));
AllPictures.Add (new PictureInformation ("Coffee House", "CoffeeHouse", "coffee,people,menu,restaurant,cafe"));
AllPictures.Add (new PictureInformation ("Computer and Expresso", "ComputerExpresso", "computer,coffee,expresso,phone,notebook"));
AllPictures.Add (new PictureInformation ("Hamburger", "Hamburger", "meat,bread,cheese,tomato,pickle,lettus"));
AllPictures.Add (new PictureInformation ("Lasagna Dinner", "Lasagna", "salad,bread,plate,lasagna,pasta"));
AllPictures.Add (new PictureInformation ("Expresso Meeting", "PeopleExpresso", "people,bag,phone,expresso,coffee,table,tablet,notebook"));
AllPictures.Add (new PictureInformation ("Soup and Sandwich", "SoupAndSandwich", "soup,sandwich,bread,meat,plate,tomato,lettus,egg"));
AllPictures.Add (new PictureInformation ("Morning Coffee", "TabletCoffee", "tablet,person,man,coffee,magazine,table"));
AllPictures.Add (new PictureInformation ("Evening Coffee", "TabletMagCoffee", "tablet,magazine,coffee,table"));
}
private void FindPictures ()
{
// Clear list
FoundPictures.Clear ();
// Scan each picture for a match
foreach (PictureInformation picture in AllPictures) {
if (SearchFilter == "") {
// If no search term, everything matches
FoundPictures.Add (picture);
} else if (picture.Title.Contains (SearchFilter) || picture.Keywords.Contains (SearchFilter)) {
// If the search term is in the title or keywords, we've found a match
FoundPictures.Add (picture);
}
}
}
#endregion
#region Override Methods
public override nint NumberOfSections (UICollectionView collectionView)
{
// Only one section in this collection
return 1;
}
public override nint GetItemsCount (UICollectionView collectionView, nint section)
{
// Return the number of matching pictures
return FoundPictures.Count;
}
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
// Get a new cell and return it
var cell = collectionView.DequeueReusableCell (CellID, indexPath);
return (UICollectionViewCell)cell;
}
public override void WillDisplayCell (UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
{
// Grab the cell
var currentCell = cell as SearchResultViewCell;
if (currentCell == null)
throw new Exception ("Expected to display a `SearchResultViewCell`.");
// Display the current picture info in the cell
var item = FoundPictures [indexPath.Row];
currentCell.PictureInfo = item;
}
public override void ItemSelected (UICollectionView collectionView, NSIndexPath indexPath)
{
// If this Search Controller was presented as a modal view, close
// it before continuing
// DismissViewController (true, null);
// Grab the picture being selected and report it
var picture = FoundPictures [indexPath.Row];
Console.WriteLine ("Selected: {0}", picture.Title);
}
public void UpdateSearchResultsForSearchController (UISearchController searchController)
{
// Save the search filter and update the Collection View
SearchFilter = searchController.SearchBar.Text ?? string.Empty;
}
public override void DidUpdateFocus (UIFocusUpdateContext context, UIFocusAnimationCoordinator coordinator)
{
var previousItem = context.PreviouslyFocusedView as SearchResultViewCell;
if (previousItem != null) {
UIView.Animate (0.2, () => {
previousItem.TextColor = UIColor.LightGray;
});
}
var nextItem = context.NextFocusedView as SearchResultViewCell;
if (nextItem != null) {
UIView.Animate (0.2, () => {
nextItem.TextColor = UIColor.Black;
});
}
}
#endregion
}
}
Во-первых, IUISearchResultsUpdating
интерфейс добавляется в класс для обработки фильтра контроллера поиска, обновляемого пользователем:
public partial class SearchResultsViewController : UICollectionViewController , IUISearchResultsUpdating
Константа также определяется для указания идентификатора ячейки прототипа (который соответствует идентификатору, определенному в конструкторе интерфейсов выше), который будет использоваться позже, когда контроллер сбора запрашивает новую ячейку:
public const string CellID = "ImageCell";
служба хранилища создается для полного списка элементов поиска, термина фильтра поиска и списка элементов, соответствующих этим термину:
private string _searchFilter = "";
...
public List<PictureInformation> AllPictures { get; set;}
public List<PictureInformation> FoundPictures { get; set; }
public string SearchFilter {
get { return _searchFilter; }
set {
_searchFilter = value.ToLower();
FindPictures ();
CollectionView?.ReloadData ();
}
}
SearchFilter
После изменения список соответствующих элементов обновляется, а содержимое представления коллекции перезагрузится. Подпрограмма FindPictures
отвечает за поиск элементов, соответствующих новому термину поиска:
private void FindPictures ()
{
// Clear list
FoundPictures.Clear ();
// Scan each picture for a match
foreach (PictureInformation picture in AllPictures) {
if (SearchFilter == "") {
// If no search term, everything matches
FoundPictures.Add (picture);
} else if (picture.Title.Contains (SearchFilter) || picture.Keywords.Contains (SearchFilter)) {
// If the search term is in the title or keywords, we've found a match
FoundPictures.Add (picture);
}
}
}
Значение SearchFilter
будет обновлено (которое будет обновлять представление коллекции результатов) при изменении фильтра в контроллере поиска:
public void UpdateSearchResultsForSearchController (UISearchController searchController)
{
// Save the search filter and update the Collection View
SearchFilter = searchController.SearchBar.Text ?? string.Empty;
}
Метод PopulatePictures
изначально заполняет коллекцию доступных элементов:
private void PopulatePictures ()
{
// Clear list
AllPictures.Clear ();
// Add images
AllPictures.Add (new PictureInformation ("Antipasta Platter","Antipasta","cheese,grapes,tomato,coffee,meat,plate"));
...
}
В этом примере все примеры данных создаются в памяти при загрузке контроллера представления коллекции. В реальном приложении эти данные, вероятно, будут считываться из базы данных или веб-службы, и только по мере необходимости, чтобы не перерасходить ограниченную память Apple TV.
GetItemsCount
Методы NumberOfSections
предоставляют количество сопоставленных элементов:
public override nint NumberOfSections (UICollectionView collectionView)
{
// Only one section in this collection
return 1;
}
public override nint GetItemsCount (UICollectionView collectionView, nint section)
{
// Return the number of matching pictures
return FoundPictures.Count;
}
Метод GetCell
возвращает новую ячейку прототипа (на основе определенного CellID
выше в раскадровки) для каждого элемента в представлении коллекции:
public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
{
// Get a new cell and return it
var cell = collectionView.DequeueReusableCell (CellID, indexPath);
return (UICollectionViewCell)cell;
}
Метод WillDisplayCell
вызывается до отображаемой ячейки, чтобы ее можно было настроить:
public override void WillDisplayCell (UICollectionView collectionView, UICollectionViewCell cell, NSIndexPath indexPath)
{
// Grab the cell
var currentCell = cell as SearchResultViewCell;
if (currentCell == null)
throw new Exception ("Expected to display a `SearchResultViewCell`.");
// Display the current picture info in the cell
var item = FoundPictures [indexPath.Row];
currentCell.PictureInfo = item;
}
Этот DidUpdateFocus
метод предоставляет визуальный отзыв пользователю по мере выделения элементов в представлении коллекции результатов:
public override void DidUpdateFocus (UIFocusUpdateContext context, UIFocusAnimationCoordinator coordinator)
{
var previousItem = context.PreviouslyFocusedView as SearchResultViewCell;
if (previousItem != null) {
UIView.Animate (0.2, () => {
previousItem.TextColor = UIColor.LightGray;
});
}
var nextItem = context.NextFocusedView as SearchResultViewCell;
if (nextItem != null) {
UIView.Animate (0.2, () => {
nextItem.TextColor = UIColor.Black;
});
}
}
Наконец, ItemSelected
метод обрабатывает пользователя, выбрав элемент (щелкнув Touch Surface с помощью Siri Remote) в представлении коллекции результатов:
public override void ItemSelected (UICollectionView collectionView, NSIndexPath indexPath)
{
// If this Search Controller was presented as a modal view, close
// it before continuing
// DismissViewController (true, null);
// Grab the picture being selected and report it
var picture = FoundPictures [indexPath.Row];
Console.WriteLine ("Selected: {0}", picture.Title);
}
Если поле поиска было представлено в виде модального диалогового окна (в верхней части вызываемого представления), используйте DismissViewController
метод, чтобы закрыть представление поиска, когда пользователь выбирает элемент. В этом примере поле поиска отображается как содержимое вкладки "Представление вкладок", поэтому здесь не закрывается.
Дополнительные сведения о представлениях коллекции см . в документации по работе с представлениями коллекции.
Представление поля поиска
Существует два основных способа представления поля поиска (и связанных с ним экранных клавиатур и результатов поиска) пользователю в tvOS:
- Модальное диалоговое окно — поле поиска может быть представлено в текущем режиме представления и просмотра в виде модального представления полноэкранного диалогового окна. Обычно это делается в ответ на нажатие кнопки или другого элемента пользовательского интерфейса. Диалоговое окно закрывается, когда пользователь выбирает элемент из результатов поиска.
- Содержимое представления. Поле поиска является прямой частью данного представления. Например, как содержимое вкладки поиска в контроллере представления вкладок.
Например, список изображений, доступных для поиска выше, поле поиска представлено как "Содержимое представления" на вкладке "Поиск", а контроллер представления вкладки поиска выглядит следующим образом:
using System;
using UIKit;
namespace tvText
{
public partial class SecondViewController : UIViewController
{
#region Constants
public const string SearchResultsID = "SearchResults";
#endregion
#region Computed Properties
public SearchResultsViewController ResultsController { get; set;}
#endregion
#region Constructors
public SecondViewController (IntPtr handle) : base (handle)
{
}
#endregion
#region Private Methods
public void ShowSearchController ()
{
// Build an instance of the Search Results View Controller from the Storyboard
ResultsController = Storyboard.InstantiateViewController (SearchResultsID) as SearchResultsViewController;
if (ResultsController == null)
throw new Exception ("Unable to instantiate a SearchResultsViewController.");
// Create an initialize a new search controller
var searchController = new UISearchController (ResultsController) {
SearchResultsUpdater = ResultsController,
HidesNavigationBarDuringPresentation = false
};
// Set any required search parameters
searchController.SearchBar.Placeholder = "Enter keyword (e.g. coffee)";
// The Search Results View Controller can be presented as a modal view
// PresentViewController (searchController, true, null);
// Or in the case of this sample, the Search View Controller is being
// presented as the contents of the Search Tab directly. Use either one
// or the other method to display the Search Controller (not both).
var container = new UISearchContainerViewController (searchController);
var navController = new UINavigationController (container);
AddChildViewController (navController);
View.Add (navController.View);
}
#endregion
#region Override Methods
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// If the Search Controller is being displayed as the content
// of the search tab, include it here.
ShowSearchController ();
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
// If the Search Controller is being presented as a modal view,
// call it here to display it over the contents of the Search
// tab.
// ShowSearchController ();
}
#endregion
}
}
Во-первых, константа определяется, которая соответствует идентификатору раскадровки, назначенному контроллеру представления коллекции результатов поиска в конструкторе интерфейсов:
public const string SearchResultsID = "SearchResults";
ShowSearchController
Затем метод создает новый контроллер коллекции представлений поиска и отображает его необходимо:
public void ShowSearchController ()
{
// Build an instance of the Search Results View Controller from the Storyboard
ResultsController = Storyboard.InstantiateViewController (SearchResultsID) as SearchResultsViewController;
if (ResultsController == null)
throw new Exception ("Unable to instantiate a SearchResultsViewController.");
// Create an initialize a new search controller
var searchController = new UISearchController (ResultsController) {
SearchResultsUpdater = ResultsController,
HidesNavigationBarDuringPresentation = false
};
// Set any required search parameters
searchController.SearchBar.Placeholder = "Enter keyword (e.g. coffee)";
// The Search Results View Controller can be presented as a modal view
// PresentViewController (searchController, true, null);
// Or in the case of this sample, the Search View Controller is being
// presented as the contents of the Search Tab directly. Use either one
// or the other method to display the Search Controller (not both).
var container = new UISearchContainerViewController (searchController);
var navController = new UINavigationController (container);
AddChildViewController (navController);
View.Add (navController.View);
}
В приведенном выше методе после SearchResultsViewController
создания экземпляра из раскадровки создается новое UISearchController
, чтобы представить поле поиска и экранную клавиатуру пользователю. Коллекция результатов поиска (как определено этим параметром SearchResultsViewController
) будет отображаться на этой клавиатуре.
SearchBar
Затем настраивается информация, например указание заполнителя. Это предоставляет пользователю сведения о типе предварительно сформированного поиска.
Затем поле поиска будет представлено пользователю одним из двух способов:
- Модальное диалоговое окно —
PresentViewController
вызывается метод для представления поиска по существующему представлению в полноэкранном режиме. - Содержимое представления — создается для
UISearchContainerViewController
хранения контроллера поиска. СоздаетсяUINavigationController
для хранения контейнера поиска, затем контроллер навигации добавляется в контроллерAddChildViewController (navController)
представления, а представление представленоView.Add (navController.View)
.
Наконец, и снова на основе типа ViewDidLoad
ViewDidAppear
презентации или метода вызовет ShowSearchController
метод, чтобы представить поиск пользователю:
public override void ViewDidLoad ()
{
base.ViewDidLoad ();
// If the Search Controller is being displayed as the content
// of the search tab, include it here.
ShowSearchController ();
}
public override void ViewDidAppear (bool animated)
{
base.ViewDidAppear (animated);
// If the Search Controller is being presented as a modal view,
// call it here to display it over the contents of the Search
// tab.
// ShowSearchController ();
}
При запуске приложения и вкладке поиска, выбранной пользователем, полный нефильтрованный список элементов будет представлен пользователю:
Когда пользователь начинает вводить поисковый термин, список результатов будет отфильтрован этим термином и обновляется автоматически:
В любое время пользователь может переключить фокус на элемент в результатах поиска и щелкнуть сенсорное устройство Siri Remote, чтобы выбрать его.
Итоги
В этой статье рассматривается проектирование и работа с полями текста и поиска в приложении Xamarin.tvOS. В нем показано, как создать содержимое коллекции текста и поиска в конструкторе интерфейсов, и он показал два разных способа представления поля поиска пользователю в tvOS.