共用方式為


使用 Xamarin.iOS 編輯數據表

在子類別中 UITableViewSource 覆寫方法可啟用數據表編輯功能。 最簡單的編輯行為是可使用單一方法覆寫實作的撥動到刪除手勢。 更複雜的編輯(包括行動數據列)可以使用編輯模式中的資料表來完成。

撥動以刪除

要刪除功能的撥動是用戶預期在 iOS 中的自然手勢。

撥動至刪除的範例

有三種方法覆寫會影響撥動手勢,以顯示 儲存格中的 [刪除] 按鈕:

  • CommitEditingStyle – 資料表來源會偵測是否已覆寫此方法,並自動啟用撥動到刪除手勢。 方法的實作應該在 上UITableView呼叫 DeleteRows ,讓單元格消失,同時從模型中移除基礎數據(例如,陣列、字典或資料庫)。
  • CanEditRow – 如果覆寫 CommitEditingStyle,則會假設所有數據列都可以編輯。 如果實作此方法並傳回 false (針對某些特定數據列,或針對所有數據列),則撥動到刪除手勢將無法在該單元格中使用。
  • TitleForDeleteConfirmation – 選擇性地指定 [刪除] 按鈕的文字。 如果未實作這個方法,按鈕文字將會是 “Delete”。

這些方法會在 類別中 TableSource 實作,如下所示:

public override void CommitEditingStyle (UITableView tableView, UITableViewCellEditingStyle editingStyle, Foundation.NSIndexPath indexPath)
{
    switch (editingStyle) {
        case UITableViewCellEditingStyle.Delete:
            // remove the item from the underlying data source
            tableItems.RemoveAt(indexPath.Row);
            // delete the row from the table
            tableView.DeleteRows (new NSIndexPath[] { indexPath }, UITableViewRowAnimation.Fade);
            break;
        case UITableViewCellEditingStyle.None:
            Console.WriteLine ("CommitEditingStyle:None called");
            break;
    }
}
public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
    return true; // return false if you wish to disable editing for a specific indexPath or for all rows
}
public override string TitleForDeleteConfirmation (UITableView tableView, NSIndexPath indexPath)
{   // Optional - default text is 'Delete'
    return "Trash (" + tableItems[indexPath.Row].SubHeading + ")";
}

在此範例中, UITableViewSource 已更新 為使用 List<TableItem> (而不是字串陣列)做為數據源,因為它支援從集合新增和刪除專案。

編輯模式

當數據表處於編輯模式時,使用者在每個數據列上看到紅色的「停止」小工具,這會在觸控時顯示 [刪除] 按鈕。 數據表也會顯示「句柄」圖示,表示可以拖曳數據列以變更順序。 TableEditMode 範例會實作這些功能,如下所示。

TableEditMode 範例會實作這些功能,如下所示

有許多不同的方法 UITableViewSource 會影響數據表的編輯模式行為:

  • CanEditRow – 是否可以編輯每個資料列。 傳回 false,以防止在編輯模式中同時進行撥動刪除和刪除。
  • CanMoveRow – 傳回 true 以啟用移動 'handle' 或 false 以防止移動。
  • EditingStyleForRow – 當數據表處於編輯模式時,這個方法的傳回值會決定單元格是否顯示紅色刪除圖示或綠色新增圖示。 如果無法編輯資料列,則傳回 UITableViewCellEditingStyle.None
  • MoveRow – 移動數據列時呼叫,以便修改基礎數據結構以符合數據表中顯示的數據。

前三個方法的實作相對直接 – 除非您想要使用 indexPath 來變更特定數據列的行為,而只是硬式編碼整個數據表的傳回值。

public override bool CanEditRow (UITableView tableView, NSIndexPath indexPath)
{
    return true; // return false if you wish to disable editing for a specific indexPath or for all rows
}
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
{
    return true; // return false if you don't allow re-ordering
}
public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
    return UITableViewCellEditingStyle.Delete; // this example doesn't support Insert
}

實作 MoveRow 稍微複雜一點,因為它需要改變基礎數據結構以符合新的順序。 因為數據會實作為 List 下列程式代碼,所以會在舊位置刪除數據項,並將其插入新位置。 如果數據儲存在具有「訂單」數據行的 SQLite 資料庫數據表中(例如),這個方法會改為執行一些 SQL 作業,以重新排序該數據行中的數位。

