Partager via


Vues de collection dans Xamarin.iOS

Les vues de collection permettent d’afficher du contenu à l’aide de dispositions arbitraires. Ils permettent de créer facilement des dispositions de type grille hors de la boîte, tout en prenant en charge les dispositions personnalisées.

Les vues de collection, disponibles dans la classe, sont un nouveau concept dans iOS 6 qui présente plusieurs éléments à l’écran UICollectionView à l’aide de dispositions. Les modèles permettant de fournir des données à un UICollectionView pour créer des éléments et interagir avec ces éléments suivent les mêmes modèles de délégation et de source de données couramment utilisés dans le développement iOS.

Toutefois, les vues de collection fonctionnent avec un sous-système de disposition indépendant de celui-ci UICollectionView . Par conséquent, il suffit de fournir une autre disposition pour modifier facilement la présentation d’un affichage collection.

iOS fournit une classe de disposition appelée UICollectionViewFlowLayout qui permet à des dispositions basées sur des lignes telles qu’une grille d’être créée sans travail supplémentaire. En outre, des dispositions personnalisées peuvent également être créées pour permettre toute présentation que vous pouvez imaginer.

Principes de base de UICollectionView

La UICollectionView classe est composée de trois éléments différents :

  • Cellules : vues pilotées par les données pour chaque élément
  • Vues supplémentaires : vues pilotées par les données associées à une section.
  • Vues de décoration : vues non pilotées par les données créées par une disposition

Cellules

Les cellules sont des objets qui représentent un élément unique dans le jeu de données présenté par la vue collection. Chaque cellule est une instance de la UICollectionViewCell classe, composée de trois vues différentes, comme illustré dans la figure ci-dessous :

Chaque cellule est composée de trois vues différentes, comme illustré ici

La UICollectionViewCell classe a les propriétés suivantes pour chacune de ces vues :

  • ContentView : cette vue contient le contenu présenté par la cellule. Elle est affichée dans l’ordre de z le plus haut sur l’écran.
  • SelectedBackgroundView : les cellules ont intégré la prise en charge de la sélection. Cette vue est utilisée pour indiquer visuellement qu’une cellule est sélectionnée. Il est affiché juste en dessous du ContentView moment où une cellule est sélectionnée.
  • BackgroundView : les cellules peuvent également afficher un arrière-plan, qui est présenté par le BackgroundView . Cette vue est affichée sous le SelectedBackgroundView .

En définissant la ContentView valeur de sorte qu’il soit plus petit que le BackgroundView et SelectedBackgroundView, il BackgroundView peut être utilisé pour cadrer visuellement le contenu, tandis que celui-ci SelectedBackgroundView s’affiche lorsqu’une cellule est sélectionnée, comme indiqué ci-dessous :

Éléments de cellule différents

Les cellules de la capture d’écran ci-dessus sont créées en hériter UICollectionViewCell et en définissant respectivement les propriétés et BackgroundView les ContentViewSelectedBackgroundView propriétés, comme indiqué dans le code suivant :

public class AnimalCell : UICollectionViewCell
{
        UIImageView imageView;

        [Export ("initWithFrame:")]
        public AnimalCell (CGRect frame) : base (frame)
        {
            BackgroundView = new UIView{BackgroundColor = UIColor.Orange};

            SelectedBackgroundView = new UIView{BackgroundColor = UIColor.Green};

            ContentView.Layer.BorderColor = UIColor.LightGray.CGColor;
            ContentView.Layer.BorderWidth = 2.0f;
            ContentView.BackgroundColor = UIColor.White;
            ContentView.Transform = CGAffineTransform.MakeScale (0.8f, 0.8f);

            imageView = new UIImageView (UIImage.FromBundle ("placeholder.png"));
            imageView.Center = ContentView.Center;
            imageView.Transform = CGAffineTransform.MakeScale (0.7f, 0.7f);

            ContentView.AddSubview (imageView);
        }

        public UIImage Image {
            set {
                imageView.Image = value;
            }
        }
}

Vues supplémentaires

Les vues supplémentaires sont des vues qui présentent des informations associées à chaque section d’un UICollectionView. Comme les cellules, les vues supplémentaires sont pilotées par les données. Là où les cellules présentent les données d’élément d’une source de données, les vues supplémentaires présentent les données de section, telles que les catégories de livres dans une bibliothèque de livres ou le genre de musique dans une bibliothèque de musique.

Par exemple, une vue supplémentaire peut être utilisée pour présenter un en-tête pour une section particulière, comme illustré dans la figure ci-dessous :

Vue supplémentaire utilisée pour présenter un en-tête pour une section particulière, comme indiqué ici

Pour utiliser un affichage supplémentaire, il doit d’abord être inscrit dans la ViewDidLoad méthode :

CollectionView.RegisterClassForSupplementaryView (typeof(Header), UICollectionElementKindSection.Header, headerId);

Ensuite, la vue doit être retournée à l’aide GetViewForSupplementaryElementde , créée à l’aide DequeueReusableSupplementaryViewde , et hérite de UICollectionReusableView. L’extrait de code suivant génère l’élément SupplementView présenté dans la capture d’écran ci-dessus :

public override UICollectionReusableView GetViewForSupplementaryElement (UICollectionView collectionView, NSString elementKind, NSIndexPath indexPath)
        {
            var headerView = (Header)collectionView.DequeueReusableSupplementaryView (elementKind, headerId, indexPath);
            headerView.Text = "Supplementary View";
            return headerView;
        }

Les vues supplémentaires sont plus génériques que les en-têtes et pieds de page. Ils peuvent être positionnés n’importe où dans la vue collection et peuvent être composés de n’importe quelle vue, ce qui rend leur apparence entièrement personnalisable.

Vues de décoration

Les vues de décoration sont des vues purement visuelles qui peuvent être affichées dans un UICollectionView. Contrairement aux cellules et aux vues supplémentaires, elles ne sont pas pilotées par les données. Elles sont toujours créées dans la sous-classe d’une disposition et peuvent ensuite changer en tant que disposition du contenu. Par exemple, un affichage Décoration peut être utilisé pour présenter un affichage d’arrière-plan qui fait défiler le contenu dans le UICollectionViewfichier , comme indiqué ci-dessous :

Vue Décoration avec un arrière-plan rouge

L’extrait de code ci-dessous modifie l’arrière-plan en rouge dans la classe d’exemples CircleLayout :

public class MyDecorationView : UICollectionReusableView
 {
   [Export ("initWithFrame:")]
   public MyDecorationView (CGRect frame) : base (frame)
   {
     BackgroundColor = UIColor.Red;
   }
 }

Source de données

