Заполнение таблицы с данными в Xamarin.iOSPopulating a Table with Data in Xamarin.iOS

Для добавления строк в UITableView необходимо реализовать UITableViewSource подклассов и переопределение, вызывает методы, которые Просмотр таблицы для заполнения сам.To add rows to a UITableView you need to implement a UITableViewSource subclass and override the methods that the table view calls to populate itself.

В этом руководстве описывается:This guide covers:

  • Создание подкласса UITableViewSourceSubclassing a UITableViewSource
  • Повторное использование ячеекCell Reuse
  • Добавление индексаAdding an Index
  • Добавление верхних и нижних колонтитуловAdding Headers and Footers

Создание подкласса UITableViewSourceSubclassing UITableViewSource

Объект UITableViewSource подкласс назначается в каждый UITableView.A UITableViewSource subclass is assigned to every UITableView. Представление таблицы запрашивает класс источника, чтобы определить, как для своей отрисовки (для примера, сколько строк являются обязательными и высоту каждой строки, если они отличаются от настроек по умолчанию).The table view queries the source class to determine how to render itself (for example, how many rows are required and the height of each row if different from the default). Самое главное источник предоставляет каждое представление ячейки, заполненную данными.Most importantly, the source supplies each cell view populated with data.

Существует только два обязательных методы, необходимые для создания отображения данных таблицы.There are only two mandatory methods required to make a table display data:

  • RowsInSection — возвращаемое nint число общее число строк данных в таблице будет отображаться.RowsInSection – return an nint count of the total number of rows of data the table should display.
  • GetCell — возвращаемое UITableCellView заполняется данными для соответствующего индекса строки, передаваемые методу.GetCell – return a UITableCellView populated with data for the corresponding row index passed to the method.

Пример файла BasicTable TableSource.cs имеет простейшая реализация UITableViewSource.The BasicTable sample file TableSource.cs has the simplest possible implementation of UITableViewSource. Вы увидите в приведенном ниже фрагменте кода, что он принимает массив строк для отображения в таблице и возвращает стиль ячейки по умолчанию, содержащий каждой строки:You can see in code snippet below that it accepts an array of strings to display in the table and returns a default cell style containing each string:

public class TableSource : UITableViewSource {

        string[] TableItems;
        string CellIdentifier = "TableCell";

        public TableSource (string[] items)
        {
            TableItems = items;
        }

        public override nint RowsInSection (UITableView tableview, nint section)
        {
            return TableItems.Length;
        }

        public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
        {
            UITableViewCell cell = tableView.DequeueReusableCell (CellIdentifier);
            string item = TableItems[indexPath.Row];

            //---- if there are no cells to reuse, create a new one
            if (cell == null)
            { cell = new UITableViewCell (UITableViewCellStyle.Default, CellIdentifier); }

            cell.TextLabel.Text = item;

            return cell;
        }
}

Объект UITableViewSource можно использовать любую структуру данных, от простой строковый массив (как показано в этом примере) <> списка или другой коллекции.A UITableViewSource can use any data structure, from a simple string array (as shown in this example) to a List <> or other collection. Реализация UITableViewSource методы изолирует таблицы из базовой структуры данных.The implementation of UITableViewSource methods isolates the table from the underlying data structure.

Чтобы использовать этот подкласс, создать массив строк для создания источника, а затем присвоить экземпляр UITableView:To use this subclass, create a string array to construct the source then assign it to an instance of UITableView:

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    table = new UITableView(View.Bounds); // defaults to Plain style
    string[] tableItems = new string[] {"Vegetables","Fruits","Flower Buds","Legumes","Bulbs","Tubers"};
    table.Source = new TableSource(tableItems);
    Add (table);
}

Результирующая таблица выглядит следующим образом:The resulting table looks like this:

