Storyboards unifiés dans Xamarin.iOS

iOS 8 inclut un nouveau mécanisme simple à utiliser pour créer l’interface utilisateur , le storyboard unifié. Avec un seul storyboard pour couvrir toutes les différentes tailles d’écran matérielles, des vues rapides et réactives peuvent être créées dans un style « design-once, use-many ».

Comme le développeur n’a plus besoin de créer un storyboard distinct et spécifique pour les appareils i Téléphone et iPad, ils ont la possibilité de concevoir des applications avec une interface commune, puis de personnaliser cette interface pour différentes classes de taille. De cette façon, une application peut être adaptée aux forces de chaque facteur de forme et chaque interface utilisateur peut être paramétrée pour offrir la meilleure expérience.

Classes de taille

Avant iOS 8, le développeur a utilisé UIInterfaceOrientation et UIInterfaceIdiom fait la distinction entre les modes portrait et paysage, et entre les appareils i Téléphone et iPad. Dans iOS8, l’orientation et l’appareil sont déterminés à l’aide de classes de taille.

Les appareils sont définis par les classes de taille, dans les axes verticaux et horizontaux, et il existe deux types de classes de taille dans iOS 8 :

  • Normal : il s’agit d’une grande taille d’écran (par exemple, un iPad) ou d’un gadget qui donne l’impression d’une grande taille (par exemple, un iPad) UIScrollView
  • Compact : il s’agit d’appareils plus petits (tels qu’un i Téléphone). Cette taille prend en compte l’orientation de l’appareil.

Si les deux concepts sont utilisés ensemble, le résultat est une grille de 2 x 2 qui définit les différentes tailles possibles qui peuvent être utilisées dans les deux orientations différentes, comme illustré dans le diagramme suivant :

Grille de 2 x 2 qui définit les différentes tailles possibles qui peuvent être utilisées dans les orientations régulières et compactes

Le développeur peut créer un contrôleur de vue qui utilise l’une des quatre possibilités qui entraîneraient des dispositions différentes (comme indiqué dans les graphiques ci-dessus).

Classes de taille iPad

L’iPad, en raison de la taille, a une taille de classe régulière pour les deux orientations.

Classes de taille iPad

i Téléphone Classes de taille

I Téléphone a différentes classes de taille en fonction de l’orientation de l’appareil :

i Téléphone Classes de taille

  • Lorsque l’appareil est en mode portrait, l’écran a une classe compacte horizontalement et normalement verticalement
  • Lorsque l’appareil est en mode paysage, les classes d’écran sont inversées du mode Portrait.

i Téléphone 6 classes de taille plus

Les tailles sont les mêmes que les i Téléphone antérieures lors de l’orientation portrait, mais différentes dans le paysage :

i Téléphone 6 classes de taille plus

Étant donné que i Téléphone 6 Plus a un écran suffisamment grand, il est en mesure d’avoir une classe de taille de largeur régulière en mode Paysage.

Prise en charge d’une nouvelle échelle d’écran

I Téléphone 6 Plus utilise un nouvel écran Rétine HD avec un facteur d’échelle d’écran de 3,0 (trois fois la résolution d’écran i Téléphone d’origine). Pour offrir la meilleure expérience possible sur ces appareils, incluez de nouvelles illustrations conçues pour cette échelle d’écran. Dans Xcode 6 et versions ultérieures, les catalogues de ressources peuvent inclure des images de taille 1x, 2x et 3x ; ajoutez simplement les nouvelles ressources d’image et iOS choisissez les ressources appropriées lors de l’exécution sur un i Téléphone 6 Plus.

Le comportement de chargement d’image dans iOS reconnaît également un @3x suffixe sur les fichiers image. Par exemple, si le développeur inclut une ressource d’image (à différentes résolutions) dans l’offre groupée de l’application avec les noms de fichiers suivants : MonkeyIcon.png, MonkeyIcon@2x.pnget MonkeyIcon@3x.png. Sur i Téléphone 6 Plus l’image MonkeyIcon@3x.png sera utilisée automatiquement si le développeur charge une image à l’aide du code suivant :

UIImage icon = UIImage.FromFile("MonkeyImage.png");

Écrans de lancement dynamique

Le fichier d’écran de lancement s’affiche sous la forme d’un écran de démarrage pendant qu’une application iOS lance pour fournir des commentaires à l’utilisateur que l’application démarre réellement. Avant iOS 8, le développeur doit inclure plusieurs Default.png ressources d’image pour chaque type d’appareil, orientation et résolution d’écran sur laquelle l’application s’exécuterait.

Nouveautés d’iOS 8, le développeur peut créer un fichier atomique .xib unique dans Xcode qui utilise la disposition automatique et les classes de taille pour créer un écran de lancement dynamique qui fonctionnera pour chaque appareil, résolution et orientation. Cela réduit non seulement la quantité de travail requise par le développeur pour créer et gérer toutes les ressources d’image requises, mais elle réduit la taille de l’offre groupée installée de l’application.

Caractéristiques

Les caractéristiques sont des propriétés qui peuvent être utilisées pour déterminer comment une disposition change à mesure que son environnement change. Ils se composent d’un ensemble de propriétés (le HorizontalSizeClass et basé surUIUserInterfaceSizeClass), ainsi que de l’idiome d’interface (UIUserInterfaceIdiom) et de l’échelle VerticalSizeClass d’affichage.

