Naplnění tabulky daty v Xamarin.iOS

Pokud chcete přidat řádky do UITableView podtřídy, musíte implementovat UITableViewSource podtřídu a přepsat metody, které zobrazení tabulky volá k naplnění samotného.

Tento průvodce popisuje:

  • Podtřídy uiTableViewSource
  • Opakované použití buňky
  • Přidání indexu
  • Přidání záhlaví a zápatí

Podtřídy UITableViewSource

UITableViewSource Každé podtřídě je přiřazeno každé UITableViewpodtřídě . Zobrazení tabulky se dotazuje zdrojové třídy, aby určila, jak se má vykreslit (například kolik řádků se vyžaduje a výška každého řádku, pokud se liší od výchozího). Nejdůležitější je, že zdroj poskytuje každé zobrazení buněk naplněné daty.

K zobrazení dat tabulky se vyžadují jenom dvě povinné metody:

  • RowsInSection – vrátí nint počet celkového počtu řádků dat, která by se měla zobrazit v tabulce.
  • GetCell – vrátí vyplněná UITableViewCell data pro odpovídající index řádku předaný metodě.

Ukázkový soubor BasicTable TableSource.cs má nejjednodušší možnou implementaci UITableViewSource. V následujícím fragmentu kódu vidíte, že přijímá pole řetězců, které se mají zobrazit v tabulce, a vrátí výchozí styl buňky obsahující každý řetězec:

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;
        }
}

A UITableViewSource může použít libovolnou datovou strukturu z jednoduchého pole řetězců (jak je znázorněno v tomto příkladu) až po seznam <> nebo jinou kolekci. Implementace UITableViewSource metod izoluje tabulku od základní datové struktury.

Chcete-li použít tuto podtřídu, vytvořte pole řetězců pro vytvoření zdroje a pak ho přiřaďte instanci 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);
}

Výsledná tabulka vypadá takto:

Sample table running

Většina tabulek umožňuje uživateli, aby ho vybral a provedl nějakou jinou akci (například přehrávání skladby nebo volání kontaktu nebo zobrazení jiné obrazovky). Abychom toho dosáhli, musíme udělat několik věcí. Nejprve vytvoříme AlertController, který zobrazí zprávu, když uživatel klikne na řádek přidáním následujícího příkazu do RowSelected metody:

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);
}

Dále vytvořte instanci kontroleru zobrazení:

HomeScreen owner;

Přidejte konstruktor do třídy UITableViewSource, který přebírá kontroler zobrazení jako parametr a uloží ho do pole:

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

}

Upravte metodu ViewDidLoad, kde je vytvořena třída UITableViewSource pro předání this odkazu:

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

Nakonec v metodě zavolejte RowSelectedPresentViewController pole uložené v mezipaměti:

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

    ...
}

Uživatel se teď může dotýkat řádku a zobrazí se upozornění:

The row selected alert

Opakované použití buňky

V tomto příkladu je jenom šest položek, takže není nutné opakovaně používat buňku. Při zobrazení stovek nebo tisíců řádků by však bylo plýtvání pamětí vytvořit stovky nebo tisíce UITableViewCell objektů, když se na obrazovku najednou vejde jen několik.

Chcete-li se této situaci vyhnout, když buňka zmizí z obrazovky, její zobrazení se umístí do fronty pro opakované použití. Když se uživatel posune, volání GetCell tabulky, která požádá o zobrazení nových zobrazení – aby znovu použila existující buňku (která se právě nezobrazuje), jednoduše volejte metodu DequeueReusableCell . Pokud je buňka k dispozici pro opakované použití, bude vrácena, jinak se vrátí hodnota null a váš kód musí vytvořit novou instanci buňky.

Tento fragment kódu z příkladu ukazuje vzor:

// 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);

Efektivně cellIdentifier vytváří samostatné fronty pro různé typy buněk. V tomto příkladu všechny buňky vypadají stejně, takže se použije jenom jeden pevně zakódovaný identifikátor. Pokud existují různé typy buněk, měly by mít každý jiný řetězec identifikátoru, a to jak při vytváření instancí, tak při jejich vyžádání z fronty pro opakované použití.