Comme avec d’autres parties d’iOS, telles que UITableView et MKMapView, UICollectionView obtient ses données à partir d’une source de données, qui est exposée dans Xamarin.iOS via la UICollectionViewDataSource classe. Cette classe est chargée de fournir du contenu à ce UICollectionView qui suit :

  • Cellules : retournées par la GetCell méthode.
  • Vues supplémentaires : retournées par la GetViewForSupplementaryElement méthode.
  • Nombre de sections : retournées par la NumberOfSections méthode. La valeur par défaut est 1 si elle n’est pas implémentée.
  • Nombre d’éléments par section : retourné par GetItemsCount méthode.

UICollectionViewController

Pour des raisons pratiques, la UICollectionViewController classe est disponible. Cette option est automatiquement configurée pour être à la fois le délégué, qui est abordé dans la section suivante et la source de données pour sa UICollectionView vue.

Comme avec UITableView, la UICollectionView classe appelle uniquement sa source de données pour obtenir des cellules pour les éléments qui se trouvent à l’écran. Les cellules qui défilent hors de l’écran sont placées dans une file d’attente à des fins de réutilisation, comme l’illustre l’image suivante :

Les cellules qui défilent hors de l’écran sont placées dans une file d’attente pour une réutilisation, comme indiqué ici

La réutilisation des cellules a été simplifiée avec UICollectionView et UITableView. Vous n’avez plus besoin de créer une cellule directement dans la source de données si celle-ci n’est pas disponible dans la file d’attente de réutilisation, car les cellules sont inscrites auprès du système. Si une cellule n’est pas disponible lors de l’appel à la suppression de la file d’attente de la cellule à partir de la file d’attente de réutilisation, iOS la crée automatiquement en fonction du type ou du nib inscrit. La même technique est également disponible pour les vues supplémentaires.

Par exemple, considérez le code suivant qui inscrit la AnimalCell classe :

static NSString animalCellId = new NSString ("AnimalCell");
CollectionView.RegisterClassForCell (typeof(AnimalCell), animalCellId);

Lorsqu’une UICollectionView cellule a besoin d’une cellule, car son élément est à l’écran, il UICollectionView appelle la méthode de sa source de GetCell données. Comme cela fonctionne avec UITableView, cette méthode est chargée de configurer une cellule à partir des données de stockage, qui serait une AnimalCell classe dans ce cas.

Le code suivant montre une implémentation de GetCell celle-ci qui retourne une AnimalCell instance :

public override UICollectionViewCell GetCell (UICollectionView collectionView, Foundation.NSIndexPath indexPath)
{
        var animalCell = (AnimalCell)collectionView.DequeueReusableCell (animalCellId, indexPath);

        var animal = animals [indexPath.Row];

        animalCell.Image = animal.Image;

        return animalCell;
}

L’appel à DequeReusableCell est l’endroit où la cellule sera dé-mise en file d’attente à partir de la file d’attente de réutilisation ou, si une cellule n’est pas disponible dans la file d’attente, créée en fonction du type inscrit dans l’appel à CollectionView.RegisterClassForCell.

Dans ce cas, en inscrivant la AnimalCell classe, iOS crée une nouvelle AnimalCell classe en interne et la retourne lorsqu’un appel à la file d’attente d’une cellule est effectué, après quoi il est configuré avec l’image contenue dans la classe animale et retourné pour l’affichage dans le UICollectionView.

Déléguer

La UICollectionView classe utilise un délégué de type UICollectionViewDelegate pour prendre en charge l’interaction avec le contenu dans le UICollectionView. Cela permet de contrôler les points suivants :

  • Sélection de cellule : détermine si une cellule est sélectionnée.
  • Mise en surbrillance des cellules : détermine si une cellule est en cours de contact.
  • Menus de cellule : menu affiché pour une cellule en réponse à un long mouvement de presse.

Comme avec la source de données, il UICollectionViewController est configuré par défaut comme délégué pour le UICollectionView.

Cellule HighLighting

Lorsqu’une cellule est enfoncée, la cellule passe dans un état mis en surbrillance et elle n’est pas sélectionnée tant que l’utilisateur n’a pas levé son doigt de la cellule. Cela permet une modification temporaire de l’apparence de la cellule avant qu’elle ne soit réellement sélectionnée. Lors de SelectedBackgroundView la sélection, la cellule s’affiche. La figure ci-dessous montre l’état mis en surbrillance juste avant la sélection :

Cette figure montre l’état mis en surbrillance juste avant la sélection

Pour implémenter la mise en surbrillance, les méthodes et ItemUnhighlighted les ItemHighlighted méthodes de l’application UICollectionViewDelegate peuvent être utilisées. Par exemple, le code suivant applique un arrière-plan jaune du moment où ContentView la cellule est mise en surbrillance et un arrière-plan blanc lorsqu’il n’est pas mis en surbrillance, comme illustré dans l’image ci-dessus :

public override void ItemHighlighted (UICollectionView collectionView, NSIndexPath indexPath)
{
        var cell = collectionView.CellForItem(indexPath);
        cell.ContentView.BackgroundColor = UIColor.Yellow;
}

public override void ItemUnhighlighted (UICollectionView collectionView, NSIndexPath indexPath)
{
        var cell = collectionView.CellForItem(indexPath);
        cell.ContentView.BackgroundColor = UIColor.White;
}

Désactivation de la sélection

La sélection est activée par défaut dans UICollectionView. Pour désactiver la sélection, remplacer ShouldHighlightItem et retourner false, comme indiqué ci-dessous :

public override bool ShouldHighlightItem (UICollectionView collectionView, NSIndexPath indexPath)
{
        return false;
}

Lorsque la mise en surbrillance est désactivée, le processus de sélection d’une cellule est également désactivé. En outre, il existe également une ShouldSelectItem méthode qui contrôle directement la sélection, même si elle ShouldHighlightItem est implémentée et retourne false, ShouldSelectItem n’est pas appelée.

ShouldSelectItem permet à la sélection d’être activée ou désactivée sur une base d’élément par élément, lorsqu’elle ShouldHighlightItem n’est pas implémentée. Il permet également la mise en surbrillance sans sélection, si ShouldHighlightItem elle est implémentée et retourne true, tandis que ShouldSelectItem retourne false.

Menus de cellule

Chaque cellule d’une cellule UICollectionView est capable d’afficher un menu qui permet de couper, copier et coller pour être éventuellement pris en charge. Pour créer un menu d’édition sur une cellule :

  1. Remplacez et retournez ShouldShowMenu true si l’élément doit afficher un menu.
  2. Remplacez et retournez CanPerformAction true pour chaque action que l’élément peut effectuer, ce qui sera l’une des opérations couper, copier ou coller.
  3. Remplacez PerformAction la modification, copie de l’opération de collage.