Большинство таблиц разрешает пользователю touch строки, чтобы выбрать ее и выполнения других действий (например, воспроизведение песни, или вызов контакт или отображения другого экрана).Most tables allow the user to touch a row to select it and perform some other action (such as playing a song, or calling a contact, or showing another screen). Для этого существует несколько вещей, которые нам нужно сделать.To achieve this, there are a few things we need to do. Во-первых давайте создадим AlertController для отображения сообщения, когда пользователь щелкните строку, добавив следующую команду, чтобы RowSelected метод:First, let's create an AlertController to display a message when the user click on a row by adding the following to the RowSelected method:

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    UIAlertController okAlertController = UIAlertController.Create ("Row Selected", tableItems[indexPath.Row], UIAlertControllerStyle.Alert);
    okAlertController.AddAction(UIAlertAction.Create("OK", UIAlertActionStyle.Default, null));
    ...

    tableView.DeselectRow (indexPath, true);
}

Создайте экземпляр нашего контроллера представления:Next, create an instance of our View Controller:

HomeScreen owner;

Добавьте конструктор в класс UITableViewSource, который принимает контроллер представления в качестве параметра и сохраняет его в поле:Add a constructor to your UITableViewSource class which takes a view controller as a parameter and saves it in a field:

public TableSource (string[] items, HomeScreen owner)
{
    ...
    this.owner = owner;

}

Измените метод ViewDidLoad, где создается класс UITableViewSource для передачи this ссылки:Modify the ViewDidLoad method where the UITableViewSource class is created to pass the this reference:

table.Source = new TableSource(tableItems, this);

Наконец, обратно в ваш RowSelected мы вызываем метод PresentViewController кэшированных поля:Finally, back in your RowSelected method, call PresentViewController on the cached field:

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    ...
    owner.PresentViewController (okAlertController, true, null);

    ...
}

Теперь пользователь могут соприкасаться строки и появится предупреждение:Now the user can touch a row and an alert will appear:

Повторное использование ячеекCell Reuse

В этом примере имеется только шесть элементов, поэтому не существует, повторное использование ячеек не требуется.In this example there are only six items, so there is no cell reuse required. При отображении сотни или тысячи строк, однако было бы к повышенному расходу памяти для создания сотен или тысяч UITableViewCell объектов, когда только некоторые помещаются на экране одновременно.When displaying hundreds or thousands of rows, however, it would be a waste of memory to create hundreds or thousands of UITableViewCell objects when only a few fit on the screen at a time.

Чтобы избежать такой ситуации, когда ячейка пропадает с экрана, на котором его представления помещается в очередь для повторного использования.To avoid this situation, when a cell disappears from the screen its view is placed in a queue for reuse. Во время прокрутки, таблице вызывает GetCell запрашивать новые представления для отображения — повторное использование существующей ячейкой, (который не отображается в настоящий момент) просто вызовите DequeueReusableCell метод.As the user scrolls, the table calls GetCell to request new views to display – to reuse an existing cell (that is not currently being displayed) simply call the DequeueReusableCell method. Если ячейка доступна для повторного использования, которые будут возвращены, в противном случае возвращается значение null, и ваш код должен создать новый экземпляр ячейки.If a cell is available for reuse it will be returned, otherwise a null is returned and your code must create a new cell instance.

Этот фрагмент кода из примера показан шаблон:This snippet of code from the example demonstrates the pattern:

// request a recycled cell to save memory
UITableViewCell cell = tableView.DequeueReusableCell (cellIdentifier);
// if there are no cells to reuse, create a new one
if (cell == null)
    cell = new UITableViewCell (UITableViewCellStyle.Default, cellIdentifier);

cellIdentifier Фактически создает отдельные очереди для различных типов ячейки.The cellIdentifier effectively creates separate queues for different types of cell. В этом примере, что все ячейки выглядят же жестко закодированное чтобы только один идентификатор используется.In this example all the cells look the same so only one hardcoded identifier is used. При наличии различных типов ячейки они должен иметь строку другой идентификатор при создании экземпляров и по запросу из очереди повторного использования.If there were different types of cell they should each have a different identifier string, both when they are instantiated and when they are requested from the reuse queue.