Tous les états ci-dessus sont encapsulés dans un conteneur auquel Apple fait référence en tant que collection trait (), UITraitCollectionqui contient non seulement les propriétés, mais aussi leurs valeurs.

Environnement de caractéristiques

Les environnements trait sont une nouvelle interface dans iOS 8 et peuvent retourner une collection trait pour les objets suivants :

  • Écrans ( UIScreens ).
  • Windows ( UIWindows ).
  • Afficher les contrôleurs ( UIViewController ).
  • Vues ( UIView ).
  • Presentation Controller ( ). UIPresentationController

Le développeur utilise la collection Trait retournée par un environnement trait pour déterminer comment une interface utilisateur doit être disposée.

Tous les environnements de caractéristiques font une hiérarchie comme indiqué dans le diagramme suivant :

Diagramme de hiérarchie des environnements de caractéristiques

La collection Trait que chacun des environnements trait ci-dessus a été acheminé, par défaut, du parent à l’environnement enfant.

Outre l’obtention de la collection trait actuelle, l’environnement trait a une TraitCollectionDidChange méthode, qui peut être substituée dans les sous-classes View ou View Controller. Le développeur peut utiliser cette méthode pour modifier l’un des éléments d’interface utilisateur qui dépendent des caractéristiques lorsque ces caractéristiques ont changé.

Collections de caractéristiques classiques

Cette section traite des types classiques de collections de caractéristiques que l’utilisateur rencontrera lors de l’utilisation d’iOS 8.

Voici une collection Trait classique que le développeur peut voir sur un i Téléphone :

Propriété Valeur
HorizontalSizeClass Compact
VerticalSizeClass Regular
UserInterfaceIdom votre numéro de
DisplayScale 2.0

L’ensemble ci-dessus représente une collection de caractéristiques complètes, car elle a des valeurs pour toutes ses propriétés de caractéristiques.

Il est également possible d’avoir une collection Trait qui manque certaines de ses valeurs (dont Apple fait référence à Unspecified) :

Propriété Valeur
HorizontalSizeClass Compact
VerticalSizeClass Non spécifié
UserInterfaceIdom Non spécifié
DisplayScale Non spécifié

En règle générale, toutefois, lorsque le développeur demande à Trait Environment pour sa collection Trait, il retourne une collection complète, comme indiqué dans l’exemple ci-dessus.

Si un environnement de caractéristiques (comme un affichage ou un contrôleur de vue) n’est pas à l’intérieur de la hiérarchie d’affichage actuelle, le développeur peut récupérer des valeurs non spécifiées pour une ou plusieurs des propriétés de caractéristiques.

Le développeur obtiendra également une collection Trait partiellement qualifiée s’il utilise l’une des méthodes de création fournies par Apple, telles que UITraitCollection.FromHorizontalSizeClass, pour créer une collection.

Une opération qui peut être effectuée sur plusieurs collections traits consiste à les comparer les unes aux autres, ce qui implique de demander à une collection Trait s’il contient un autre. C’est que, pour toute caractéristique spécifiée dans la deuxième collection, la valeur doit correspondre exactement à la valeur de la première collection.

Pour tester deux caractéristiques, utilisez la Contains méthode de UITraitCollection passage de la valeur de la caractéristique à tester.

Le développeur peut effectuer les comparaisons manuellement dans le code pour déterminer comment mettre en page les vues ou les contrôleurs de vue. Toutefois, UIKit utilise cette méthode en interne pour fournir certaines de ses fonctionnalités, comme dans le proxy d’apparence, par exemple.

Proxy d’apparence

Le proxy d’apparence a été introduit dans les versions antérieures d’iOS pour permettre aux développeurs de personnaliser les propriétés de leurs vues. Il a été étendu dans iOS 8 pour prendre en charge trait Collections.

Les proxys d’apparence incluent désormais une nouvelle méthode, AppearanceForTraitCollectionqui retourne un nouveau proxy d’apparence pour la collection trait donnée qui a été passée. Toutes les personnalisations effectuées par le développeur sur ce proxy d’apparence prennent uniquement effet sur les vues conformes à la collection trait spécifiée.

En règle générale, le développeur transmet une collection trait partiellement spécifiée à la AppearanceForTraitCollection méthode, telle qu’une classe de taille horizontale de Compact, afin qu’elle puisse personnaliser n’importe quelle vue dans l’application compactée horizontalement.

Uiimage

Une autre classe à laquelle Apple a ajouté Trait Collection est UIImage. Dans le passé, le développeur devait spécifier une @1X et @2x version d’une ressource graphique bitmap qu’il allait inclure dans l’application (par exemple, une icône).

iOS 8 a été développé pour permettre au développeur d’inclure plusieurs versions d’une image dans un catalogue d’images basé sur une collection trait. Par exemple, le développeur peut inclure une image plus petite pour l’utilisation d’une classe Trait Compact et d’une image de taille complète pour toute autre collection.

Lorsque l’une des images est utilisée à l’intérieur d’une UIImageView classe, l’affichage Image affiche automatiquement la version correcte de l’image pour sa collection Trait. Si l’environnement trait change (par exemple, l’utilisateur bascule l’appareil du portrait vers le paysage), l’affichage image sélectionne automatiquement la nouvelle taille d’image pour qu’elle corresponde à la nouvelle collection trait et modifie sa taille pour qu’elle corresponde à celle de la version actuelle de l’image affichée.

UIImageAsset