La capture d’écran suivante montre le menu lorsqu’une cellule est longue enfoncée :

Cette capture d’écran montre le menu lorsqu’une cellule est longue enfoncée

Disposition

UICollectionView prend en charge un système de disposition qui permet le positionnement de tous ses éléments, cellules, vues supplémentaires et vues de décoration, pour être géré indépendamment de l’élément UICollectionView lui-même. À l’aide du système de disposition, une application peut prendre en charge des dispositions telles que celle qui ressemble à la grille que nous avons vue dans cet article, ainsi que fournir des dispositions personnalisées.

Principes de base de la disposition

Les dispositions d’une UICollectionView classe sont définies dans une classe qui hérite de UICollectionViewLayout. L’implémentation de disposition est chargée de créer les attributs de disposition pour chaque élément du UICollectionView. Il existe deux façons de créer une disposition :

  • Utilisez le composant intégré UICollectionViewFlowLayout .
  • Fournissez une disposition personnalisée en hériter de UICollectionViewLayout .

Mise en page fluide

La UICollectionViewFlowLayout classe fournit une disposition basée sur des lignes qui convient à l’organisation du contenu dans une grille de cellules comme nous l’avons vu.

Pour utiliser une disposition de flux :

  • Créer une instance de UICollectionViewFlowLayout :
var layout = new UICollectionViewFlowLayout ();
  • Passez l’instance au constructeur du UICollectionView :
simpleCollectionViewController = new SimpleCollectionViewController (layout);

Il s’agit de tout ce qui est nécessaire pour mettre en page le contenu d’une grille. En outre, lorsque l’orientation change, les UICollectionViewFlowLayout handles réorganisent le contenu de manière appropriée, comme indiqué ci-dessous :

Exemple de modifications d’orientation

Ensemble de sections

Pour fournir un espace autour du UIContentView, les dispositions ont une SectionInset propriété de type UIEdgeInsets. Par exemple, le code suivant fournit une mémoire tampon de 50 pixels autour de chaque section de la UIContentView section lorsqu’elle est disposée par un UICollectionViewFlowLayout:

var layout = new UICollectionViewFlowLayout ();
layout.SectionInset = new UIEdgeInsets (50,50,50,50);

Cela entraîne l’espacement autour de la section, comme indiqué ci-dessous :

Espacement autour de la section, comme illustré ici

Sous-classe UICollectionViewFlowLayout

Dans l’édition à utiliser UICollectionViewFlowLayout directement, il peut également être sous-classé pour personnaliser davantage la disposition du contenu le long d’une ligne. Par exemple, cela peut être utilisé pour créer une disposition qui n’encapsule pas les cellules dans une grille, mais crée plutôt une seule ligne avec un effet de défilement horizontal, comme indiqué ci-dessous :

Une seule ligne avec un effet de défilement horizontal

Pour implémenter cela en sous-classe UICollectionViewFlowLayout , vous devez :

  • Initialisation de toutes les propriétés de disposition qui s’appliquent à la disposition elle-même ou à tous les éléments de la disposition dans le constructeur.
  • Substitution , retour de ShouldInvalidateLayoutForBoundsChange true afin que lorsque les limites des UICollectionView modifications, la disposition des cellules sera recalculée. Cela est utilisé dans ce cas, assurez-vous que le code de transformation appliqué à la cellule la plus centrale sera appliqué pendant le défilement.
  • Substitution pour TargetContentOffset que la cellule la plus centrale soit alignée au centre du UICollectionView point de défilement.
  • LayoutAttributesForElementsInRect Substitution pour retourner un tableau de UICollectionViewLayoutAttributes . Chacun UICollectionViewLayoutAttribute contient des informations sur la disposition de l’élément particulier, y compris les propriétés telles que son Center , SizeZIndex et Transform3D .

Le code suivant montre une telle implémentation :

using System;
using CoreGraphics;
using Foundation;
using UIKit;
using CoreGraphics;
using CoreAnimation;

namespace SimpleCollectionView
{
  public class LineLayout : UICollectionViewFlowLayout
  {
    public const float ITEM_SIZE = 200.0f;
    public const int ACTIVE_DISTANCE = 200;
    public const float ZOOM_FACTOR = 0.3f;

    public LineLayout ()
    {
      ItemSize = new CGSize (ITEM_SIZE, ITEM_SIZE);
      ScrollDirection = UICollectionViewScrollDirection.Horizontal;
            SectionInset = new UIEdgeInsets (400,0,400,0);
      MinimumLineSpacing = 50.0f;
    }

    public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
    {
      return true;
    }

    public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
    {
      var array = base.LayoutAttributesForElementsInRect (rect);
            var visibleRect = new CGRect (CollectionView.ContentOffset, CollectionView.Bounds.Size);

      foreach (var attributes in array) {
        if (attributes.Frame.IntersectsWith (rect)) {
          float distance = (float)(visibleRect.GetMidX () - attributes.Center.X);
          float normalizedDistance = distance / ACTIVE_DISTANCE;
          if (Math.Abs (distance) < ACTIVE_DISTANCE) {
            float zoom = 1 + ZOOM_FACTOR * (1 - Math.Abs (normalizedDistance));
            attributes.Transform3D = CATransform3D.MakeScale (zoom, zoom, 1.0f);
            attributes.ZIndex = 1;
          }
        }
      }
      return array;
    }

    public override CGPoint TargetContentOffset (CGPoint proposedContentOffset, CGPoint scrollingVelocity)
    {
      float offSetAdjustment = float.MaxValue;
      float horizontalCenter = (float)(proposedContentOffset.X + (this.CollectionView.Bounds.Size.Width / 2.0));
      CGRect targetRect = new CGRect (proposedContentOffset.X, 0.0f, this.CollectionView.Bounds.Size.Width, this.CollectionView.Bounds.Size.Height);
      var array = base.LayoutAttributesForElementsInRect (targetRect);
      foreach (var layoutAttributes in array) {
        float itemHorizontalCenter = (float)layoutAttributes.Center.X;
        if (Math.Abs (itemHorizontalCenter - horizontalCenter) < Math.Abs (offSetAdjustment)) {
          offSetAdjustment = itemHorizontalCenter - horizontalCenter;
        }
      }
            return new CGPoint (proposedContentOffset.X + offSetAdjustment, proposedContentOffset.Y);
    }

  }
}

Disposition personnalisée

En plus de l’utilisation UICollectionViewFlowLayout, les dispositions peuvent également être entièrement personnalisées en héritent directement de UICollectionViewLayout.

