Úpravy tabulek pomocí Xamarin.iOS

Funkce pro úpravy tabulek jsou povoleny přepsáním metod v podtřídě UITableViewSource . Nejjednodušším chováním při úpravách je gesto potáhnutí prstem na odstranění, které lze implementovat s jedním přepsáním metody. Složitější úpravy (včetně přesouvání řádků) je možné provádět s tabulkou v režimu úprav.

Potáhnutím prstem na odstranění

Funkce odstranění potáhnutím prstem je přirozené gesto v iOSu, které uživatelé očekávají.

Example of Swipe to Delete

Existují tři přepsání metod, které ovlivňují gesto potáhnutí prstem, aby se v buňce zobrazilo tlačítko Odstranit :

  • CommitEditingStyle – Zdroj tabulky zjistí, jestli je tato metoda přepsána a automaticky povolí gesto potáhnutí prstem na odstranění. Implementace metody by měla volat DeleteRowsUITableView , aby buňky zmizely, a také odebrat podkladová data z modelu (například pole, slovník nebo databáze).
  • CanEditRow – Pokud CommitEditingStyle je přepsán, předpokládá se, že všechny řádky budou upravitelné. Pokud je tato metoda implementována a vrací false (pro některé konkrétní řádky nebo pro všechny řádky), gesto potáhnutí prstem na odstranění nebude v této buňce k dispozici.
  • TitleForDeleteConfirmation – Volitelně určuje text tlačítka Odstranit . Pokud tato metoda není implementována, text tlačítka bude "Delete".

Tyto metody jsou implementovány ve TableSource třídě:

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

V tomto příkladu byl aktualizován tak UITableViewSource , aby jako zdroj dat používal ( List<TableItem> místo pole řetězců), protože podporuje přidávání a odstraňování položek z kolekce.

Režim Úpravy

Když je tabulka v režimu úprav, zobrazí se uživateli na každém řádku červený widget Stop, který při dotyku odhalí tlačítko Odstranit. Tabulka také zobrazí ikonu úchytu, která označuje, že řádek lze přetáhnout a změnit pořadí. Ukázka TableEditMode implementuje tyto funkce, jak je znázorněno.

The TableEditMode sample implements these features as shown

Existuje několik různých metod UITableViewSource , které ovlivňují chování režimu úprav tabulky:

  • CanEditRow – zda lze každý řádek upravit. Vrátí hodnotu false, aby se zabránilo odstranění potažením prstem a odstraněním v režimu úprav.
  • CanMoveRow – vrátí hodnotu true, aby bylo možné povolit přesunutí popisovač nebo false, aby se zabránilo přesunutí.
  • EditingStyleForRow – pokud je tabulka v režimu úprav, návratová hodnota z této metody určuje, zda buňka zobrazuje červenou ikonu odstranění nebo zelenou ikonu přidat. Pokud by řádek neměl být upravitelný, vraťte UITableViewCellEditingStyle.None se.
  • MoveRow – volá se při přesunutí řádku tak, aby byla podkladová datová struktura upravena tak, aby odpovídala datům zobrazeným v tabulce.

Implementace prvních tří metod je relativně jednoduchá – pokud nechcete použít indexPath ke změně chování konkrétních řádků, stačí pevně zakódovat návratové hodnoty pro celou tabulku.

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
}

Implementace MoveRow je trochu složitější, protože potřebuje změnit podkladovou datovou strukturu tak, aby odpovídala novému pořadí. Vzhledem k tomu, že se data implementují jako List kód níže, odstraní položku dat ve starém umístění a vloží je do nového umístění. Pokud byla data uložená v tabulce databáze SQLite se sloupcem order (například), tato metoda by místo toho potřebovala provést některé operace SQL, aby se čísla v tomto sloupci přeuspořádala.

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

Nakonec, aby se tabulka dostala do režimu úprav, musí tlačítko Upravit volat SetEditing takto:

table.SetEditing (true, true);

a po dokončení úprav by mělo být vypnuto tlačítko Hotovo :

table.SetEditing (false, true);

Styl úprav vložení řádku

Vložení řádku z tabulky je neobvyklé uživatelské rozhraní – hlavním příkladem standardních aplikací pro iOS je obrazovka Upravit kontakt . Tento snímek obrazovky ukazuje, jak funguje funkce vložení řádku – v režimu úprav je další řádek, který (po kliknutí) vloží do dat další řádky. Po dokončení úprav se odebere dočasný (přidat nový) řádek.

When editing is complete, the temporary add new row is removed

Existuje řada různých metod UITableViewSource , které ovlivňují chování režimu úprav tabulky. Tyto metody byly v ukázkovém kódu implementovány následujícím způsobem:

  • EditingStyleForRow – vrátí řádky UITableViewCellEditingStyle.Delete obsahující data a vrátí UITableViewCellEditingStyle.Insert se pro poslední řádek (který se přidá speciálně pro chování jako tlačítko vložení).
  • CustomizeMoveTarget – Zatímco uživatel přesouvá buňku návratovou hodnotu z této volitelné metody může přepsat svou volbu umístění. To znamená, že můžete zabránit tomu, aby buňky v určitých pozicích vyřadily – například v tomto příkladu, které brání přesunutí libovolného řádku za řádkem (přidat nový).
  • CanMoveRow – vrátí hodnotu true, aby bylo možné povolit přesunutí popisovač nebo false, aby se zabránilo přesunutí. V tomto příkladu má poslední řádek skrytý popisovač, protože je určený jenom jako tlačítko pro vložení.

Přidáme také dvě vlastní metody pro přidání řádku Insert a potom ho znovu odebereme, pokud už není potřeba. Volají se z tlačítek Upravit a Hotovo :

  • WillBeginTableEditing – Když se dotknete tlačítka Upravit , zavolá SetEditing se tabulka do režimu úprav. Tím se aktivuje Metoda WillBeginTableEditing, kde na konci tabulky zobrazíme (přidat nový) řádek, který bude fungovat jako tlačítko vložit.
  • DidFinishTableEditing – Po stisknutí SetEditing tlačítka Hotovo se znovu zavolá, aby se vypnul režim úprav. Ukázkový kód odebere řádek (přidat nový) z tabulky, když už není potřeba upravovat.

Tyto přepsání metod se implementují v ukázkovém souboru 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;
}

Tyto dvě vlastní metody slouží k přidání a odebrání řádku (přidání nového) řádku, když je režim úprav tabulky povolený nebo zakázaný:

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
}

Nakonec tento kód vytvoří instanci tlačítek Upravit a Hotovo s lambdami, které povolí nebo zakáže režim úprav, když se dotknete:

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

Tento vzor uživatelského rozhraní pro vložení řádku se moc často nepoužívá, ale můžete je použít UITableView.BeginUpdatesEndUpdates také k animaci vložení nebo odebrání buněk v libovolné tabulce. Pravidlo pro použití těchto metod spočívá v tom, že rozdíl v hodnotě vrácené mezi voláními RowsInSection a EndUpdates volání musí odpovídat čistému počtu buněk přidaných nebo odstraněných pomocí InsertRows metod a DeleteRows metod.BeginUpdates Pokud se podkladový zdroj dat nezmění tak, aby odpovídal vložením nebo odstraněním v zobrazení tabulky, dojde k chybě.