Opakované použití buněk v iOSu 6+

iOS 6 přidal vzor opakovaného použití buněk podobný tomu, který je součástí zobrazení kolekce. I když stávající vzor opětovného použití, který je uvedený výše, je stále podporován pro zpětnou kompatibilitu, je tento nový vzor vhodnější, protože odstraňuje potřebu kontroly null v buňce.

S novým vzorem aplikace zaregistruje třídu buněk nebo xib, které se mají použít voláním RegisterClassForCellReuse buď nebo RegisterNibForCellReuse v konstruktoru kontroleru. Když pak v metodě zrušíte vyřazení buňky GetCell , jednoduše zavoláte DequeueReusableCell předání identifikátoru, který jste zaregistrovali pro třídu buňky nebo xib a cestu indexu.

Například následující kód zaregistruje vlastní třídu buněk v UITableViewController:

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

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

Se zaregistrovanou třídou MyCell lze buňku vyřadit z fronty metodou GetCellUITableViewSource bez nutnosti dodatečné kontroly null, jak je znázorněno níže:

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;
  }
}

Mějte na paměti, že při použití nového vzoru opakovaného použití s vlastní třídou buněk je nutné implementovat konstruktor, který přebírá IntPtr, jak je znázorněno v následujícím fragmentu kódu, jinak Objective-C nebude možné vytvořit instanci třídy buňky:

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

Příklady témat vysvětlených výše najdete v ukázce Základní tabulka propojená s tímto článkem.

Přidání indexu

Index pomáhá uživateli procházet dlouhé seznamy, obvykle seřazené abecedně, i když můžete indexovat podle libovolného kritéria. Ukázka BasicTableIndex načte mnohem delší seznam položek ze souboru, aby ukázal index. Každá položka v indexu odpovídá oddílu tabulky.

The Index display

Aby bylo možné podporovat "oddíly" data za tabulkou, je potřeba seskupit, takže ukázka BasicTableIndex vytvoří Dictionary<> z pole řetězců první písmeno každé položky jako klíč slovníku:

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 ();

Podtřída UITableViewSource pak potřebuje, aby bylo možné použít Dictionary<> následující metody:

  • NumberOfSections – tato metoda je volitelná, ve výchozím nastavení tabulka předpokládá jednu část. Při zobrazení indexu by tato metoda měla vrátit počet položek v indexu (například 26, pokud index obsahuje všechna písmena anglické abecedy).
  • RowsInSection – vrátí počet řádků v daném oddílu.
  • SectionIndexTitles – vrátí pole řetězců, které se použijí k zobrazení indexu. Vzorový kód vrátí matici písmen.

Aktualizované metody v ukázkovém souboru BasicTableIndex/TableSource.cs vypadají takto:

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;
}

Indexy se obvykle používají pouze se stylem prosté tabulky.

Přidání záhlaví a zápatí

Záhlaví a zápatí lze použít k vizuálnímu seskupení řádků v tabulce. Požadovaná datová struktura je velmi podobná přidání indexu Dictionary<> – funguje opravdu dobře. Místo použití abecedy k seskupení buněk tento příklad seskupí zeleninu podle botanického typu. Výstup vypadá takto:

Sample Headers and Footers

K zobrazení záhlaví a zápatí podtřídy UITableViewSource vyžaduje tyto další metody:

  • TitleForHeader – vrátí text, který se má použít jako záhlaví.
  • TitleForFooter – vrátí text, který se má použít jako zápatí.

Aktualizované metody v ukázkovém souboru BasicTableHeaderFooter/Code/TableSource.cs vypadají takto:

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";
}

Vzhled záhlaví a zápatí můžete dále přizpůsobit pomocí objektu View pomocí GetViewForHeader přepsání UITableViewSourcemetody .GetViewForFooter