共用方式為


使用 Xamarin.iOS 中的數據填入數據表

若要將數據列加入至 UITableView ,您需要實 UITableViewSource 作子類別,並覆寫數據表檢視呼叫以填入本身的方法。

本指南涵蓋:

  • 子類別化UITableViewSource
  • 單元格重複使用
  • 新增索引
  • 新增頁首和頁尾

子類別化UITableViewSource

UITableViewSource 類別會指派給每個 UITableView。 數據表檢視會查詢來源類別,以判斷如何轉譯本身(例如,如果與預設值不同,則需要多少列,以及每個數據列的高度)。 最重要的是,來源會提供填入數據的每個數據格檢視。

建立資料表顯示資料只需要兩個必要方法:

  • 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 類別以傳遞 this 參考的 ViewDidLoad 方法:

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

最後,回到您的 RowSelected 方法,在快取欄位上呼叫 PresentViewController

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

    ...
}

現在使用者可以觸控數據列,而且會出現警示:

選取的數據列警示

單元格重複使用

在此範例中,只有六個專案,因此不需要重複使用單元格。 不過,顯示數百或數千個數據列時,只要在畫面上只容納一些物件時,就會浪費記憶體來建立數百或數千個 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 會為不同類型的儲存格建立個別的佇列。 在此範例中,所有儲存格看起來都相同,因此只會使用一個硬式編碼標識碼。 如果有不同類型的數據格,它們都應該有不同的標識符字串,這兩者都是在具現化時,以及從重複使用佇列要求它們時。

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 類別之後,可以在 的 方法UITableViewSourceGetCell清除儲存格,而不需要額外的 Null 檢查,如下所示:

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 – 此方法是選擇性的,根據預設,數據表假設有一個區段。 當顯示索引時,這個方法應該會傳回索引中的項目數(例如,如果索引包含英文字母的所有字母,則為 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";
}

您可以使用 上的 和 GetViewForFooter 方法覆寫UITableViewSourceGetViewForHeader使用 View 物件進一步自定義頁首和頁尾的外觀。