Apple a ajouté une nouvelle classe à iOS 8 appelé UIImageAsset pour donner au développeur encore plus de contrôle sur la sélection d’images.

Une ressource image inclut toutes les différentes versions d’une image et permet au développeur de demander une image spécifique qui correspond à une collection trait qui a été passée. Les images peuvent être ajoutées ou supprimées d’une ressource image, à la volée.

Pour plus d’informations sur les ressources d’image, consultez la documentation UIImageAsset d’Apple.

Combinaison de collections de caractéristiques

Une autre fonction qu’un développeur peut effectuer sur Trait Collections consiste à ajouter deux ensembles qui entraînent la collection combinée, où les valeurs non spécifiées d’une collection sont remplacées par les valeurs spécifiées dans une seconde. Cette opération est effectuée à l’aide de la FromTraitsFromCollections méthode de la UITraitCollection classe.

Comme indiqué ci-dessus, si l’un des traits n’est pas spécifié dans l’une des collections de caractéristiques et est spécifié dans un autre, la valeur est définie sur la version spécifiée. Toutefois, s’il existe plusieurs versions d’une valeur donnée spécifiées, la valeur de la dernière collection trait sera la valeur utilisée.

Contrôleurs d’affichage adaptatif

Cette section décrit les détails de la façon dont les contrôleurs d’affichage et de vue iOS ont adopté les concepts des caractéristiques et des classes de taille pour être automatiquement plus adaptatifs dans les applications du développeur.

Contrôleur d’affichage fractionné

L’une des classes view Controller qui a changé le plus dans iOS 8 est la UISplitViewController classe. Dans le passé, le développeur utilise souvent un contrôleur de vue fractionné sur la version iPad de l’application, puis il devra fournir une version complètement différente de sa hiérarchie d’affichage pour la version i Téléphone de l’application.

Dans iOS 8, la UISplitViewController classe est disponible sur les deux plateformes (iPad et i Téléphone), ce qui permet au développeur de créer une hiérarchie de contrôleurs de vue qui fonctionnera pour i Téléphone et iPad.

Lorsqu’un i Téléphone est dans le paysage, le contrôleur de vue fractionné présente ses vues côte à côte, comme il le ferait lors de l’affichage sur un iPad.

Substitution des caractéristiques

Les environnements de caractéristiques sont en cascade à partir du conteneur parent jusqu’aux conteneurs enfants, comme dans le graphique suivant montrant un contrôleur de vue fractionné sur un iPad dans l’orientation paysage :

Contrôleur de vue fractionné sur un iPad dans l’orientation paysage

Étant donné que l’iPad a une classe de taille régulière dans les orientations horizontales et verticales, la vue fractionnée affiche à la fois les vues maître et détail.

Sur un i Téléphone, où la classe taille est compacte dans les deux orientations, le contrôleur de vue fractionné affiche uniquement l’affichage des détails, comme indiqué ci-dessous :

Le contrôleur d’affichage fractionné affiche uniquement l’affichage des détails

Dans une application où le développeur souhaite afficher à la fois l’affichage maître et détaillé sur un i Téléphone dans l’orientation paysage, le développeur doit insérer un conteneur parent pour le contrôleur de vue fractionné et remplacer la collection trait. Comme indiqué dans le graphique ci-dessous :

Le développeur doit insérer un conteneur parent pour le contrôleur de vue fractionné et remplacer la collection trait

A UIView est défini comme parent du contrôleur de vue fractionné et la SetOverrideTraitCollection méthode est appelée sur la vue en passant une nouvelle collection trait et ciblant le contrôleur de vue fractionné. La nouvelle collection trait remplace la HorizontalSizeClassvaleur , la définissant Regularsur , afin que le contrôleur de vue fractionné affiche à la fois les vues maître et détail sur un i Téléphone dans l’orientation paysage.

Notez que le VerticalSizeClass paramètre a été défini unspecifiedsur , ce qui permet à la nouvelle collection Trait d’être ajoutée à la collection Trait sur le parent, ce qui entraîne l’ajout d’un Compact VerticalSizeClass contrôleur de vue fractionné enfant.

Modifications des caractéristiques

Cette section examine en détail la façon dont les collections de traits passent lorsque l’environnement trait change. Par exemple, lorsque l’appareil est pivoté du portrait au paysage.

Vue d’ensemble des changements de traits de paysage

Tout d’abord, iOS 8 effectue une configuration pour préparer la transition. Ensuite, le système anime l’état de transition. Enfin, iOS 8 propre s-up tous les états temporaires requis pendant la transition.

iOS 8 fournit plusieurs rappels que le développeur peut utiliser pour participer à la modification des caractéristiques, comme indiqué dans le tableau suivant :

Phase Rappel Description
Programme d’installation
  • WillTransitionToTraitCollection
  • TraitCollectionDidChange
  • Cette méthode est appelée au début d’une modification de trait avant qu’une collection trait ne soit définie sur sa nouvelle valeur.
  • La méthode est appelée lorsque la valeur de la collection trait a changé, mais avant qu’une animation ne se produise.
Animation WillTransitionToTraitCollection Le coordinateur de transition qui est passé à cette méthode a une AnimateAlongside propriété qui permet au développeur d’ajouter des animations qui seront exécutées avec les animations par défaut.
Nettoyage WillTransitionToTraitCollection Fournit une méthode permettant aux développeurs d’inclure leur propre code de propre up une fois la transition effectuée.