Повторное использование ячеек в iOS 6 +Cell Reuse in iOS 6+

iOS 6 добавлены ячейки повторное использование шаблон, аналогичный один Знакомство с представлениями коллекции.iOS 6 added a cell reuse pattern similar to the one introduction with Collection Views. Несмотря на то, что существующий шаблон повторного использования, приведенный выше по-прежнему поддерживается для обратной совместимости, этот шаблон является предпочтительным, так как он избавляет от необходимости проверку значений null в ячейке.Although the existing reuse pattern shown above is still supported for backwards compatibility, this new pattern is preferable as it removes the need for the null check on the cell.

С помощью новой модели приложение регистрирует класс ячейки или xib для использования с помощью вызова RegisterClassForCellReuse или RegisterNibForCellReuse в конструктор контроллера.With the new pattern an application registers the cell class or xib to be used by calling either RegisterClassForCellReuse or RegisterNibForCellReuse in the controller's constructor. Затем, когда вывод ячейки в GetCell простым вызовом метода DequeueReusableCell передав идентификатор регистрации класс ячейки или xib и пути индекса.Then, when dequeueing the cell in the GetCell method, simply call DequeueReusableCell passing the identifier you registered for the cell class or xib and the index path.

Например следующий код регистрирует пользовательский класс ячейки в UITableViewController:For example, the following code registers a custom cell class in a UITableViewController:

public class MyTableViewController : UITableViewController
{
  static NSString MyCellId = new NSString ("MyCellId");

  public MyTableViewController ()
  {
    TableView.RegisterClassForCellReuse (typeof(MyCell), MyCellId);
  }
  ...
}

С помощью класса MyCell регистрации, ячейки может быть выведен из очереди в GetCell метод UITableViewSource без необходимости дополнительной пустоту, как показано ниже:With the MyCell class registered, the cell can be dequeued in the GetCell method of the UITableViewSource without the need for the extra null check, as shown below:

class MyTableSource : UITableViewSource
{
  public override UITableViewCell GetCell (UITableView tableView, NSIndexPath indexPath)
  {
    // if cell is not available in reuse pool, iOS will create one automatically
    // no need to do null check and create cell manually
    var cell = (MyCell) tableView.DequeueReusableCell (MyCellId, indexPath);

    // do whatever you need to with cell, such as assigning properties, etc.

    return cell;
  }
}

Следует помнить, что при использовании нового шаблона повторного использования с пользовательский класс ячейки, вам необходимо реализовать конструктор, принимающий IntPtr, как показано в следующем фрагменте, в противном случае Objective-C будет невозможно создать экземпляр класса ячейки:Be aware, when using the new reuse pattern with a custom cell class, you need to implement the constructor that takes an IntPtr, as shown in the snippet below, otherwise Objective-C won't be able to construct an instance of the cell class:

public class MyCell : UITableViewCell
{
  public MyCell (IntPtr p):base(p)
  {
  }
  ...
}

Вы можете увидеть примеры в разделах описано выше в BasicTable образец, связанные с этой статьей.You can see examples of the topics explained above in the BasicTable sample linked to this article.

Добавление индексаAdding an Index

Индекс помогает пользователям прокручивать длинных списках, обычно представлены в алфавитном порядке несмотря на то, что можно индексировать по критериям, независимо от необходимости.An index helps the user scroll through long lists, typically ordered alphabetically although you can index by whatever criteria you wish. BasicTableIndex пример будет загружен из файла, чтобы продемонстрировать индекс гораздо более длинный список элементов.The BasicTableIndex sample loads a much longer list of items from a file to demonstrate the index. Каждый элемент в индексе соответствует «раздел» таблицы.Each item in the index corresponds to a ‘section’ of the table.