Les méthodes clés à substituer sont les suivantes :

  • PrepareLayout : permet d’effectuer des calculs géométriques initiaux qui seront utilisés tout au long du processus de disposition.
  • CollectionViewContentSize : retourne la taille de la zone utilisée pour afficher le contenu.
  • LayoutAttributesForElementsInRect – Comme dans l’exemple UICollectionViewFlowLayout présenté précédemment, cette méthode est utilisée pour fournir des informations sur la UICollectionView façon de mettre en page chaque élément. Toutefois, contrairement au , lors de la UICollectionViewFlowLayout création d’une disposition personnalisée, vous pouvez positionner les éléments toutefois que vous choisissez.

Par exemple, le même contenu peut être présenté dans une disposition circulaire, comme indiqué ci-dessous :

Disposition personnalisée circulaire comme indiqué ici

La chose puissante sur les dispositions est que pour passer de la disposition de type grille, à une disposition de défilement horizontale, et par la suite à cette disposition circulaire nécessite uniquement la classe de disposition fournie pour être UICollectionView modifiée. Rien dans le UICollectionView, son délégué ou son code source de données change du tout.

Modifications apportées à iOS 9

Dans iOS 9, la vue collection (UICollectionView) prend désormais en charge la réorganisation des éléments hors de la zone en ajoutant un nouveau module de reconnaissance de mouvement par défaut et plusieurs nouvelles méthodes de prise en charge.

À l’aide de ces nouvelles méthodes, vous pouvez facilement implémenter le glisser pour réorganiser dans votre vue collection et avoir la possibilité de personnaliser l’apparence des éléments pendant n’importe quelle étape du processus de réorganisation.

Exemple du processus de réorganisation

Dans cet article, nous allons examiner l’implémentation d’un glisser-à-réorganiser dans une application Xamarin.iOS, ainsi que certaines des autres modifications apportées à iOS 9 au contrôle de vue de collection :

Réorganisation des éléments

Comme indiqué ci-dessus, l’une des modifications les plus importantes apportées à la vue de collection dans iOS 9 a été l’ajout de fonctionnalités de glisser-réorganiser facilement hors de la zone.

Dans iOS 9, le moyen le plus rapide d’ajouter une réorganisation à une vue de collection consiste à utiliser un UICollectionViewController. Le contrôleur de vue collection possède désormais une InstallsStandardGestureForInteractiveMovement propriété, qui ajoute un module de reconnaissance de mouvement standard qui prend en charge le glissement pour réorganiser les éléments de la collection. Étant donné que la valeur par défaut est true, vous devez uniquement implémenter la MoveItem méthode de la UICollectionViewDataSource classe pour prendre en charge la commande glisser-à-réorganiser. Par exemple :

