Remplissage d’une table avec des données dans Xamarin.iOS
Pour ajouter des lignes à une UITableView
sous-classe, vous devez implémenter une UITableViewSource
sous-classe et remplacer les méthodes que l’affichage table appelle pour remplir lui-même.
Ce guide couvre les points suivants :
- Sous-classe d’un UITableViewSource
- Réutilisation des cellules
- Ajout d’un index
- Ajout d’en-têtes et de pieds de page
Sous-classe UITableViewSource
Une UITableViewSource
sous-classe est affectée à chaque UITableView
. La vue table interroge la classe source pour déterminer comment se rendre (par exemple, le nombre de lignes requises et la hauteur de chaque ligne si elle est différente de la valeur par défaut). Plus important encore, la source fournit chaque vue de cellule remplie de données.
Il n’existe que deux méthodes obligatoires pour créer des données d’affichage de table :
- RowsInSection : retourne un
nint
nombre total de lignes de données que la table doit afficher. - GetCell : retourne un
UITableViewCell
remplissage avec des données pour l’index de ligne correspondant passé à la méthode.
L’exemple de fichier BasicTable TableSource.cs a l’implémentation la plus simple possible de UITableViewSource
. Vous pouvez voir dans l’extrait de code ci-dessous qu’il accepte un tableau de chaînes à afficher dans le tableau et retourne un style de cellule par défaut contenant chaque chaîne :
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;
}
}
Un UITableViewSource
peut utiliser n’importe quelle structure de données, d’un tableau de chaînes simple (comme illustré dans cet exemple) à une liste ou à une <> autre collection. L’implémentation de méthodes isole la table de la structure de UITableViewSource
données sous-jacente.
Pour utiliser cette sous-classe, créez un tableau de chaînes pour construire la source, puis affectez-la à une instance de 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);
}
La table résultante ressemble à ceci :
La plupart des tables permettent à l’utilisateur de toucher une ligne pour la sélectionner et d’effectuer une autre action (par exemple, lire une chanson ou appeler un contact ou afficher un autre écran). Pour ce faire, il y a quelques choses que nous devons faire. Tout d’abord, nous allons créer un AlertController pour afficher un message lorsque l’utilisateur clique sur une ligne en ajoutant ce qui suit à la RowSelected
méthode :
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);
}
Ensuite, créez une instance de notre contrôleur de vue :
HomeScreen owner;
Ajoutez un constructeur à votre classe UITableViewSource qui prend un contrôleur de vue en tant que paramètre et l’enregistre dans un champ :
public TableSource (string[] items, HomeScreen owner)
{
...
this.owner = owner;
}
Modifiez la méthode ViewDidLoad où la classe UITableViewSource est créée pour passer la this
référence :
table.Source = new TableSource(tableItems, this);
Enfin, de retour dans votre RowSelected
méthode, appelez PresentViewController
le champ mis en cache :
public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
...
owner.PresentViewController (okAlertController, true, null);
...
}
À présent, l’utilisateur peut toucher une ligne et une alerte s’affiche :
Réutilisation des cellules
Dans cet exemple, il n’y a que six éléments. Il n’y a donc aucune réutilisation de cellule requise. Toutefois, lors de l’affichage de centaines ou de milliers de lignes, il s’agirait d’un gaspillage de mémoire pour créer des centaines ou des milliers d’objets UITableViewCell
lorsqu’il n’y en a que quelques-uns sur l’écran à la fois.
Pour éviter cette situation, lorsqu’une cellule disparaît de l’écran, son affichage est placé dans une file d’attente pour réutilisation. À mesure que l’utilisateur défile, le tableau appelle GetCell
pour demander de nouvelles vues à afficher : pour réutiliser une cellule existante (qui n’est pas actuellement affichée), appelez simplement la DequeueReusableCell
méthode. Si une cellule est disponible pour la réutilisation, elle est retournée, sinon une valeur Null est retournée et votre code doit créer une instance de cellule.
Cet extrait de code de l’exemple illustre le modèle :
// 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);
Les cellIdentifier
files d’attente distinctes sont créées pour différents types de cellules. Dans cet exemple, toutes les cellules ressemblent de sorte qu’un seul identificateur codé en dur est utilisé. S’il existe différents types de cellules, ils doivent chacun avoir une chaîne d’identificateur différente, à la fois lorsqu’ils sont instanciés et quand ils sont demandés à partir de la file d’attente de réutilisation.
Réutilisation des cellules dans iOS 6+
iOS 6 a ajouté un modèle de réutilisation de cellule similaire à l’introduction avec les vues de collection. Bien que le modèle de réutilisation existant indiqué ci-dessus soit toujours pris en charge pour la compatibilité descendante, ce nouveau modèle est préférable, car il supprime la nécessité de la case activée Null sur la cellule.
Avec le nouveau modèle, une application inscrit la classe de cellule ou xib à utiliser en appelant ou RegisterClassForCellReuse
RegisterNibForCellReuse
dans le constructeur du contrôleur. Ensuite, lors de la mise en file d’attente de la cellule dans la GetCell
méthode, appelez DequeueReusableCell
simplement le passage de l’identificateur que vous avez inscrit pour la classe de cellule ou xib et le chemin d’accès à l’index.
Par exemple, le code suivant inscrit une classe de cellule personnalisée dans un UITableViewController :
public class MyTableViewController : UITableViewController
{
static NSString MyCellId = new NSString ("MyCellId");
public MyTableViewController ()
{
TableView.RegisterClassForCellReuse (typeof(MyCell), MyCellId);
}
...
}
Avec la classe MyCell inscrite, la cellule peut être mise en file d’attente dans la GetCell
méthode du UITableViewSource
case activée null supplémentaire, comme indiqué ci-dessous :
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;
}
}
N’oubliez pas que lorsque vous utilisez le nouveau modèle de réutilisation avec une classe de cellule personnalisée, vous devez implémenter le constructeur qui accepte un IntPtr
, comme indiqué dans l’extrait de code ci-dessous, sinon Objective-C , ne pourra pas construire une instance de la classe de cellule :
public class MyCell : UITableViewCell
{
public MyCell (IntPtr p):base(p)
{
}
...
}
Vous pouvez voir des exemples des rubriques décrites ci-dessus dans l’exemple BasicTable lié à cet article.
Ajout d’un index
Un index aide l’utilisateur à parcourir de longues listes, généralement classés par ordre alphabétique, bien que vous puissiez indexer selon les critères souhaités. L’exemple BasicTableIndex charge une liste beaucoup plus longue d’éléments d’un fichier pour illustrer l’index. Chaque élément de l’index correspond à une « section » de la table.
Pour prendre en charge les « sections » les données derrière la table doivent être regroupées, l’exemple BasicTableIndex crée donc un Dictionary<>
tableau de chaînes à l’aide de la première lettre de chaque élément comme clé de dictionnaire :
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 ();
La UITableViewSource
sous-classe a ensuite besoin des méthodes suivantes ajoutées ou modifiées pour utiliser :Dictionary<>
- NumberOfSections : cette méthode est facultative, par défaut, la table suppose une section. Lors de l’affichage d’un index, cette méthode doit retourner le nombre d’éléments dans l’index (par exemple, 26 si l’index contient toutes les lettres de l’alphabet anglais).
- RowsInSection : retourne le nombre de lignes d’une section donnée.
- SectionIndexTitles : retourne le tableau de chaînes qui seront utilisées pour afficher l’index. L’exemple de code retourne un tableau de lettres.
Les méthodes mises à jour dans l’exemple de fichier BasicTableIndex/TableSource.cs ressemblent à ceci :
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;
}
Les index sont généralement utilisés uniquement avec le style de table plain.
Ajout d’en-têtes et de pieds de page
Les en-têtes et les pieds de page peuvent être utilisés pour regrouper visuellement des lignes dans une table. La structure de données requise est très similaire à l’ajout d’un index.Dictionary<>
Au lieu d’utiliser l’alphabet pour regrouper les cellules, cet exemple regroupe les légumes par type botanique.
Une sortie classique ressemble à ceci :
Pour afficher les en-têtes et pieds de page de la UITableViewSource
sous-classe, ces méthodes supplémentaires sont nécessaires :
- TitleForHeader : retourne le texte à utiliser comme en-tête
- TitleForFooter : retourne le texte à utiliser comme pied de page.
Les méthodes mises à jour dans l’exemple de fichier BasicTableHeaderFooter/Code/TableSource.cs ressemblent à ceci :
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";
}
Vous pouvez personnaliser davantage l’apparence de l’en-tête et du pied de page avec un objet View, à l’aide des remplacements de méthode GetViewForHeader
et GetViewForFooter
des remplacements sur UITableViewSource
.