Для поддержки «sections», данные для таблицы необходимо группировать, чтобы в образце BasicTableIndex создается Dictionary<> из массива строк, используя первую букву каждого элемента в качестве ключа словаря:To support ‘sections’ the data behind the table needs to be grouped, so the BasicTableIndex sample creates a Dictionary<> from the array of strings using the first letter of each item as the dictionary key:

indexedTableItems = new Dictionary<string, List<string>>();
foreach (var t in items) {
    if (indexedTableItems.ContainsKey (t[0].ToString ())) {
        indexedTableItems[t[0].ToString ()].Add(t);
    } else {
        indexedTableItems.Add (t[0].ToString (), new List<string>() {t});
    }
}
keys = indexedTableItems.Keys.ToArray ();

UITableViewSource Подкласс должна следующие методы добавлены или изменены для использования Dictionary<> :The UITableViewSource subclass then needs the following methods added or modified to use the Dictionary<> :

  • NumberOfSections — этот метод является необязательным, по умолчанию в таблице предполагается один раздел.NumberOfSections – this method is optional, by default the table assumes one section. При отображении индекса этот метод должен возвращать число элементов в индексе (например, 26 Если индекс содержит все буквы английского алфавита).When displaying an index this method should return the number of items in the index (for example, 26 if the index contains all the letters of the English alphabet).
  • RowsInSection — возвращает количество строк в конкретном разделе.RowsInSection – returns the number of rows in a given section.
  • SectionIndexTitles — возвращает массив строк, которые будут использоваться для отображения индекса.SectionIndexTitles – returns the array of strings that will be used to display the index. Пример кода возвращает массив букв.The sample code returns an array of letters.

Обновленные методы в образце файла BasicTableIndex/TableSource.cs выглядеть следующим образом:The updated methods in the sample file BasicTableIndex/TableSource.cs look like this:

public override nint NumberOfSections (UITableView tableView)
{
    return keys.Length;
}
public override nint RowsInSection (UITableView tableview, nint section)
{
    return indexedTableItems[keys[section]].Count;
}
public override string[] SectionIndexTitles (UITableView tableView)
{
    return keys;
}

Индексы обычно используются только с простой таблицы стилей.Indexes are generally only used with the Plain table style.

Добавление верхних и нижних колонтитуловAdding Headers and Footers

Верхние и нижние колонтитулы позволяют визуально сгруппировать строки в таблице.Headers and footers can be used to visually group rows in a table. Необходимые структуры данных очень сходно с добавлением индекса — Dictionary<> работает действительно хорошо.The data structure required is very similar to adding an index – a Dictionary<> works really well. Вместо использования алфавита, чтобы группировать ячейки, в этом примере будет группировать овощи botanical типом.Instead of using the alphabet to group the cells, this example will group the vegetables by botanical type. Вывод выглядит следующим образом.The output looks like this:

Чтобы отобразить верхние и нижние колонтитулы UITableViewSource подкласс требует эти дополнительные методы:To display headers and footers the UITableViewSource subclass requires these additional methods:

  • TitleForHeader — возвращает текст, который используется в качестве заголовкаTitleForHeader – returns the text to use as the header
  • TitleForFooter — возвращает текст для использования в качестве нижнего колонтитула.TitleForFooter – returns the text to use as the footer.

Обновленные методы в образце файла BasicTableHeaderFooter/Code/TableSource.cs выглядеть следующим образом:The updated methods in the sample file BasicTableHeaderFooter/Code/TableSource.cs look like this:

public override string TitleForHeader (UITableView tableView, nint section)
{
    return keys[section];
}
public override string TitleForFooter (UITableView tableView, nint section)
{
    return indexedTableItems[keys[section]].Count + " items";
}

Можно настроить внешний вид заголовка и нижнего колонтитула с представлением объекта, использование GetViewForHeader и GetViewForFooter метод переопределяет на UITableViewSource.You can further customize the appearance of the header and footer with a View object, using the GetViewForHeader and GetViewForFooter method overrides on UITableViewSource.