La WillTransitionToTraitCollection méthode est idéale pour animer les contrôleurs de vue ainsi que les modifications apportées à la collection Trait. La WillTransitionToTraitCollection méthode est disponible uniquement sur les contrôleurs d’affichage ( UIViewController) et non sur d’autres environnements de caractéristiques, comme UIViews.

Il TraitCollectionDidChange est idéal pour travailler avec la UIView classe, où le développeur souhaite mettre à jour l’interface utilisateur à mesure que les caractéristiques changent.

Réduction des contrôleurs de vue fractionnés

Examinons maintenant plus en détails ce qui se passe lorsqu’un contrôleur de vue fractionné se réduit d’une colonne à une vue de colonne. Dans le cadre de cette modification, deux processus doivent se produire :

  • Par défaut, le contrôleur de vue fractionné utilise le contrôleur de vue principal comme vue après la réduction. Le développeur peut remplacer ce comportement en remplaçant la GetPrimaryViewControllerForCollapsingSplitViewController méthode du contrôleur de UISplitViewControllerDelegate vue et en fournissant n’importe quel contrôleur de vue qu’il souhaite afficher dans l’état réduit.
  • Le contrôleur de vue secondaire doit être fusionné dans le contrôleur de vue principal. En règle générale, le développeur n’a pas besoin d’entreprendre d’action pour cette étape ; Le contrôleur de vue fractionné inclut la gestion automatique de cette phase en fonction de l’appareil matériel. Toutefois, il peut y avoir certains cas particuliers où le développeur souhaite interagir avec cette modification. L’appel de la CollapseSecondViewController méthode permet au contrôleur de UISplitViewControllerDelegate vue maître d’être affiché lorsque l’effondrement se produit, au lieu de la vue détails.

Développement du contrôleur de vue fractionné

Examinons maintenant plus en détails ce qui se passe lorsqu’un contrôleur de vue fractionné est développé à partir d’un état réduit. Une fois de plus, deux étapes doivent se produire :

  • Tout d’abord, définissez le nouveau contrôleur de vue principal. Par défaut, le contrôleur de vue fractionné utilise automatiquement le contrôleur d’affichage principal à partir de la vue réduite. Là encore, le développeur peut remplacer ce comportement à l’aide de la GetPrimaryViewControllerForExpandingSplitViewController méthode du UISplitViewControllerDelegate .
  • Une fois le contrôleur de vue principal choisi, le contrôleur de vue secondaire doit être recréé. Là encore, le contrôleur de vue fractionné inclut la gestion automatique de cette phase en fonction de l’appareil matériel. Le développeur peut remplacer ce comportement en appelant la SeparateSecondaryViewController méthode du UISplitViewControllerDelegate .

Dans un contrôleur de vue fractionné, le contrôleur de vue principal joue un rôle dans le développement et la réduction des vues en implémentant les méthodes et SeparateSecondaryViewController les CollapseSecondViewController méthodes du UISplitViewControllerDelegate. UINavigationController implémente ces méthodes pour envoyer (push) et afficher automatiquement le contrôleur de vue secondaire.

Affichage des contrôleurs

Une autre modification apportée par Apple à iOS 8 est la façon dont le développeur affiche les contrôleurs de vue. Dans le passé, si l’application disposait d’un contrôleur de vue feuille (par exemple, un contrôleur de vue table) et que le développeur a montré un autre (par exemple, en réponse à l’utilisateur appuyant sur une cellule), l’application revient à travers la hiérarchie du contrôleur de contrôleur vers le contrôleur de vue de navigation et appelle la PushViewController méthode pour afficher la nouvelle vue.

Cela a présenté un couplage très serré entre le contrôleur de navigation et l’environnement dans lequel il s’exécutait. Dans iOS 8, Apple a découplé cela en fournissant deux nouvelles méthodes :

  • ShowViewController : s’adapte pour afficher le nouveau contrôleur d’affichage en fonction de son environnement. Par exemple, dans un élément UINavigationController , il envoie simplement la nouvelle vue sur la pile. Dans un contrôleur de vue fractionné, le nouveau contrôleur d’affichage sera présenté sur le côté gauche en tant que nouveau contrôleur de vue principal. Si aucun contrôleur d’affichage conteneur n’est présent, la nouvelle vue s’affiche en tant que contrôleur d’affichage modal.
  • ShowDetailViewController : fonctionne de la même manière que ShowViewController, mais est implémenté sur un contrôleur de vue fractionné pour remplacer l’affichage des détails par le nouveau contrôleur de vue passé. Si le contrôleur d’affichage fractionné est réduit (comme indiqué dans une application i Téléphone), l’appel est redirigé vers la ShowViewController méthode, et la nouvelle vue s’affiche en tant que contrôleur d’affichage principal. Là encore, si aucun contrôleur d’affichage conteneur n’est présent, la nouvelle vue s’affiche en tant que contrôleur d’affichage modal.

Ces méthodes fonctionnent en commençant par le contrôleur de vue feuille et en parcourant la hiérarchie d’affichage jusqu’à ce qu’ils trouvent le contrôleur de vue conteneur approprié pour gérer l’affichage de la nouvelle vue.

Les développeurs peuvent implémenter ShowViewController et ShowDetailViewController dans leurs propres contrôleurs d’affichage personnalisés pour obtenir les mêmes fonctionnalités automatisées que celles qui UINavigationController leur UISplitViewController sont proposées.

