Modifica di tabelle con Xamarin.iOS
Le funzionalità di modifica delle tabelle sono abilitate eseguendo l'override dei metodi in una UITableViewSource
sottoclasse. Il comportamento di modifica più semplice è il movimento swipe-to-delete che può essere implementato con un unico override del metodo.
La modifica più complessa (incluse le righe in movimento) può essere eseguita con la tabella in modalità di modifica.
Scorrimento rapido per eliminare
La funzionalità di scorrimento rapido per eliminare è un gesto naturale in iOS previsto dagli utenti.
Esistono tre override del metodo che influiscono sul movimento di scorrimento rapido per visualizzare un pulsante Elimina in una cella:
- CommitEditingStyle : l'origine della tabella rileva se questo metodo viene sottoposto a override e abilita automaticamente il movimento swipe-to-delete. L'implementazione del metodo deve chiamare
DeleteRows
suUITableView
per far scomparire le celle e rimuovere anche i dati sottostanti dal modello, ad esempio una matrice, un dizionario o un database. - CanEditRow : se CommitEditingStyle è sottoposto a override, si presuppone che tutte le righe siano modificabili. Se questo metodo viene implementato e restituisce false (per alcune righe specifiche o per tutte le righe), il gesto swipe-to-delete non sarà disponibile in tale cella.
- TitleForDeleteConfirmation : specifica facoltativamente il testo per il pulsante Elimina . Se questo metodo non viene implementato, il testo del pulsante sarà "Delete".
Questi metodi vengono implementati nella TableSource
classe seguente:
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 + ")";
}
Per questo esempio l'oggetto UITableViewSource
è stato aggiornato in modo da usare (anziché una List<TableItem>
matrice di stringhe) come origine dati perché supporta l'aggiunta e l'eliminazione di elementi dalla raccolta.
Modalità Modifica
Quando una tabella è in modalità di modifica, l'utente vede un widget rosso "stop" su ogni riga, che rivela un pulsante Elimina quando viene toccato. Nella tabella viene inoltre visualizzata un'icona "handle" per indicare che la riga può essere trascinata per modificare l'ordine. L'esempio TableEditMode implementa queste funzionalità come illustrato.
Esistono diversi metodi su UITableViewSource
cui influiscono sul comportamento della modalità di modifica di una tabella:
- CanEditRow : indica se ogni riga può essere modificata. Restituisce false per impedire l'eliminazione e l'eliminazione tramite scorrimento rapido durante la modalità di modifica.
- CanMoveRow : restituisce true per abilitare lo spostamento 'handle' o false per impedire lo spostamento.
- EditingStyleForRow : quando la tabella è in modalità di modifica, il valore restituito da questo metodo determina se la cella visualizza l'icona di eliminazione rossa o l'icona di aggiunta verde. Restituisce
UITableViewCellEditingStyle.None
se la riga non deve essere modificabile. - MoveRow : chiamato quando viene spostata una riga in modo che la struttura di dati sottostante possa essere modificata in modo che corrisponda ai dati visualizzati nella tabella.
L'implementazione per i primi tre metodi è relativamente semplice, a meno che non si voglia usare indexPath
per modificare il comportamento di righe specifiche, è sufficiente impostare come hardcode i valori restituiti per l'intera tabella.
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
}
L'implementazione MoveRow
è leggermente più complessa perché deve modificare la struttura dei dati sottostante in modo che corrisponda al nuovo ordine. Poiché i dati vengono implementati come List
codice seguente elimina l'elemento di dati nella posizione precedente e lo inserisce nella nuova posizione. Se i dati sono stati archiviati in una tabella di database SQLite con una colonna "order", ad esempio, questo metodo dovrà eseguire alcune operazioni SQL per riordinare i numeri in tale colonna.
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);
}
Infine, per ottenere la tabella in modalità di modifica, il pulsante Modifica deve chiamare SetEditing
come questo
table.SetEditing (true, true);
e al termine della modifica dell'utente, il pulsante Fine dovrebbe disattivare la modalità di modifica:
table.SetEditing (false, true);
Stile di modifica inserimento righe
L'inserimento di righe dall'interno della tabella è un'interfaccia utente non comune. L'esempio principale nelle app iOS standard è la schermata Modifica contatto . Questo screenshot mostra come funziona la funzionalità di inserimento delle righe, in modalità di modifica è presente una riga aggiuntiva che, quando si fa clic, inserisce righe aggiuntive nei dati. Al termine della modifica, la riga temporanea (aggiunta nuova) viene rimossa.
Esistono diversi metodi che influiscono sul UITableViewSource
comportamento della modalità di modifica di una tabella. Questi metodi sono stati implementati come segue nel codice di esempio:
- EditingStyleForRow : restituisce
UITableViewCellEditingStyle.Delete
per le righe contenenti dati e restituisceUITableViewCellEditingStyle.Insert
per l'ultima riga (che verrà aggiunta specificamente per comportarsi come pulsante di inserimento). - CustomizeMoveTarget : mentre l'utente sta spostando una cella il valore restituito da questo metodo facoltativo può eseguire l'override della propria posizione. Ciò significa che è possibile impedirgli di eliminare la cella in determinate posizioni, ad esempio questo esempio che impedisce che qualsiasi riga venga spostata dopo la riga (aggiungi nuova).
- CanMoveRow : restituisce true per abilitare lo spostamento 'handle' o false per impedire lo spostamento. Nell'esempio l'ultima riga ha nascosto lo spostamento 'handle' perché è destinato al server solo come pulsante di inserimento.
Vengono inoltre aggiunti due metodi personalizzati per aggiungere la riga 'insert' e quindi rimuoverla di nuovo quando non è più necessario. Vengono chiamati dai pulsanti Modifica e Fine :
- WillBeginTableEditing : quando viene toccato il pulsante Modifica chiama
SetEditing
per mettere la tabella in modalità di modifica. In questo modo viene attivato il metodo WillBeginTableEditing in cui viene visualizzata la riga (aggiungi nuova) alla fine della tabella in modo da fungere da "pulsante di inserimento". - DidFinishTableEditing : quando viene toccato
SetEditing
il pulsante Fine viene chiamato di nuovo per disattivare la modalità di modifica. Il codice di esempio rimuove la riga (aggiungi nuova) dalla tabella quando la modifica non è più necessaria.
Questi override del metodo vengono implementati nel file di esempio 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;
}
Questi due metodi personalizzati vengono usati per aggiungere e rimuovere la riga (aggiungi nuovo) quando la modalità di modifica della tabella è abilitata o disabilitata:
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
}
Infine, questo codice crea un'istanza dei pulsanti Modifica e Fine , con espressioni lambda che abilitano o disabilitano la modalità di modifica quando vengono toccati:
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;
});
Questo modello di interfaccia utente di inserimento di righe non viene usato molto spesso, ma è anche possibile usare i UITableView.BeginUpdates
metodi e EndUpdates
per animare l'inserimento o la rimozione di celle in qualsiasi tabella. La regola per l'uso di questi metodi è che la differenza nel valore restituito da RowsInSection
tra le BeginUpdates
chiamate e EndUpdates
deve corrispondere al numero netto di celle aggiunte/eliminate con i InsertRows
metodi e DeleteRows
. Se l'origine dati sottostante non viene modificata in modo che corrisponda agli inserimenti/eliminazioni nella vista tabella si verificherà un errore.