Xamarin.iOS でのデータを使用したテーブルの設定

に行を UITableView 追加するには、サブクラスを UITableViewSource 実装し、テーブル ビューが呼び出すメソッドをオーバーライドして自身を設定する必要があります。

このガイドでは、次の内容について説明します。

  • UITableViewSource のサブクラス化
  • セルの再利用
  • インデックスの追加
  • ヘッダーとフッターの追加

UITableViewSource のサブクラス化

UITableViewSourceサブクラスは、すべての UITableViewに割り当てられます。 テーブル ビューはソース クラスに対してクエリを実行して、それ自体をレンダリングする方法を決定します (たとえば、必要な行の数と、既定値と異なる場合は各行の高さ)。 最も重要なのは、ソースによって、データが入力された各セル ビューが提供される点です。

テーブルの表示データを作成するために必要な必須の方法は 2 つだけです。

  • RowsInSection – テーブルに nint 表示する必要があるデータ行の合計数を返します。
  • GetCell – メソッドに UITableViewCell 渡される対応する行インデックスのデータが設定された を返します。

BasicTable サンプル ファイル TableSource.cs には、 の最も簡単な実装 UITableViewSourceがあります。 以下のコード スニペットでは、表に表示する文字列の配列を受け入れ、各文字列を含む既定のセル スタイルを返すことがわかります。

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 、単純な文字列配列 (この例に示すように) から List <> またはその他のコレクションまで、任意のデータ構造を使用できます。 メソッドの UITableViewSource 実装により、基になるデータ構造からテーブルが分離されます。

このサブクラスを使用するには、文字列配列を作成してソースを構築し、 の 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);
}

結果のテーブルは次のようになります。

サンプル テーブルの実行

ほとんどのテーブルでは、ユーザーが行をタッチして選択し、他のアクション (曲の再生、連絡先の呼び出し、別の画面の表示など) を実行できます。 これを実現するには、いくつかの作業を行う必要があります。 まず、AlertController を作成して、ユーザーが行をクリックしたときにメッセージを表示します。次のコードを メソッドに RowSelected 追加します。

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

次に、ビュー コントローラーのインスタンスを作成します。

HomeScreen owner;

ビュー コントローラーをパラメーターとして受け取り、フィールドに保存するコンストラクターを UITableViewSource クラスに追加します。

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

}

参照を渡すために UITableViewSource クラスが作成される ViewDidLoad メソッドを this 変更します。

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

最後に、メソッドに RowSelected 戻り、キャッシュされたフィールドで を呼び出 PresentViewController します。

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

    ...
}

これでユーザーは行に触れることができ、アラートが表示されます。

選択した行のアラート

セルの再利用

この例では 6 つの項目しかないため、セルの再利用は必要ありません。 ただし、数百行または数千行を表示する場合は、一度に数個しか画面に収まらない場合に、数百または数千の UITableViewCell オブジェクトを作成するのはメモリの無駄になります。

この状況を回避するために、セルが画面から消えると、そのビューは再利用のためにキューに配置されます。 ユーザーがスクロールすると、テーブルは を呼び出 GetCell して、表示する新しいビューを要求します。既存のセル (現在表示されていない) を再利用するには、 メソッドを DequeueReusableCell 呼び出すだけです。 セルを再利用できる場合は返されます。それ以外の場合は null が返され、コードで新しいセル インスタンスを作成する必要があります。

この例のコード スニペットは、パターンを示しています。

// 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 、さまざまな種類のセルに対して個別のキューが効果的に作成されます。 この例では、すべてのセルが同じように見えるので、ハードコーディングされた識別子は 1 つだけ使用されます。 セルの種類が異なる場合は、インスタンス化されたときと再利用キューから要求されたときの両方で、それぞれ異なる識別子文字列を持つ必要があります。

iOS 6 以降でのセルの再利用

iOS 6 では、コレクション ビューの概要と同様のセル再利用パターンが追加されました。 上記の既存の再利用パターンは下位互換性のために引き続きサポートされていますが、セルに null チェックが不要になったため、この新しいパターンが推奨されます。

新しいパターンでは、アプリケーションは、 または をコントローラーのコンストラクターで呼び出 RegisterClassForCellReuse すことによって使用されるセル クラスまたは RegisterNibForCellReuse xib を登録します。 次に、 メソッドで GetCell セルをデキューする場合は、 を呼び出 DequeueReusableCell して、セル クラスまたは xib に登録した識別子とインデックス パスを渡します。

たとえば、次のコードは、UITableViewController にカスタム セル クラスを登録します。

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

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

MyCell クラスを登録すると、次に示すように、余分な null チェックを必要とせずに、 の メソッドUITableViewSourceGetCellセルをデキューできます。

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 、セル クラスのインスタンスを構築できません。

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

上で説明したトピックの例については、この記事にリンクされている BasicTable サンプルを参照してください。

インデックスの追加

インデックスは、ユーザーが長いリストをスクロールするのに役立ちます。通常はアルファベット順に並べられますが、任意の条件でインデックスを作成できます。 BasicTableIndex サンプルでは、インデックスを示すために、ファイルからアイテムのはるかに長いリストを読み込みます。 インデックス内の各項目は、テーブルの 'section' に対応します。

[インデックス] の表示

"セクション" をサポートするには、テーブルの背後にあるデータをグループ化する必要があるため、BasicTableIndex サンプルでは、各項目の最初の文字をディクショナリ キーとして使用して、文字列の配列から を作成 Dictionary<> します。

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<> するために次のメソッドを追加または変更する必要があります。

  • NumberOfSections – このメソッドは省略可能です。既定では、テーブルは 1 つのセクションを前提としています。 インデックスを表示する場合、このメソッドはインデックス内の項目の数を返す必要があります (たとえば、インデックスに英語のアルファベットのすべての文字が含まれている場合は 26)。
  • RowsInSection – 特定のセクションの行数を返します。
  • SectionIndexTitles – インデックスの表示に使用される文字列の配列を返します。 サンプル コードは、文字の配列を返します。

サンプル ファイル BasicTableIndex/TableSource.cs の更新されたメソッドは次のようになります。

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

インデックスは通常、プレーン テーブル スタイルでのみ使用されます。

ヘッダーとフッターの追加

ヘッダーとフッターを使用して、テーブル内の行を視覚的にグループ化できます。 必要なデータ構造は、インデックス Dictionary<> の追加と非常によく似ています。 この例では、アルファベットを使用してセルをグループ化する代わりに、植物の種類別に野菜をグループ化します。 出力は次のようになります。

ヘッダーとフッターのサンプル

ヘッダーとフッターを表示するには、サブクラスに次の UITableViewSource 追加メソッドが必要です。

  • TitleForHeader – ヘッダーとして使用するテキストを返します
  • TitleForFooter – フッターとして使用するテキストを返します。

サンプル ファイル BasicTableHeaderFooter/Code/TableSource.cs の更新されたメソッドは次のようになります。

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

の メソッドと メソッドのオーバーライドUITableViewSourceを使用して、View オブジェクトを使用してヘッダーとGetViewForFooterフッターのGetViewForHeader外観をさらにカスタマイズできます。