Fonctionnement

Dans cette section, nous allons examiner la façon dont ces méthodes sont réellement implémentées dans iOS 8. Commençons par examiner la nouvelle GetTargetForAction méthode :

Nouvelle méthode GetTargetForAction

Cette méthode guide la chaîne de hiérarchie jusqu’à ce que le contrôleur d’affichage de conteneur approprié soit trouvé. Par exemple :

  1. Si une ShowViewController méthode est appelée, le premier contrôleur de vue de la chaîne qui implémente cette méthode est le contrôleur de navigation. Il est donc utilisé comme parent de la nouvelle vue.
  2. Si une ShowDetailViewController méthode a été appelée à la place, le contrôleur de vue fractionné est le premier contrôleur de vue à l’implémenter. Il est donc utilisé comme parent.

La GetTargetForAction méthode fonctionne en localisant un contrôleur de vue qui implémente une action donnée, puis en demandant à ce contrôleur de vue s’il souhaite recevoir cette action. Étant donné que cette méthode est publique, les développeurs peuvent créer leurs propres méthodes personnalisées qui fonctionnent comme les méthodes intégrées ShowViewController et ShowDetailViewController les méthodes.

Présentation adaptative

Dans iOS 8, Apple a également fait des présentations popover ( UIPopoverPresentationController) adaptatives. Par conséquent, un contrôleur d’affichage de présentation popover présente automatiquement une vue contextuelle normale dans une classe de taille régulière, mais l’affiche en plein écran dans une classe de taille compacte horizontalement (par exemple, sur un i Téléphone).

Pour prendre en charge les modifications dans le système de storyboard unifié, un nouvel objet de contrôleur a été créé pour gérer les contrôleurs de vue présentés . UIPresentationController Ce contrôleur est créé à partir du moment où le contrôleur d’affichage est présenté jusqu’à ce qu’il soit ignoré. Comme il s’agit d’une classe de gestion, elle peut être considérée comme une super classe sur le contrôleur de vue, car elle répond aux modifications d’appareil qui affectent le contrôleur de vue (par exemple, l’orientation) qui sont ensuite renvoyées dans le contrôleur de vue les contrôles Du contrôleur de présentation.

Lorsque le développeur présente un contrôleur de vue à l’aide de la PresentViewController méthode, la gestion du processus de présentation est transmise .UIKit UIKit handles (entre autres) le contrôleur approprié pour le style créé, avec la seule exception étant lorsqu’un contrôleur de vue a le style défini UIModalPresentationCustomsur . Ici, l’application peut fournir son propre PresentationController plutôt que d’utiliser le UIKit contrôleur.

Styles de présentation personnalisés

Avec un style de présentation personnalisé, les développeurs ont la possibilité d’utiliser un contrôleur de présentation personnalisé. Ce contrôleur personnalisé peut être utilisé pour modifier l’apparence et le comportement de l’affichage auquel il est allié.

Utilisation des classes de taille

Le projet Xamarin Photos adaptatives inclus dans cet article donne un exemple de travail d’utilisation des classes de taille et des contrôleurs de vue adaptative dans une application d’interface unifiée iOS 8.

Bien que l’application crée complètement son interface utilisateur à partir du code, au lieu de créer un storyboard unifié à l’aide du Générateur d’interface de Xcode, les mêmes techniques s’appliquent.

Examinons maintenant plus en détail la façon dont le projet Photos adaptatives implémente plusieurs fonctionnalités de la classe taille dans iOS 8 pour créer une application adaptative.

Adaptation aux modifications de l’environnement trait

Lors de l’exécution de l’application Photos adaptatives sur un i Téléphone, lorsque l’utilisateur fait pivoter l’appareil du portrait vers le paysage, le contrôleur de vue fractionné affiche à la fois la vue maître et les détails :

Le contrôleur d’affichage fractionné affiche à la fois la vue maître et les détails, comme indiqué ici

Pour ce faire, substituez la UpdateConstraintsForTraitCollection méthode du contrôleur de vue et ajustez les contraintes en fonction de la valeur du VerticalSizeClass. Par exemple :