public override void MoveItem (UICollectionView collectionView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
{
  // Reorder our list of items
  ...
}

Exemple de réorganisation simple

Par exemple, démarrez un nouveau projet Xamarin.iOS et modifiez le fichier Main.storyboard . Faites glisser un UICollectionViewController sur l’aire de conception :

Ajout d’un UICollectionViewController

Sélectionnez l’affichage collection (il peut être plus simple de le faire à partir du plan du document). Dans l’onglet Disposition du panneau Propriétés, définissez les tailles suivantes, comme illustré dans la capture d’écran ci-dessous :

  • Taille de cellule : Largeur – 60 | Hauteur – 60
  • Taille de l’en-tête : Largeur – 0 | Hauteur – 0
  • Taille du pied de page : Largeur – 0 | Hauteur – 0
  • Espacement minimal : pour les cellules – 8 | Pour les lignes – 8
  • Ensembles de sections : Top – 16 | Bas – 16 | Gauche – 16 | Droit - 16

Définir les tailles d’affichage collection

Ensuite, modifiez la cellule par défaut :

  • Modifier sa couleur d’arrière-plan en bleu
  • Ajouter une étiquette pour agir comme titre de la cellule
  • Définir l’identificateur de réutilisation sur la cellule

Modifier la cellule par défaut

Ajoutez des contraintes pour maintenir l’étiquette centrée à l’intérieur de la cellule au fur et à mesure qu’elle change de taille :

Dans le Panneau de propriétés de CollectionViewCell et définissez la classe sur TextCollectionViewCell:

Définir la classe sur TextCollectionViewCell

Définissez l’affichage réutilisable de la collection sur Cell:

Définir la vue réutilisable collection sur cellule

Enfin, sélectionnez l’étiquette et nommez-la TextLabel:

nom label TextLabel

Modifiez la TextCollectionViewCell classe et ajoutez les propriétés suivantes :

using System;
using Foundation;
using UIKit;

namespace CollectionView
{
  public partial class TextCollectionViewCell : UICollectionViewCell
  {
    #region Computed Properties
    public string Title {
      get { return TextLabel.Text; }
      set { TextLabel.Text = value; }
    }
    #endregion

    #region Constructors
    public TextCollectionViewCell (IntPtr handle) : base (handle)
    {
    }
    #endregion
  }
}

Ici, la Text propriété de l’étiquette est exposée en tant que titre de la cellule, afin qu’elle puisse être définie à partir du code.

Ajoutez une nouvelle classe C# au projet et appelez-le WaterfallCollectionSource. Modifiez le fichier et faites-le ressembler à ce qui suit :

using System;
using Foundation;
using UIKit;
using System.Collections.Generic;

namespace CollectionView
{
  public class WaterfallCollectionSource : UICollectionViewDataSource
  {
    #region Computed Properties
    public WaterfallCollectionView CollectionView { get; set;}
    public List<int> Numbers { get; set; } = new List<int> ();
    #endregion

    #region Constructors
    public WaterfallCollectionSource (WaterfallCollectionView collectionView)
    {
      // Initialize
      CollectionView = collectionView;

      // Init numbers collection
      for (int n = 0; n < 100; ++n) {
        Numbers.Add (n);
      }
    }
    #endregion

    #region Override Methods
    public override nint NumberOfSections (UICollectionView collectionView) {
      // We only have one section
      return 1;
    }

    public override nint GetItemsCount (UICollectionView collectionView, nint section) {
      // Return the number of items
      return Numbers.Count;
    }

    public override UICollectionViewCell GetCell (UICollectionView collectionView, NSIndexPath indexPath)
    {
      // Get a reusable cell and set {~~it's~>its~~} title from the item
      var cell = collectionView.DequeueReusableCell ("Cell", indexPath) as TextCollectionViewCell;
      cell.Title = Numbers [(int)indexPath.Item].ToString();

      return cell;
    }

    public override bool CanMoveItem (UICollectionView collectionView, NSIndexPath indexPath) {
      // We can always move items
      return true;
    }

    public override void MoveItem (UICollectionView collectionView, NSIndexPath sourceIndexPath, NSIndexPath destinationIndexPath)
    {
      // Reorder our list of items
      var item = Numbers [(int)sourceIndexPath.Item];
      Numbers.RemoveAt ((int)sourceIndexPath.Item);
      Numbers.Insert ((int)destinationIndexPath.Item, item);
    }
    #endregion
  }
}

Cette classe est la source de données de notre vue de collection et fournit les informations pour chaque cellule de la collection. Notez que la MoveItem méthode est implémentée pour autoriser les éléments de la collection à faire glisser de nouveau.

Ajoutez une autre nouvelle classe C# au projet et appelez-le WaterfallCollectionDelegate. Modifiez ce fichier et faites-le ressembler à ce qui suit :

using System;
using Foundation;
using UIKit;
using System.Collections.Generic;

namespace CollectionView
{
  public class WaterfallCollectionDelegate : UICollectionViewDelegate
  {
    #region Computed Properties
    public WaterfallCollectionView CollectionView { get; set;}
    #endregion

    #region Constructors
    public WaterfallCollectionDelegate (WaterfallCollectionView collectionView)
    {

      // Initialize
      CollectionView = collectionView;

    }
    #endregion

    #region Overrides Methods
    public override bool ShouldHighlightItem (UICollectionView collectionView, NSIndexPath indexPath) {
      // Always allow for highlighting
      return true;
    }

    public override void ItemHighlighted (UICollectionView collectionView, NSIndexPath indexPath)
    {
      // Get cell and change to green background
      var cell = collectionView.CellForItem(indexPath);
      cell.ContentView.BackgroundColor = UIColor.FromRGB(183,208,57);
    }

    public override void ItemUnhighlighted (UICollectionView collectionView, NSIndexPath indexPath)
    {
      // Get cell and return to blue background
      var cell = collectionView.CellForItem(indexPath);
      cell.ContentView.BackgroundColor = UIColor.FromRGB(164,205,255);
    }
    #endregion
  }
}

Cela servira de délégué pour notre vue de collection. Les méthodes ont été remplacées pour mettre en surbrillance une cellule lorsque l’utilisateur interagit avec elle dans la vue collection.

Ajoutez une dernière classe C# au projet et appelez-le WaterfallCollectionView. Modifiez ce fichier et faites-le ressembler à ce qui suit :

using System;
using UIKit;
using System.Collections.Generic;
using Foundation;

namespace CollectionView
{
  [Register("WaterfallCollectionView")]
  public class WaterfallCollectionView : UICollectionView
  {

    #region Constructors
    public WaterfallCollectionView (IntPtr handle) : base (handle)
    {
    }
    #endregion

    #region Override Methods
    public override void AwakeFromNib ()
    {
      base.AwakeFromNib ();

      // Initialize
      DataSource = new WaterfallCollectionSource(this);
      Delegate = new WaterfallCollectionDelegate(this);

    }
    #endregion
  }
}

Notez que DataSource et Delegate que nous avons créé ci-dessus sont définis lorsque la vue collection est construite à partir de son storyboard (ou fichier .xib ).

Modifiez à nouveau le fichier Main.storyboard , puis sélectionnez l’affichage collection et basculez vers les propriétés. Définissez la classe sur la classe personnalisée WaterfallCollectionView que nous avons définie ci-dessus :

Enregistrez les modifications que vous avez apportées à l’interface utilisateur et exécutez l’application. Si l’utilisateur sélectionne un élément dans la liste et le fait glisser vers un nouvel emplacement, les autres éléments s’animent automatiquement lorsqu’ils quittent le chemin de l’élément. Lorsque l’utilisateur supprime l’élément dans un nouvel emplacement, il reste à cet emplacement. Par exemple :

Exemple de glisser un élément vers un nouvel emplacement

Utilisation d’un module de reconnaissance de mouvement personnalisé

Dans les cas où vous ne pouvez pas utiliser un UICollectionViewController élément et devez utiliser un élément normal UIViewControllerou si vous souhaitez prendre davantage de contrôle sur le mouvement de glisser-déplacer, vous pouvez créer votre propre module de reconnaissance de mouvement personnalisé et l’ajouter à l’affichage de collection lorsque l’affichage est chargé. Par exemple :

public override void ViewDidLoad ()
{
  base.ViewDidLoad ();

  // Create a custom gesture recognizer
  var longPressGesture = new UILongPressGestureRecognizer ((gesture) => {

    // Take action based on state
    switch(gesture.State) {
    case UIGestureRecognizerState.Began:
      var selectedIndexPath = CollectionView.IndexPathForItemAtPoint(gesture.LocationInView(View));
      if (selectedIndexPath !=null) {
        CollectionView.BeginInteractiveMovementForItem(selectedIndexPath);
      }
      break;
    case UIGestureRecognizerState.Changed:
      CollectionView.UpdateInteractiveMovementTargetPosition(gesture.LocationInView(View));
      break;
    case UIGestureRecognizerState.Ended:
      CollectionView.EndInteractiveMovement();
      break;
    default:
      CollectionView.CancelInteractiveMovement();
      break;
    }

  });

  // Add the custom recognizer to the collection view
  CollectionView.AddGestureRecognizer(longPressGesture);
}

Ici, nous utilisons plusieurs nouvelles méthodes ajoutées à la vue de collection pour implémenter et contrôler l’opération de glissement :

  • BeginInteractiveMovementForItem - Marque le début d’une opération de déplacement.
  • UpdateInteractiveMovementTargetPosition - Est envoyé à mesure que l’emplacement de l’élément est mis à jour.
  • EndInteractiveMovement - Marque la fin d’un déplacement d’élément.
  • CancelInteractiveMovement - Marque l’utilisateur qui annule l’opération de déplacement.

Lorsque l’application est exécutée, l’opération de glisser fonctionne exactement comme le module de reconnaissance de mouvement de glissement par défaut fourni avec la vue collection.

Dispositions personnalisées et réorganisation

Dans iOS 9, plusieurs nouvelles méthodes ont été ajoutées pour fonctionner avec des dispositions glisser-à-réorganiser et personnalisées dans un affichage de collection. Pour explorer cette fonctionnalité, nous allons ajouter une disposition personnalisée à la collection.

Tout d’abord, ajoutez une nouvelle classe C# appelée WaterfallCollectionLayout au projet. Modifiez-le et faites-le ressembler à ce qui suit :

using System;
using Foundation;
using UIKit;
using System.Collections.Generic;
using CoreGraphics;

namespace CollectionView
{
  [Register("WaterfallCollectionLayout")]
  public class WaterfallCollectionLayout : UICollectionViewLayout
  {
    #region Private Variables
    private int columnCount = 2;
    private nfloat minimumColumnSpacing = 10;
    private nfloat minimumInterItemSpacing = 10;
    private nfloat headerHeight = 0.0f;
    private nfloat footerHeight = 0.0f;
    private UIEdgeInsets sectionInset = new UIEdgeInsets(0, 0, 0, 0);
    private WaterfallCollectionRenderDirection itemRenderDirection = WaterfallCollectionRenderDirection.ShortestFirst;
    private Dictionary<nint,UICollectionViewLayoutAttributes> headersAttributes = new Dictionary<nint, UICollectionViewLayoutAttributes>();
    private Dictionary<nint,UICollectionViewLayoutAttributes> footersAttributes = new Dictionary<nint, UICollectionViewLayoutAttributes>();
    private List<CGRect> unionRects = new List<CGRect>();
    private List<nfloat> columnHeights = new List<nfloat>();
    private List<UICollectionViewLayoutAttributes> allItemAttributes = new List<UICollectionViewLayoutAttributes>();
    private List<List<UICollectionViewLayoutAttributes>> sectionItemAttributes = new List<List<UICollectionViewLayoutAttributes>>();
    private nfloat unionSize = 20;
    #endregion

    #region Computed Properties
    [Export("ColumnCount")]
    public int ColumnCount {
      get { return columnCount; }
      set {
        WillChangeValue ("ColumnCount");
        columnCount = value;
        DidChangeValue ("ColumnCount");

        InvalidateLayout ();
      }
    }

    [Export("MinimumColumnSpacing")]
    public nfloat MinimumColumnSpacing {
      get { return minimumColumnSpacing; }
      set {
        WillChangeValue ("MinimumColumnSpacing");
        minimumColumnSpacing = value;
        DidChangeValue ("MinimumColumnSpacing");

        InvalidateLayout ();
      }
    }

    [Export("MinimumInterItemSpacing")]
    public nfloat MinimumInterItemSpacing {
      get { return minimumInterItemSpacing; }
      set {
        WillChangeValue ("MinimumInterItemSpacing");
        minimumInterItemSpacing = value;
        DidChangeValue ("MinimumInterItemSpacing");

        InvalidateLayout ();
      }
    }

    [Export("HeaderHeight")]
    public nfloat HeaderHeight {
      get { return headerHeight; }
      set {
        WillChangeValue ("HeaderHeight");
        headerHeight = value;
        DidChangeValue ("HeaderHeight");

        InvalidateLayout ();
      }
    }

    [Export("FooterHeight")]
    public nfloat FooterHeight {
      get { return footerHeight; }
      set {
        WillChangeValue ("FooterHeight");
        footerHeight = value;
        DidChangeValue ("FooterHeight");

        InvalidateLayout ();
      }
    }

    [Export("SectionInset")]
    public UIEdgeInsets SectionInset {
      get { return sectionInset; }
      set {
        WillChangeValue ("SectionInset");
        sectionInset = value;
        DidChangeValue ("SectionInset");

        InvalidateLayout ();
      }
    }

    [Export("ItemRenderDirection")]
    public WaterfallCollectionRenderDirection ItemRenderDirection {
      get { return itemRenderDirection; }
      set {
        WillChangeValue ("ItemRenderDirection");
        itemRenderDirection = value;
        DidChangeValue ("ItemRenderDirection");

        InvalidateLayout ();
      }
    }
    #endregion

    #region Constructors
    public WaterfallCollectionLayout ()
    {
    }

    public WaterfallCollectionLayout(NSCoder coder) : base(coder) {

    }
    #endregion

    #region Public Methods
    public nfloat ItemWidthInSectionAtIndex(int section) {

      var width = CollectionView.Bounds.Width - SectionInset.Left - SectionInset.Right;
      return (nfloat)Math.Floor ((width - ((ColumnCount - 1) * MinimumColumnSpacing)) / ColumnCount);
    }
    #endregion

    #region Override Methods
    public override void PrepareLayout ()
    {
      base.PrepareLayout ();

      // Get the number of sections
      var numberofSections = CollectionView.NumberOfSections();
      if (numberofSections == 0)
        return;

      // Reset collections
      headersAttributes.Clear ();
      footersAttributes.Clear ();
      unionRects.Clear ();
      columnHeights.Clear ();
      allItemAttributes.Clear ();
      sectionItemAttributes.Clear ();

      // Initialize column heights
      for (int n = 0; n < ColumnCount; n++) {
        columnHeights.Add ((nfloat)0);
      }

      // Process all sections
      nfloat top = 0.0f;
      var attributes = new UICollectionViewLayoutAttributes ();
      var columnIndex = 0;
      for (nint section = 0; section < numberofSections; ++section) {
        // Calculate section specific metrics
        var minimumInterItemSpacing = (MinimumInterItemSpacingForSection == null) ? MinimumColumnSpacing :
          MinimumInterItemSpacingForSection (CollectionView, this, section);

        // Calculate widths
        var width = CollectionView.Bounds.Width - SectionInset.Left - SectionInset.Right;
        var itemWidth = (nfloat)Math.Floor ((width - ((ColumnCount - 1) * MinimumColumnSpacing)) / ColumnCount);

        // Calculate section header
        var heightHeader = (HeightForHeader == null) ? HeaderHeight :
          HeightForHeader (CollectionView, this, section);

        if (heightHeader > 0) {
          attributes = UICollectionViewLayoutAttributes.CreateForSupplementaryView (UICollectionElementKindSection.Header, NSIndexPath.FromRowSection (0, section));
          attributes.Frame = new CGRect (0, top, CollectionView.Bounds.Width, heightHeader);
          headersAttributes.Add (section, attributes);
          allItemAttributes.Add (attributes);

          top = attributes.Frame.GetMaxY ();
        }

        top += SectionInset.Top;
        for (int n = 0; n < ColumnCount; n++) {
          columnHeights [n] = top;
        }

        // Calculate Section Items
        var itemCount = CollectionView.NumberOfItemsInSection(section);
        List<UICollectionViewLayoutAttributes> itemAttributes = new List<UICollectionViewLayoutAttributes> ();

        for (nint n = 0; n < itemCount; n++) {
          var indexPath = NSIndexPath.FromRowSection (n, section);
          columnIndex = NextColumnIndexForItem (n);
          var xOffset = SectionInset.Left + (itemWidth + MinimumColumnSpacing) * (nfloat)columnIndex;
          var yOffset = columnHeights [columnIndex];
          var itemSize = (SizeForItem == null) ? new CGSize (0, 0) : SizeForItem (CollectionView, this, indexPath);
          nfloat itemHeight = 0.0f;

          if (itemSize.Height > 0.0f && itemSize.Width > 0.0f) {
            itemHeight = (nfloat)Math.Floor (itemSize.Height * itemWidth / itemSize.Width);
          }

          attributes = UICollectionViewLayoutAttributes.CreateForCell (indexPath);
          attributes.Frame = new CGRect (xOffset, yOffset, itemWidth, itemHeight);
          itemAttributes.Add (attributes);
          allItemAttributes.Add (attributes);
          columnHeights [columnIndex] = attributes.Frame.GetMaxY () + MinimumInterItemSpacing;
        }
        sectionItemAttributes.Add (itemAttributes);

        // Calculate Section Footer
        nfloat footerHeight = 0.0f;
        columnIndex = LongestColumnIndex();
        top = columnHeights [columnIndex] - MinimumInterItemSpacing + SectionInset.Bottom;
        footerHeight = (HeightForFooter == null) ? FooterHeight : HeightForFooter(CollectionView, this, section);

        if (footerHeight > 0) {
          attributes = UICollectionViewLayoutAttributes.CreateForSupplementaryView (UICollectionElementKindSection.Footer, NSIndexPath.FromRowSection (0, section));
          attributes.Frame = new CGRect (0, top, CollectionView.Bounds.Width, footerHeight);
          footersAttributes.Add (section, attributes);
          allItemAttributes.Add (attributes);
          top = attributes.Frame.GetMaxY ();
        }

        for (int n = 0; n < ColumnCount; n++) {
          columnHeights [n] = top;
        }
      }

      var i =0;
      var attrs = allItemAttributes.Count;
      while(i < attrs) {
        var rect1 = allItemAttributes [i].Frame;
        i = (int)Math.Min (i + unionSize, attrs) - 1;
        var rect2 = allItemAttributes [i].Frame;
        unionRects.Add (CGRect.Union (rect1, rect2));
        i++;
      }

    }

    public override CGSize CollectionViewContentSize {
      get {
        if (CollectionView.NumberOfSections () == 0) {
          return new CGSize (0, 0);
        }

        var contentSize = CollectionView.Bounds.Size;
        contentSize.Height = columnHeights [0];
        return contentSize;
      }
    }

    public override UICollectionViewLayoutAttributes LayoutAttributesForItem (NSIndexPath indexPath)
    {
      if (indexPath.Section >= sectionItemAttributes.Count) {
        return null;
      }

      if (indexPath.Item >= sectionItemAttributes [indexPath.Section].Count) {
        return null;
      }

      var list = sectionItemAttributes [indexPath.Section];
      return list [(int)indexPath.Item];
    }

    public override UICollectionViewLayoutAttributes LayoutAttributesForSupplementaryView (NSString kind, NSIndexPath indexPath)
    {
      var attributes = new UICollectionViewLayoutAttributes ();

      switch (kind) {
      case "header":
        attributes = headersAttributes [indexPath.Section];
        break;
      case "footer":
        attributes = footersAttributes [indexPath.Section];
        break;
      }

      return attributes;
    }

    public override UICollectionViewLayoutAttributes[] LayoutAttributesForElementsInRect (CGRect rect)
    {
      var begin = 0;
      var end = unionRects.Count;
      List<UICollectionViewLayoutAttributes> attrs = new List<UICollectionViewLayoutAttributes> ();

      for (int i = 0; i < end; i++) {
        if (rect.IntersectsWith(unionRects[i])) {
          begin = i * (int)unionSize;
        }
      }

      for (int i = end - 1; i >= 0; i--) {
        if (rect.IntersectsWith (unionRects [i])) {
          end = (int)Math.Min ((i + 1) * (int)unionSize, allItemAttributes.Count);
          break;
        }
      }

      for (int i = begin; i < end; i++) {
        var attr = allItemAttributes [i];
        if (rect.IntersectsWith (attr.Frame)) {
          attrs.Add (attr);
        }
      }

      return attrs.ToArray();
    }

    public override bool ShouldInvalidateLayoutForBoundsChange (CGRect newBounds)
    {
      var oldBounds = CollectionView.Bounds;
      return (newBounds.Width != oldBounds.Width);
    }
    #endregion

    #region Private Methods
    private int ShortestColumnIndex() {
      var index = 0;
      var shortestHeight = nfloat.MaxValue;
      var n = 0;

      // Scan each column for the shortest height
      foreach (nfloat height in columnHeights) {
        if (height < shortestHeight) {
          shortestHeight = height;
          index = n;
        }
        ++n;
      }

      return index;
    }

    private int LongestColumnIndex() {
      var index = 0;
      var longestHeight = nfloat.MinValue;
      var n = 0;

      // Scan each column for the shortest height
      foreach (nfloat height in columnHeights) {
        if (height > longestHeight) {
          longestHeight = height;
          index = n;
        }
        ++n;
      }

      return index;
    }

    private int NextColumnIndexForItem(nint item) {
      var index = 0;

      switch (ItemRenderDirection) {
      case WaterfallCollectionRenderDirection.ShortestFirst:
        index = ShortestColumnIndex ();
        break;
      case WaterfallCollectionRenderDirection.LeftToRight:
        index = ColumnCount;
        break;
      case WaterfallCollectionRenderDirection.RightToLeft:
        index = (ColumnCount - 1) - ((int)item / ColumnCount);
        break;
      }

      return index;
    }
    #endregion

    #region Events
    public delegate CGSize WaterfallCollectionSizeDelegate(UICollectionView collectionView, WaterfallCollectionLayout layout, NSIndexPath indexPath);
    public delegate nfloat WaterfallCollectionFloatDelegate(UICollectionView collectionView, WaterfallCollectionLayout layout, nint section);
    public delegate UIEdgeInsets WaterfallCollectionEdgeInsetsDelegate(UICollectionView collectionView, WaterfallCollectionLayout layout, nint section);

    public event WaterfallCollectionSizeDelegate SizeForItem;
    public event WaterfallCollectionFloatDelegate HeightForHeader;
    public event WaterfallCollectionFloatDelegate HeightForFooter;
    public event WaterfallCollectionEdgeInsetsDelegate InsetForSection;
    public event WaterfallCollectionFloatDelegate MinimumInterItemSpacingForSection;
    #endregion
  }
}

Cette classe peut être utilisée pour fournir une disposition personnalisée de deux colonnes de type cascade à la vue collection. Le code utilise le codage clé-valeur (via les WillChangeValue méthodes) DidChangeValue pour fournir une liaison de données pour nos propriétés calculées dans cette classe.

Ensuite, modifiez et WaterfallCollectionSource apportez les modifications et ajouts suivants :

private Random rnd = new Random();
...

public List<nfloat> Heights { get; set; } = new List<nfloat> ();
...

public WaterfallCollectionSource (WaterfallCollectionView collectionView)
{
  // Initialize
  CollectionView = collectionView;

  // Init numbers collection
  for (int n = 0; n < 100; ++n) {
    Numbers.Add (n);
    Heights.Add (rnd.Next (0, 100) + 40.0f);
  }
}

Cela crée une hauteur aléatoire pour chacun des éléments qui seront affichés dans la liste.

Ensuite, modifiez la WaterfallCollectionView classe et ajoutez la propriété d’assistance suivante :

public WaterfallCollectionSource Source {
  get { return (WaterfallCollectionSource)DataSource; }
}

Cela facilite l’obtention de notre source de données (et des hauteurs d’élément) à partir de la disposition personnalisée.

Enfin, modifiez le contrôleur de vue et ajoutez le code suivant :

public override void AwakeFromNib ()
{
  base.AwakeFromNib ();

  var waterfallLayout = new WaterfallCollectionLayout ();

  // Wireup events
  waterfallLayout.SizeForItem += (collectionView, layout, indexPath) => {
    var collection = collectionView as WaterfallCollectionView;
    return new CGSize((View.Bounds.Width-40)/3,collection.Source.Heights[(int)indexPath.Item]);
  };

  // Attach the custom layout to the collection
  CollectionView.SetCollectionViewLayout(waterfallLayout, false);
}

Cela crée une instance de notre disposition personnalisée, définit l’événement pour fournir la taille de chaque élément et attache la nouvelle disposition à notre vue de collection.

Si nous réexécutons l’application Xamarin.iOS, la vue collection se présente désormais comme suit :

L’affichage collection ressemblera maintenant à ceci

Nous pouvons toujours faire glisser vers réorganiser les éléments comme précédemment, mais les éléments changeront désormais de taille pour s’adapter à leur nouvel emplacement lorsqu’ils sont supprimés.

Modifications apportées à l’affichage collection

Dans les sections suivantes, nous allons examiner en détail les modifications apportées à chaque classe dans l’affichage collection par iOS 9.

UICollectionView

Les modifications ou ajouts suivants ont été apportés à la UICollectionView classe pour iOS 9 :

  • BeginInteractiveMovementForItem : marque le début d’une opération de glissement.
  • CancelInteractiveMovement : informe la vue de collection que l’utilisateur a annulé une opération de glissement.
  • EndInteractiveMovement : informe la vue de collection que l’utilisateur a terminé une opération de glissement.
  • GetIndexPathsForVisibleSupplementaryElements : renvoie l’en-tête ou le indexPath pied de page d’une section d’affichage de collection.
  • GetSupplementaryView : retourne l’en-tête ou le pied de page donné.
  • GetVisibleSupplementaryViews : retourne une liste de tous les en-têtes et pieds de page visibles.
  • UpdateInteractiveMovementTargetPosition : informe l’affichage de collection que l’utilisateur a déplacé ou est en déplacement, un élément pendant une opération de glisser.

UICollectionViewController

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewController classe dans iOS 9 :

  • InstallsStandardGestureForInteractiveMovement : si true le nouveau Module de reconnaissance de mouvement qui prend automatiquement en charge la commande glisser-à-réorganiser sera utilisé.
  • CanMoveItem : informe la vue de collection si un élément donné peut être réorganisé.
  • GetTargetContentOffset : permet d’obtenir le décalage d’un élément d’affichage de collection donné.
  • GetTargetIndexPathForMove : obtient l’élément indexPath donné pour une opération de glissement.
  • MoveItem : déplace l’ordre d’un élément donné dans la liste.

UICollectionViewDataSource

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewDataSource classe dans iOS 9 :

  • CanMoveItem : informe la vue de collection si un élément donné peut être réorganisé.
  • MoveItem : déplace l’ordre d’un élément donné dans la liste.

UICollectionViewDelegate

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewDelegate classe dans iOS 9 :

  • GetTargetContentOffset : permet d’obtenir le décalage d’un élément d’affichage de collection donné.
  • GetTargetIndexPathForMove : obtient l’élément indexPath donné pour une opération de glissement.

UICollectionViewFlowLayout

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewFlowLayout classe dans iOS 9 :

  • SectionFootersPinToVisibleBounds : colle les pieds de page de section aux limites de l’affichage de collection visible.
  • SectionHeadersPinToVisibleBounds : colle les en-têtes de section aux limites de l’affichage de collection visible.

UICollectionViewLayout

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewLayout classe dans iOS 9 :

  • GetInvalidationContextForEndingInteractiveMovementOfItems : retourne le contexte d’invalidation à la fin d’une opération de glisser lorsque l’utilisateur termine le glisser ou l’annule.
  • GetInvalidationContextForInteractivelyMovingItems : retourne le contexte d’invalidation au début d’une opération de glissement.
  • GetLayoutAttributesForInteractivelyMovingItem : obtient les attributs de disposition d’un élément donné lors du glissement d’un élément.
  • GetTargetIndexPathForInteractivelyMovingItem : retourne l’élément indexPath qui se trouve au point donné lors du glissement d’un élément.

UICollectionViewLayoutAttributes

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewLayoutAttributes classe dans iOS 9 :

  • CollisionBoundingPath : retourne le chemin de collision de deux éléments pendant une opération de glissement.
  • CollisionBoundsType : retourne le type de collision (sous la forme d’un UIDynamicItemCollisionBoundsType) qui s’est produite pendant une opération de glissement.

UICollectionViewLayoutInvalidationContext

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewLayoutInvalidationContext classe dans iOS 9 :

  • InteractiveMovementTarget : retourne l’élément cible d’une opération de glissement.
  • PreviousIndexPathsForInteractivelyMovingItems : retourne les indexPaths autres éléments impliqués dans un glisser-déplacer pour réorganiser l’opération.
  • TargetIndexPathsForInteractivelyMovingItems : retourne les indexPaths éléments qui seront réorganisés à la suite d’une opération de glisser-réorganiser.

UICollectionViewSource

Les modifications ou ajouts suivants ont été apportés à la UICollectionViewSource classe dans iOS 9 :

  • CanMoveItem : informe la vue de collection si un élément donné peut être réorganisé.
  • GetTargetContentOffset : retourne les décalages des éléments qui seront déplacés par le biais d’une opération de glisser-réorganiser.
  • GetTargetIndexPathForMove : retourne l’élément indexPath qui sera déplacé pendant une opération de glisser-réorganiser.
  • MoveItem : déplace l’ordre d’un élément donné dans la liste.

Résumé

Cet article a abordé les modifications apportées aux vues de collection dans iOS 9 et décrit comment les implémenter dans Xamarin.iOS. Elle a abordé l’implémentation d’une action de glisser-réorganiser simple dans un affichage de collection ; à l’aide d’un Module de reconnaissance de mouvement personnalisé avec glisser-à-réorganiser ; et comment le glisser-à-réorganiser affecte une disposition d’affichage de collection personnalisée.