public override void MoveRow (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
{
    var item = tableItems[sourceIndexPath.Row];
    var deleteAt = sourceIndexPath.Row;
    var insertAt = destinationIndexPath.Row;

    // are we inserting
    if (destinationIndexPath.Row < sourceIndexPath.Row) {
        // add one to where we delete, because we're increasing the index by inserting
        deleteAt += 1;
    } else {
        // add one to where we insert, because we haven't deleted the original yet
        insertAt += 1;
    }
    tableItems.Insert (insertAt, item);
    tableItems.RemoveAt (deleteAt);
}

最後,若要讓數據表進入編輯模式,[ 編輯 ] 按鈕必須呼叫 SetEditing 如下

table.SetEditing (true, true);

當使用者完成編輯時,[ 完成 ] 按鈕應該關閉編輯模式:

table.SetEditing (false, true);

數據列插入編輯樣式

數據表內的數據列插入是常見的使用者介面, 標準 iOS 應用程式中的主要範例是 [編輯連絡人 ] 畫面。 此螢幕快照顯示數據列插入功能的運作方式 – 在編輯模式中,有一個額外的數據列(按兩下時)會將其他資料列插入數據中。 編輯完成時,會移除暫存 (新增) 數據列。

編輯完成時,會移除暫時新增數據列

有許多不同的方法 UITableViewSource 會影響數據表的編輯模式行為。 這些方法已在範例程式代碼中實作如下:

  • EditingStyleForRow – 傳 UITableViewCellEditingStyle.Delete 回包含數據的數據列,並傳 UITableViewCellEditingStyle.Insert 回最後一個數據列(特別要新增為做為插入按鈕的行為)。
  • CustomizeMoveTarget – 當用戶移動單元格時,這個選擇性方法的傳回值可以覆寫其選擇的位置。 這表示您可以防止它們在特定位置「卸除」單元格,例如此範例可防止在 (新增) 數據列之後移動任何數據列。
  • CanMoveRow – 傳回 true 以啟用移動 'handle' 或 false 以防止移動。 在此範例中,最後一個數據列會隱藏移動 『handle』,因為它僅供伺服器作為插入按鈕。

我們也新增兩個自定義方法以新增 『insert』 數據列,然後在不再需要時再次移除它。 它們會從 [ 編輯 ] 和 [完成 ] 按鈕呼叫:

  • WillBeginTableEditing – 當觸控 [編輯] 按鈕時,它會呼叫 SetEditing 以將數據表置於編輯模式。 這會觸發WillBeginTableEditing方法,我們在數據表結尾顯示 [新增] 資料列,以做為 「插入按鈕」。
  • DidFinishTableEditing – 再次呼叫 [ SetEditing 完成] 按鈕以關閉編輯模式時。 當不再需要編輯時,此範例程式代碼會 從數據表中移除 (add new) 數據列。

這些方法覆寫會實作於範例檔案 TableEditModeAdd/Code/TableSource.cs

public override UITableViewCellEditingStyle EditingStyleForRow (UITableView tableView, NSIndexPath indexPath)
{
    if (tableView.Editing) {
        if (indexPath.Row == tableView.NumberOfRowsInSection (0) - 1)
            return UITableViewCellEditingStyle.Insert;
        else
            return UITableViewCellEditingStyle.Delete;
    } else // not in editing mode, enable swipe-to-delete for all rows
        return UITableViewCellEditingStyle.Delete;
}
public override NSIndexPath CustomizeMoveTarget (UITableView tableView, NSIndexPath sourceIndexPath, NSIndexPath proposedIndexPath)
{
    var numRows = tableView.NumberOfRowsInSection (0) - 1; // less the (add new) one
    if (proposedIndexPath.Row >= numRows)
        return NSIndexPath.FromRowSection(numRows - 1, 0);
    else
        return proposedIndexPath;
}
public override bool CanMoveRow (UITableView tableView, NSIndexPath indexPath)
{
    return indexPath.Row < tableView.NumberOfRowsInSection (0) - 1;
}

開啟或停用資料表編輯模式時,會使用這兩種自定義方法來新增和移除 (add new) 資料列:

public void WillBeginTableEditing (UITableView tableView)
{
    tableView.BeginUpdates ();
    // insert the 'ADD NEW' row at the end of table display
    tableView.InsertRows (new NSIndexPath[] {
            NSIndexPath.FromRowSection (tableView.NumberOfRowsInSection (0), 0)
        }, UITableViewRowAnimation.Fade);
    // create a new item and add it to our underlying data (it is not intended to be permanent)
    tableItems.Add (new TableItem ("(add new)"));
    tableView.EndUpdates (); // applies the changes
}
public void DidFinishTableEditing (UITableView tableView)
{
    tableView.BeginUpdates ();
    // remove our 'ADD NEW' row from the underlying data
    tableItems.RemoveAt ((int)tableView.NumberOfRowsInSection (0) - 1); // zero based :)
    // remove the row from the table display
    tableView.DeleteRows (new NSIndexPath[] { NSIndexPath.FromRowSection (tableView.NumberOfRowsInSection (0) - 1, 0) }, UITableViewRowAnimation.Fade);
    tableView.EndUpdates (); // applies the changes
}

最後,此程式代碼會具現化 [編輯 ] 和 [完成 ] 按鈕,而 Lambda 會在觸碰時啟用或停用編輯模式:

done = new UIBarButtonItem(UIBarButtonSystemItem.Done, (s,e)=>{
    table.SetEditing (false, true);
    NavigationItem.RightBarButtonItem = edit;
    tableSource.DidFinishTableEditing(table);
});
edit = new UIBarButtonItem(UIBarButtonSystemItem.Edit, (s,e)=>{
    if (table.Editing)
        table.SetEditing (false, true); // if we've half-swiped a row
    tableSource.WillBeginTableEditing(table);
    table.SetEditing (true, true);
    NavigationItem.LeftBarButtonItem = null;
    NavigationItem.RightBarButtonItem = done;
});

此數據列插入UI模式不會經常使用,不過您也可以使用 UITableView.BeginUpdatesEndUpdates 方法,以動畫顯示任何數據表中儲存格的插入或移除。 使用這些方法的規則是 和呼叫之間BeginUpdatesEndUpdatesRowsInSection回的值差異必須與 和 DeleteRows 方法新增/刪除InsertRows的儲存格淨數目相符。 如果基礎數據源未變更以符合數據表檢視上的插入/刪除,則會發生錯誤。