public void UpdateConstraintsForTraitCollection (UITraitCollection collection)
{
    var views = NSDictionary.FromObjectsAndKeys (
        new object[] { TopLayoutGuide, ImageView, NameLabel, ConversationsLabel, PhotosLabel },
        new object[] { "topLayoutGuide", "imageView", "nameLabel", "conversationsLabel", "photosLabel" }
    );

    var newConstraints = new List<NSLayoutConstraint> ();
    if (collection.VerticalSizeClass == UIUserInterfaceSizeClass.Compact) {
        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|[imageView]-[nameLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("[imageView]-[conversationsLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("[imageView]-[photosLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:|[topLayoutGuide]-[nameLabel]-[conversationsLabel]-[photosLabel]",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:|[topLayoutGuide][imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.Add (NSLayoutConstraint.Create (ImageView, NSLayoutAttribute.Width, NSLayoutRelation.Equal,
            View, NSLayoutAttribute.Width, 0.5f, 0.0f));
    } else {
        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|[imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[nameLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[conversationsLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("|-[photosLabel]-|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));

        newConstraints.AddRange (NSLayoutConstraint.FromVisualFormat ("V:[topLayoutGuide]-[nameLabel]-[conversationsLabel]-[photosLabel]-20-[imageView]|",
            NSLayoutFormatOptions.DirectionLeadingToTrailing, null, views));
    }

    if (constraints != null)
        View.RemoveConstraints (constraints.ToArray ());

    constraints = newConstraints;
    View.AddConstraints (constraints.ToArray ());
}

Ajout d’animations de transition

Lorsque le contrôleur de vue fractionné dans l’application Photos adaptatives passe de réduit à développé, les animations sont ajoutées aux animations par défaut en remplaçant la WillTransitionToTraitCollection méthode du contrôleur de vue. Par exemple :

public override void WillTransitionToTraitCollection (UITraitCollection traitCollection, IUIViewControllerTransitionCoordinator coordinator)
{
    base.WillTransitionToTraitCollection (traitCollection, coordinator);
    coordinator.AnimateAlongsideTransition ((UIViewControllerTransitionCoordinatorContext) => {
        UpdateConstraintsForTraitCollection (traitCollection);
        View.SetNeedsLayout ();
    }, (UIViewControllerTransitionCoordinatorContext) => {
    });
}

Substitution de l’environnement trait

Comme indiqué ci-dessus, l’application Photos adaptatives force le contrôleur d’affichage fractionné à afficher les détails et les affichages maîtres lorsque l’appareil i Téléphone est en mode paysage.

Pour ce faire, utilisez le code suivant dans le contrôleur de vue :

private UITraitCollection forcedTraitCollection = new UITraitCollection ();
...

public UITraitCollection ForcedTraitCollection {
    get {
        return forcedTraitCollection;
    }

    set {
        if (value != forcedTraitCollection) {
            forcedTraitCollection = value;
            UpdateForcedTraitCollection ();
        }
    }
}
...

public override void ViewWillTransitionToSize (SizeF toSize, IUIViewControllerTransitionCoordinator coordinator)
{
    ForcedTraitCollection = toSize.Width > 320.0f ?
         UITraitCollection.FromHorizontalSizeClass (UIUserInterfaceSizeClass.Regular) :
         new UITraitCollection ();

    base.ViewWillTransitionToSize (toSize, coordinator);
}

public void UpdateForcedTraitCollection ()
{
    SetOverrideTraitCollection (forcedTraitCollection, viewController);
}

Développement et réduction du contrôleur de vue fractionné

Examinons ensuite comment le comportement de développement et de réduction du contrôleur de vue fractionné a été implémenté dans Xamarin. Dans le AppDelegate, lorsque le contrôleur de vue fractionné est créé, son délégué est affecté pour gérer ces modifications :

public class SplitViewControllerDelegate : UISplitViewControllerDelegate
{
    public override bool CollapseSecondViewController (UISplitViewController splitViewController,
        UIViewController secondaryViewController, UIViewController primaryViewController)
    {
        AAPLPhoto photo = ((CustomViewController)secondaryViewController).Aapl_containedPhoto (null);
        if (photo == null) {
            return true;
        }

        if (primaryViewController.GetType () == typeof(CustomNavigationController)) {
            var viewControllers = new List<UIViewController> ();
            foreach (var controller in ((UINavigationController)primaryViewController).ViewControllers) {
                var type = controller.GetType ();
                MethodInfo method = type.GetMethod ("Aapl_containsPhoto");

                if ((bool)method.Invoke (controller, new object[] { null })) {
                    viewControllers.Add (controller);
                }
            }

            ((UINavigationController)primaryViewController).ViewControllers = viewControllers.ToArray<UIViewController> ();
        }

        return false;
    }

    public override UIViewController SeparateSecondaryViewController (UISplitViewController splitViewController,
        UIViewController primaryViewController)
    {
        if (primaryViewController.GetType () == typeof(CustomNavigationController)) {
            foreach (var controller in ((CustomNavigationController)primaryViewController).ViewControllers) {
                var type = controller.GetType ();
                MethodInfo method = type.GetMethod ("Aapl_containedPhoto");

                if (method.Invoke (controller, new object[] { null }) != null) {
                    return null;
                }
            }
        }

        return new AAPLEmptyViewController ();
    }
}

La SeparateSecondaryViewController méthode teste pour voir si une photo est affichée et prend des mesures en fonction de cet état. Si aucune photo n’est affichée, elle réduit le contrôleur d’affichage secondaire afin que le contrôleur de vue maître soit affiché.

La CollapseSecondViewController méthode est utilisée lors du développement du contrôleur de vue fractionnée pour voir si des photos existent sur la pile, si c’est le cas, elle est réduite à cette vue.

Déplacement entre les contrôleurs d’affichage

Examinons ensuite comment l’application Photos adaptatives se déplace entre les contrôleurs d’affichage. Dans la AAPLConversationViewController classe lorsque l’utilisateur sélectionne une cellule dans le tableau, la ShowDetailViewController méthode est appelée pour afficher la vue détails :

public override void RowSelected (UITableView tableView, NSIndexPath indexPath)
{
    var photo = PhotoForIndexPath (indexPath);
    var controller = new AAPLPhotoViewController ();
    controller.Photo = photo;

    int photoNumber = indexPath.Row + 1;
    int photoCount = (int)Conversation.Photos.Count;
    controller.Title = string.Format ("{0} of {1}", photoNumber, photoCount);
    ShowDetailViewController (controller, this);
}

Affichage des indicateurs de divulgation

Dans l’application Photo adaptative, il existe plusieurs endroits où les indicateurs de divulgation sont masqués ou affichés en fonction des modifications apportées à l’environnement trait. Ceci est géré avec le code suivant :

public bool Aapl_willShowingViewControllerPushWithSender ()
{
    var selector = new Selector ("Aapl_willShowingViewControllerPushWithSender");
    var target = this.GetTargetViewControllerForAction (selector, this);

    if (target != null) {
        var type = target.GetType ();
        MethodInfo method = type.GetMethod ("Aapl_willShowingDetailViewControllerPushWithSender");
        return (bool)method.Invoke (target, new object[] { });
    } else {
        return false;
    }
}

public bool Aapl_willShowingDetailViewControllerPushWithSender ()
{
    var selector = new Selector ("Aapl_willShowingDetailViewControllerPushWithSender");
    var target = this.GetTargetViewControllerForAction (selector, this);

    if (target != null) {
        var type = target.GetType ();
        MethodInfo method = type.GetMethod ("Aapl_willShowingDetailViewControllerPushWithSender");
        return (bool)method.Invoke (target, new object[] { });
    } else {
        return false;
    }
}

Celles-ci sont implémentées à l’aide de la GetTargetViewControllerForAction méthode décrite en détail ci-dessus.

Lorsqu’un contrôleur d’affichage de table affiche des données, il utilise les méthodes implémentées ci-dessus pour déterminer si un push va se produire ou non, et s’il faut afficher ou non l’indicateur de divulgation en conséquence :

public override void WillDisplay (UITableView tableView, UITableViewCell cell, NSIndexPath indexPath)
{
    bool pushes = ShouldShowConversationViewForIndexPath (indexPath) ?
         Aapl_willShowingViewControllerPushWithSender () :
         Aapl_willShowingDetailViewControllerPushWithSender ();

    cell.Accessory = pushes ? UITableViewCellAccessory.DisclosureIndicator : UITableViewCellAccessory.None;
    var conversation = ConversationForIndexPath (indexPath);
    cell.TextLabel.Text = conversation.Name;
}

Nouveau ShowDetailTargetDidChangeNotification type

Apple a ajouté un nouveau type de notification pour l’utilisation des classes de taille et des environnements de caractéristiques à partir d’un contrôleur de vue fractionné. ShowDetailTargetDidChangeNotification Cette notification est envoyée chaque fois que l’affichage détail cible d’un contrôleur de mode fractionné change, par exemple lorsque le contrôleur se développe ou s’réduit.

L’application Photos adaptatives utilise cette notification pour mettre à jour l’état de l’indicateur de divulgation lorsque le contrôleur d’affichage des détails change :

public override void ViewDidLoad ()
{
    base.ViewDidLoad ();
    TableView.RegisterClassForCellReuse (typeof(UITableViewCell), AAPLListTableViewControllerCellIdentifier);
    NSNotificationCenter.DefaultCenter.AddObserver (this, new Selector ("showDetailTargetDidChange:"),
        UIViewController.ShowDetailTargetDidChangeNotification, null);
    ClearsSelectionOnViewWillAppear = false;
}

Examinez plus en détail l’application Photos adaptatives pour voir toutes les façons dont les classes de taille, les collections de caractéristiques et les contrôleurs de vue adaptative peuvent être utilisés pour créer facilement une application unifiée dans Xamarin.iOS.

Storyboards unifiés

Nouveautés d’iOS 8, les storyboards unifiés permettent au développeur de créer un fichier de storyboard unifié qui peut être affiché sur les appareils i Téléphone et iPad en ciblant plusieurs classes de taille. En utilisant des storyboards unifiés, le développeur écrit moins de code spécifique à l’interface utilisateur et n’a qu’une seule conception d’interface pour créer et gérer.

Les principaux avantages des storyboards unifiés sont les suivants :

  • Utilisez le même fichier storyboard pour i Téléphone et iPad.
  • Déployez vers l’arrière sur iOS 6 et iOS 7.
  • Affichez un aperçu de la disposition pour différents appareils, orientations et versions du système d’exploitation.

Activation des classes de taille

Par défaut, tout nouveau projet Xamarin.iOS utilise des classes de taille. Pour utiliser des classes de taille et des segues adaptatives à l’intérieur d’un storyboard à partir d’un projet plus ancien, il doit d’abord être converti au format de storyboard unifié Xcode 6 et la boîte de dialogue Utiliser les classes de taille case activée box est sélectionnée dans l’inspecteur de fichier Xcode pour vos storyboards.

Écrans de lancement dynamique

Le fichier d’écran de lancement s’affiche sous la forme d’un écran de démarrage pendant qu’une application iOS lance pour fournir des commentaires à l’utilisateur que l’application démarre réellement. Avant iOS 8, le développeur doit inclure plusieurs Default.png ressources d’image pour chaque type d’appareil, orientation et résolution d’écran sur laquelle l’application s’exécuterait. Par exemple, Default@2x.png, , Default-Portrait@2x~ipad.pngDefault-Landscape@2x~ipad.png, etc.

Factoring in the new i Téléphone 6 and i Téléphone 6 Plus devices (and the upcoming Apple Watch) with all the existing i Téléphone and iPad devices, this représente un large éventail de tailles, orientations et résolutions de ressources d’image d’écran de Default.png démarrage qui doivent être créées et conservées. En outre, ces fichiers peuvent être assez volumineux et vont « gonfler » l’offre groupée d’applications livrables, augmentant la durée nécessaire pour télécharger l’application à partir de l’App Store iTunes (éventuellement l’empêcher de pouvoir être livré sur un réseau cellulaire) et augmenter la quantité de stockage requise sur l’appareil de l’utilisateur final.

Nouveautés d’iOS 8, le développeur peut créer un fichier atomique .xib unique dans Xcode qui utilise la disposition automatique et les classes de taille pour créer un écran de lancement dynamique qui fonctionnera pour chaque appareil, résolution et orientation. Cela réduit non seulement la quantité de travail requise par le développeur pour créer et gérer toutes les ressources d’image requises, mais elle réduit considérablement la taille de l’ensemble installé de l’application.

Les écrans de lancement dynamique présentent les limitations et considérations suivantes :

  • Utilisez uniquement UIKit des classes.
  • Utilisez une vue racine unique qui est un ou UIViewController un UIView objet.
  • Ne créez aucune connexion au code de l’application (n’ajoutez pas d’actions ou de points de sortie).
  • N’ajoutez pas d’objets UIWebView .
  • N’utilisez aucune classe personnalisée.
  • N’utilisez pas d’attributs d’exécution.

Avec les instructions ci-dessus à l’esprit, examinons l’ajout d’un écran de lancement dynamique à un projet Xamarin iOS 8 existant.

Effectuez les actions suivantes :

  1. Ouvrez Visual Studio pour Mac et chargez la solution pour ajouter l’écran de lancement dynamique à.

  2. Dans le Explorateur de solutions, cliquez avec le bouton droit sur le MainStoryboard.storyboard fichier, puis sélectionnez Ouvrir avec>Xcode Interface Builder :

    Ouvrir avec Xcode Interface Builder

  3. Dans Xcode, sélectionnez Fichier>nouveau>fichier... :

    Sélectionner fichier / Nouveau

  4. Sélectionnez l’écran de lancement de l’interface>utilisateur iOS>, puis cliquez sur le bouton Suivant :

    Sélectionner iOS / Interface utilisateur / Écran de lancement

  5. Nommez le fichier LaunchScreen.xib , puis cliquez sur le bouton Créer :

    Nommez le fichier LaunchScreen.xib

  6. Modifiez la conception de l’écran de lancement en ajoutant des éléments graphiques et en utilisant des contraintes de disposition pour les appareils, les orientations et les tailles d’écran données :

    Modification de la conception de l’écran de lancement

  7. Enregistrez les changements apportés à LaunchScreen.xib.

  8. Sélectionnez la cible des applications et l’onglet Général :

    Sélectionnez la cible des applications et l’onglet Général

  9. Cliquez sur le bouton Choisir Info.plist , sélectionnez l’application Info.plist Xamarin, puis cliquez sur le bouton Choisir :

    Sélectionnez info.plist pour l’application Xamarin

  10. Dans la section Icônes de l’application et Lancer des images, ouvrez la liste déroulante Lancer le fichier d’écran, puis choisissez le LaunchScreen.xib fichier créé ci-dessus :

    Choisissez LaunchScreen.xib

  11. Enregistrez les modifications apportées au fichier et revenez à Visual Studio pour Mac.

  12. Attendez que Visual Studio pour Mac terminer la synchronisation des modifications avec Xcode.

  13. Dans le Explorateur de solutions, cliquez avec le bouton droit sur le dossier Ressource et sélectionnez Ajouter>des fichiers... :

    Sélectionnez Ajouter / Ajouter des fichiers...

  14. Sélectionnez le LaunchScreen.xib fichier créé ci-dessus, puis cliquez sur le bouton Ouvrir :

    Sélectionnez le fichier LaunchScreen.xib

  15. Générez l’application.

Test de l’écran de lancement dynamique

Dans Visual Studio pour Mac, sélectionnez le simulateur i Téléphone 4 Retina et exécutez l’application. L’écran de lancement dynamique s’affiche dans le format et l’orientation appropriés :

Écran de lancement dynamique affiché dans l’orientation verticale

Arrêtez l’application dans Visual Studio pour Mac et sélectionnez un appareil iOS 8 iPad. Exécutez l’application et l’écran de lancement sera correctement mis en forme pour cet appareil et l’orientation :

Écran de lancement dynamique affiché dans l’orientation horizontale

Revenez à Visual Studio pour Mac et arrêtez l’exécution de l’application.

Utilisation d’iOS 7

Pour maintenir la compatibilité descendante avec iOS 7, incluez simplement les ressources d’image habituelles Default.png comme normale dans l’application iOS 8. iOS revient au comportement précédent et utilise ces fichiers comme écran de démarrage lors de l’exécution sur un appareil iOS 7.

Résumé

Cet article a examiné rapidement les classes de taille et comment elles affectent la disposition dans les appareils i Téléphone et iPad. Il a abordé le fonctionnement des traits, des environnements traits et des collections de caractéristiques avec des classes de taille pour créer des interfaces unifiées. Il a pris un bref aperçu des contrôleurs de vue adaptative et comment ils fonctionnent avec des classes de taille à l’intérieur d’interfaces unifiées. Il a examiné l’implémentation complète des classes de taille et des interfaces unifiées à partir du code C# à l’intérieur d’une application Xamarin iOS 8.

Enfin, cet article a abordé les principes de base de la création d’un écran de lancement dynamique unique qui s’affiche en tant qu’écran de démarrage sur chaque appareil iOS 8.