Storyboards iOS: analyse des avantages et des inconvénients, meilleures pratiques



Apple a créé des storyboards pour que les développeurs puissent visualiser les écrans des applications iOS et les relations entre eux. Tout le monde n'a pas aimé cet outil, et pour cause. J'ai rencontré de nombreux articles critiquant les storyboards, mais je n'ai pas trouvé d'analyse détaillée et impartiale de tous les avantages et inconvénients, en tenant compte des meilleures pratiques. Finalement, j'ai décidé d'écrire moi-même un tel article.

Je vais essayer d'analyser en détail les inconvénients et les avantages de l'utilisation de Storyboards. Après les avoir pesés, vous pouvez prendre une décision significative s'ils sont nécessaires ou non dans le projet. Cette décision n'a pas à être radicale. Si, dans certaines situations, les storyboards créent des problèmes, dans d'autres, leur utilisation est justifiée: cela aide à résoudre efficacement les tâches et à écrire du code simple et facile à gérer.

Commençons par les lacunes et analysons si toutes sont toujours pertinentes.

Inconvénients


1. Les storyboards ont du mal à gérer les conflits lors de la fusion des modifications


Storyboard est un fichier XML. Il est moins lisible que le code, il est donc plus difficile de résoudre les conflits. Mais cette complexité dépend également de la façon dont nous travaillons avec le Storyboard. Vous pouvez grandement simplifier votre tâche si vous suivez les règles ci-dessous:

  • Ne mettez pas l'intégralité de l'interface utilisateur dans un seul Storyboard, divisez-le en plusieurs plus petits. Cela permettra de répartir le travail sur les Storyboards entre les développeurs sans risque de conflits et, en cas d'inévitabilité, simplifiera la tâche de les résoudre.
  • Si vous devez utiliser la même vue à plusieurs endroits, sélectionnez-la dans une sous-classe distincte avec son propre fichier Xib.
  • Faites des commits plus souvent, car il est beaucoup plus facile de travailler avec des changements venant en petits morceaux.

L'utilisation de plusieurs storyboards au lieu d'un seul nous empêche de voir l'intégralité de la carte de l'application dans un seul fichier. Mais souvent, cela n'est pas nécessaire - seule la partie spécifique sur laquelle nous travaillons en ce moment est suffisante.

2. Les storyboards empêchent la réutilisation du code


Si nous parlons d'utiliser uniquement des storyboards sans Xibs dans le projet, des problèmes se poseront sûrement. Cependant, les Xibs, à mon avis, sont des éléments nécessaires lorsque vous travaillez avec des storyboards. Grâce à eux, vous pouvez facilement créer des vues réutilisables, qui sont également pratiques pour travailler avec du code.

Tout d'abord, créez la classe XibView base, qui est responsable du rendu de l' UIView créé dans Xib dans le Storyboard:

 @IBDesignable class XibView: UIView { var contentView: UIView? } 

XibView chargera l' UIView de Xib dans le contentView et l'ajoutera comme sa sous-vue. Nous le faisons dans la méthode setup() :

 private func setup() { guard let view = loadViewFromNib() else { return } view.frame = bounds view.autoresizingMask = [.flexibleWidth, .flexibleHeight] addSubview(view) contentView = view } 

La méthode loadViewFromNib() ressemble à ceci:

 private func loadViewFromNib() -> UIView? { let nibName = String(describing: type(of: self)) let nib = UINib(nibName: nibName, bundle: Bundle(for: XibView.self)) return nib.instantiate(withOwner: self, options: nil).first as? UIView } 

La méthode setup() doit être appelée dans les initialiseurs:

 override init(frame: CGRect) { super.init(frame: frame) setup() } required init?(coder aDecoder: NSCoder) { super.init(coder: aDecoder) setup() } 

La classe XibView prête. Les vues réutilisées, dont l'apparence est rendue dans un fichier Xib, seront héritées de XibView :

 final class RedView: XibView { } 


Si vous ajoutez maintenant une nouvelle UIView au Storyboard et définissez sa classe sur RedView , alors tout sera affiché avec succès:

La création d'une instance de RedView dans le code se produit de la manière habituelle:

 let redView = RedView() 

Un autre détail utile que tout le monde ne peut connaître est la possibilité d'ajouter des couleurs au répertoire .xcassets . Cela vous permet de les modifier globalement dans tous les Storyboards et Xibs où ils sont utilisés.

Pour ajouter de la couleur, cliquez sur "+" en bas à gauche et sélectionnez "Nouveau jeu de couleurs":

Spécifiez le nom et la couleur désirés:

La couleur créée apparaîtra dans la section "Couleurs nommées":

De plus, il peut être obtenu dans le code:

 innerView.backgroundColor = UIColor(named: "BackgroundColor") 

3. Vous ne pouvez pas utiliser des initialiseurs personnalisés pour UIViewControllers créés dans Storyboard


Dans le cas du Storyboard, nous ne pouvons pas passer de dépendances dans les initialiseurs des UIViewControllers . Habituellement, cela ressemble à ceci:

 override func prepare(for segue: UIStoryboardSegue, sender: Any?) { guard segue.identifier == "detail", let detailVC = segue.destination as? DetailViewController else { return } let object = Object() detailVC.object = object } 

Ce code peut être mieux fait en utilisant une sorte de constante pour représenter des identifiants ou des outils comme SwiftGen et R.swift , ou peut-être même Perform . Mais de cette façon, nous nous débarrassons uniquement des littéraux de chaîne et ajoutons du sucre syntaxique, et ne résolvons pas les problèmes qui se posent:

  • Comment savoir comment le DetailViewController configuré dans l'exemple ci-dessus? Si vous êtes nouveau dans le projet et n'avez pas cette connaissance, vous devrez ouvrir un fichier avec une description de ce contrôleur et l'étudier.
  • Les propriétés DetailViewController définies après l'initialisation, ce qui signifie qu'elles doivent être facultatives. Il est nécessaire de gérer les cas où une propriété est nil , sinon l'application peut se bloquer au moment le plus inopportun. Vous pouvez marquer les propriétés comme facultatives implicitement développées ( var object: Object! ), Mais l'essence ne changera pas.
  • Les propriétés doivent être marquées comme var et non let . Une situation est donc possible lorsque quelqu'un de l'extérieur veut les changer. DetailViewController doit gérer de telles situations.

Une solution est décrite dans cet article .

4. À mesure que le Storyboard grandit, la navigation devient plus difficile


Comme nous l'avons noté précédemment, vous n'avez pas besoin de tout mettre dans un Storyboard, il est préférable de le diviser en plusieurs plus petits. Avec l'avènement du Storyboard Reference, c'est devenu très simple.
Ajoutez la référence du storyboard de la bibliothèque d'objets au storyboard:

Nous définissons les valeurs de champ requises dans l' inspecteur d'attributs - il s'agit du nom du fichier Storyboard et, si nécessaire, de l' ID référencé , qui correspond à l' ID Storyboard de l' écran souhaité. Par défaut, le contrôleur de vue initiale se charge:

Si vous spécifiez un nom non valide dans le champ Storyboard ou faites référence à un ID Storyboard inexistant, Xcode vous en avertira lors de la compilation.

5. Xcode ralentit lors du chargement des story-boards


Si le Storyboard contient un grand nombre d'écrans avec de nombreuses contraintes, son chargement prendra vraiment un certain temps. Mais là encore, il est préférable de diviser le grand Storyboard en plus petits. Séparément, ils se chargent beaucoup plus rapidement et il devient plus pratique de travailler avec eux.

6. Les storyboards sont fragiles, un bug peut provoquer le plantage de l'application au moment de l'exécution


Les principaux points faibles:

  • Erreurs dans les UICollectionViewCell UITableViewCell et UICollectionViewCell .
  • Erreurs dans les identifiants de séquence.
  • Utilisation d'une sous-classe d' UIView qui n'existe plus.
  • Synchronisation des IBActions et IBOutlets avec le code.

Tout cela et certains autres problèmes peuvent entraîner le blocage de l'application au moment de l'exécution, ce qui signifie qu'il est probable que de telles erreurs tombent dans la version. Par exemple, lorsque nous définissons des identifiants de cellule ou des séquences dans le Storyboard, ils doivent être copiés dans le code où qu'ils soient utilisés. En changeant l'identifiant à un endroit, il doit être changé dans tous les autres. Il est possible que vous l'oublieriez simplement ou que vous fassiez une faute de frappe, mais que vous ne connaissiez l'erreur que lorsque l'application est en cours d'exécution.

Vous pouvez réduire la probabilité d'erreurs en supprimant les littéraux de chaîne dans votre code. Pour cela, les UICollectionViewCell UITableViewCell et UICollectionViewCell peuvent se voir attribuer les noms des classes de cellules: par exemple, l'identifiant ItemTableViewCell sera la chaîne «ItemTableViewCell». Dans le code, nous obtenons la cellule comme ceci:

 let cell = tableView.dequeueReusableCell(withIdentifier: String(describing: ItemTableViewCell.self)) as! ItemTableViewCell 

Vous pouvez ajouter la fonction générique correspondante à UITableView :

 extension UITableView { open func dequeueReusableCell<T>() -> T where T: UITableViewCell { return dequeueReusableCell(withIdentifier: String(describing: T.self)) as! T } } 

Et puis il devient plus facile d'obtenir la cellule:

 let cell: ItemTableViewCell = tableView.dequeueReusableCell() 

Si vous oubliez soudainement de spécifier la valeur de l'identifiant de cellule dans le Storyboard, Xcode affichera un avertissement, vous ne devez donc pas les ignorer.

En ce qui concerne les identificateurs de séquences, vous pouvez utiliser des énumérations pour eux. Créons un protocole spécial:

 protocol SegueHandler { associatedtype SegueIdentifier: RawRepresentable } 

UIViewController qui prend en charge ce protocole devra définir un type imbriqué avec le même nom. Il répertorie tous les identifiants de séquence que ce UIViewController peut traiter:

 extension StartViewController: SegueHandler { enum SegueIdentifier: String { case signIn, signUp } } 

De plus, dans l'extension de protocole SegueHandler , SegueHandler définissons deux fonctions: l'une accepte un UIStoryboardSegue et renvoie la valeur SegueIdentifier correspondante, et l'autre appelle simplement performSegue , en prenant l'entrée SegueIdentifier :

 extension SegueHandler where Self: UIViewController, SegueIdentifier.RawValue == String { func performSegue(withIdentifier segueIdentifier: SegueIdentifier, sender: AnyObject?) { performSegue(withIdentifier: segueIdentifier.rawValue, sender: sender) } func segueIdentifier(for segue: UIStoryboardSegue) -> SegueIdentifier { guard let identifier = segue.identifier, let identifierCase = SegueIdentifier(rawValue: identifier) else { fatalError("Invalid segue identifier \(String(describing: segue.identifier)).") } return identifierCase } } 

Et maintenant, dans un UIViewController qui prend en charge le nouveau protocole, vous pouvez travailler avec prepare(for:sender:) comme suit:

 extension StartViewController: SegueHandler { enum SegueIdentifier: String { case signIn, signUp } override func prepare(for segue: UIStoryboardSegue, sender: Any?) { switch segueIdentifier(for: segue) { case .signIn: print("signIn") case .signUp: print("signUp") } } } 

Et lancez la séquence comme ceci:

 performSegue(withIdentifier: .signIn, sender: nil) 

Si vous ajoutez un nouvel identifiant à SegueIdentifier , alors Xcode le forcera certainement à traiter dans switch/case .

Une autre option pour se débarrasser des littéraux de chaîne comme les séquences d'identificateurs et autres consiste à utiliser des outils de génération de code comme R.swift .

7. Les storyboards sont moins flexibles que le code.


Oui, c'est vrai. Si la tâche consiste à créer un écran complexe avec des animations et des effets que le Storyboard ne peut pas gérer, alors vous devez utiliser le code!

8. Les storyboards ne permettent pas de changer le type de UIViewControllers spéciaux


Par exemple, lorsque vous devez changer le type de UITableViewController en UICollectionViewController , vous devez supprimer l'objet, en ajouter un nouveau avec un autre type et le reconfigurer. Bien que ce ne soit pas un cas fréquent, il convient de noter que ces modifications sont apportées plus rapidement dans le code.

9. Les storyboards ajoutent deux dépendances supplémentaires au projet. Ils peuvent contenir des erreurs que le développeur ne peut pas corriger.


Il s'agit d'Interface Builder et de l'analyseur Storyboards. De tels cas sont rares et peuvent souvent être contournés par d'autres solutions.

10. Revue de code sophistiquée


Gardez à l'esprit que la révision du code n'est pas vraiment une recherche de bogues. Oui, ils se trouvent dans le processus de visualisation du code, mais l'objectif principal est d'identifier les faiblesses qui peuvent créer des problèmes à long terme. Pour les storyboards, il s'agit principalement du travail de mise en page automatique . Il ne devrait pas y avoir d' ambiguïté et de malentendu . Pour les trouver, utilisez simplement la recherche dans le Storyboard XML pour les lignes "ambiguous =" YES "" et "misplaced =" YES "" ou ouvrez simplement le Storyboard dans Interface Builder et recherchez les points rouges et jaunes:

Cependant, cela peut ne pas suffire. Les conflits entre les contraintes peuvent également être détectés lorsque l'application est en cours d'exécution. Si une situation similaire se produit, des informations à ce sujet s'affichent dans la console. De tels cas ne sont pas rares, par conséquent, leur recherche doit également être prise au sérieux.

Tout le reste - faire correspondre la position et la taille des éléments avec la conception, la liaison correcte des IBOutlets et IBActions - n'est pas pour la révision du code.

De plus, il est important de faire des commits plus souvent, il sera alors plus facile pour le réviseur de visualiser les changements en petits morceaux. Il sera plus en mesure de se plonger dans les détails sans rien manquer. Cela, à son tour, aura un effet positif sur la qualité de la révision du code.

Résumé


Dans la liste des défauts de Storyboards, j'ai laissé 4 éléments (par ordre décroissant de leur valeur):

  1. Les storyboards ont du mal à gérer les conflits lors de la fusion des modifications.
  2. Les storyboards sont moins flexibles que le code.
  3. Les storyboards sont fragiles, une erreur peut entraîner un plantage lors de l'exécution.
  4. Vous ne pouvez pas utiliser des initialiseurs personnalisés pour UIViewControllers créés dans le Storyboard.

Les avantages


1. Visualisation de l'interface utilisateur et des contraintes


Même si vous êtes débutant et que vous venez de démarrer un projet que vous ne connaissez pas, vous pouvez facilement trouver le point d'entrée de l'application et comment y accéder depuis l'écran souhaité. Vous savez à quoi ressembleront chaque bouton, étiquette ou champ de texte, quelle position ils prendront, comment les contraintes les affectent, comment ils interagissent avec les autres éléments. En quelques clics, vous pouvez facilement créer une nouvelle UIView , personnaliser son apparence et son comportement. La mise en page automatique nous permet de travailler avec UIView naturellement, comme si nous disions: "Ce bouton devrait être à gauche de cette étiquette et avoir la même hauteur avec elle." Cette expérience d'interface utilisateur est intuitive et efficace. Vous pouvez essayer de donner des exemples où un code bien écrit fait gagner plus de temps lors de la création de certains éléments de l'interface utilisateur, mais globalement cela ne change pas grand-chose. Le storyboard fait bien son travail.

Séparément, notez Disposition automatique. Il s'agit d'un outil très puissant et utile, sans lequel il serait difficile de créer une application qui prend en charge toutes les différentes tailles d'écran. Interface Builder vous permet de voir le résultat du travail avec Auto Layout sans lancer l'application, et si certaines contraintes ne correspondent pas au schéma général, Xcode vous en avertira immédiatement. Bien sûr, il y a des cas où Interface Builder n'est pas en mesure de fournir le comportement nécessaire d'une interface très dynamique et complexe, alors vous devez vous fier au code. Mais même dans de telles situations, vous pouvez le faire dans Interface Builder et le compléter avec seulement quelques lignes de code.

Regardons quelques exemples qui illustrent les fonctionnalités utiles d'Interface Builder.

Tables dynamiques basées sur UIStackView


Créez un nouveau UIViewController , ajoutez un plein écran UIScrollView :

Dans UIScrollView ajoutez un UIStackView vertical, UIStackView -le aux bords et définissez la hauteur et la largeur égales à UIScrollView . À cette hauteur, attribuez la priorité = Faible (250) :

Ensuite, créez toutes les cellules nécessaires et ajoutez-les à UIStackView . Peut-être que ce sera UIView ordinaire en une seule copie, ou peut-être UIView , pour lequel nous avons créé notre propre fichier Xib. Dans tous les cas, l'interface utilisateur entière de cet écran est dans le Storyboard, et grâce à la mise en page automatique correctement configurée, le défilement fonctionnera parfaitement, en s'adaptant au contenu:



Nous pouvons également adapter les cellules à la taille de leur contenu. Ajoutez UILabel à chaque cellule, liez-les aux bords:

Il est déjà clair à quoi tout cela ressemblera au moment de l'exécution. Vous pouvez associer des actions aux cellules, par exemple, passer à un autre écran. Et tout cela sans une seule ligne de code.
De plus, si vous définissez hidden = true pour un UIView partir d'un UIStackView , il ne se cachera pas seulement, mais ne prendra pas non plus d'espace. UIStackView recalculera automatiquement ses tailles:



Cellules à dimensionnement automatique


Dans l' inspecteur Taille du tableau, définissez Hauteur de ligne = Automatique et Estimation - sur une valeur moyenne:

Pour que cela fonctionne, les contraintes doivent être correctement configurées dans les cellules elles-mêmes et permettre un calcul précis de la hauteur des cellules en fonction du contenu au moment de l'exécution. Si ce n'est pas clair ce qui est en jeu, il y a une très bonne explication dans la documentation officielle .

En conséquence, en démarrant l'application, nous verrons que tout est correctement affiché:

Table à dimensionnement automatique


Vous devez implémenter ce comportement de table:



Comment réaliser un changement dynamique de hauteur similaire? Contrairement à UILabel , UIButton et à d'autres sous-classes d' UIView , c'est un peu plus difficile à faire avec un tableau, car la taille du contenu intrinsèque ne dépend pas de la taille des cellules à l'intérieur. Elle ne peut pas calculer sa taille en fonction du contenu, mais il est possible de l'aider avec cela.

Notez qu'à un moment donné de la vidéo, la hauteur de la table cesse de changer, atteignant une certaine valeur maximale. Pour ce faire, définissez la contrainte de hauteur de table avec la valeur Relation = Inférieur ou égal :

À ce stade, Interface Builder ne sait pas encore quelle hauteur sera la table, il ne connaît que sa valeur maximale égale à 200 (à partir de la contrainte de hauteur). Comme indiqué précédemment, la taille du contenu intrinsèque n'est pas égale au contenu du tableau. Cependant, nous avons la possibilité de définir l'espace réservé dans le champ Taille intrinsèque :

Cette valeur n'est valide que lorsque vous travaillez avec Interface Builder. Bien sûr, la taille du contenu intrinsèque ne doit pas nécessairement être égale à cette valeur lors de l'exécution. Nous venons de dire à Interface Builder que tout est sous contrôle.

Ensuite, créez une nouvelle sous-classe de la table CustomTableView :

 final class CustomTableView: UITableView { override var contentSize: CGSize { didSet { invalidateIntrinsicContentSize() } } override var intrinsicContentSize: CGSize { return contentSize } } 

Un de ces cas où le code est nécessaire. Ici, nous appelons invalidateIntrinsicContentSize chaque fois que contentSize la table change. Cela permettra au système d'accepter la nouvelle taille de contenu intrinsèque. À son tour, il renvoie contentSize , forçant le tableau à ajuster dynamiquement sa hauteur et à afficher un certain nombre de cellules sans défilement. Le défilement apparaît au moment où nous atteignons la limite de contrainte de hauteur.

Ces trois fonctionnalités d'Interface Builder peuvent être combinées entre elles. Ils ajoutent plus de flexibilité aux options d'organisation du contenu sans avoir besoin de contraintes supplémentaires ou de toute UIView .

2. La capacité de voir instantanément le résultat de leurs actions


Si vous redimensionnez l' UIView , le UIView quelques points sur le côté ou modifiez la couleur d'arrière-plan, vous verrez immédiatement à quoi il ressemblera lors de l'exécution sans avoir à lancer l'application. Pas besoin de se demander pourquoi certains boutons n'apparaissent pas à l'écran ou pourquoi le comportement de l' UIView pas celui souhaité.

L'utilisation de @IBInspectable révèle cet avantage de manière encore plus intéressante. Ajoutez deux UILabel et deux propriétés à RedView :

 final class RedView: XibView { @IBOutlet weak var titleLabel: UILabel! @IBOutlet weak var subtitleLabel: UILabel! @IBInspectable var title: String = "" { didSet { titleLabel.text = title } } @IBInspectable var subtitle: String = "" { didSet { subtitleLabel.text = subtitle } } } 

Deux nouveaux champs apparaîtront dans l' inspecteur d'attributs pour RedView - Title et Subtitle - Subtitle , que nous avons marqué comme @IBInspectable :

Si nous essayons d'entrer des valeurs dans ces champs, nous verrons immédiatement à quoi tout ressemblera lors de l'exécution:



Vous pouvez contrôler n'importe quoi: cornerRadius , borderWidth , borderColor . Par exemple, nous étendons la classe de base UIView :

 extension UIView { @IBInspectable var cornerRadius: CGFloat { set { layer.cornerRadius = newValue } get { return layer.cornerRadius } } @IBInspectable var borderWidth: CGFloat { set { layer.borderWidth = newValue } get { return layer.borderWidth } } @IBInspectable var borderColor: UIColor? { set { layer.borderColor = newValue?.cgColor } get { return layer.borderColor != nil ? UIColor(cgColor: layer.borderColor!) : nil } } @IBInspectable var rotate: CGFloat { set { transform = CGAffineTransform(rotationAngle: newValue * .pi/180) } get { return 0 } } } 

Nous voyons que l'inspecteur d'attributs de l'objet RedView acquis 4 nouveaux champs supplémentaires, avec lesquels vous pouvez désormais jouer:



3. Prévisualisez toutes les tailles d'écran à la fois


Nous avons donc jeté les éléments nécessaires à l'écran, ajusté leur apparence et ajouté les contraintes nécessaires. Comment savoir si le contenu s'affichera correctement sur différentes tailles d'écran? Bien sûr, vous pouvez exécuter l'application sur chaque simulateur, mais cela prendra beaucoup de temps. Il y a une meilleure option: Xcode a un mode de prévisualisation, il vous permet de voir plusieurs tailles d'écran à la fois sans lancer l'application.

Nous appelons l' éditeur adjoint , cliquez dessus sur le premier segment de la barre de transition, sélectionnez Aperçu -> Paramètres.toryboard (à titre d'exemple):

Au début, nous ne voyons qu'un seul écran, mais nous pouvons en ajouter autant que nécessaire en cliquant sur «+» dans le coin inférieur gauche et en sélectionnant les appareils nécessaires dans la liste:

De plus, si le Storyboard prend en charge plusieurs langues, vous pouvez voir à quoi ressemblera l'écran sélectionné avec chacune d'entre elles:

La langue peut être sélectionnée pour tous les écrans à la fois et pour chacun individuellement.

4. Suppression du code de l'interface utilisateur du modèle


La création d'une interface utilisateur sans Interface Builder s'accompagne soit d'une grande quantité de code standard, soit de superclasses et d'extensions qui nécessitent des travaux de maintenance supplémentaires. Ce code peut s'infiltrer dans d'autres parties de l'application, ce qui rend sa lecture et sa recherche difficiles. L'utilisation de Storyboards et de Xibs peut décharger du code, le rendant plus axé sur la logique.

5. Classes de taille


Chaque année, de nouveaux appareils apparaissent, pour lesquels vous devez adapter l'interface utilisateur. Le concept de variations de traits et, en particulier, de classes de taille , qui vous permettent de créer une interface utilisateur pour n'importe quelle taille et orientation de l'écran, y contribue.

Les classes de taille classent la hauteur (h) et la largeur (w) des écrans de l'appareil en termes de compact et régulier ( C et R ). Par exemple, l'iPhone 8 a une classe de taille (wC hR) en orientation portrait et (wC hC) en paysage, et l'iPhone 8 Plus a (wC hR) et (wR hC) respectivement. Les autres appareils peuvent être trouvés ici .

Dans un Storyboard ou Xib pour chacune des classes de taille, vous pouvez stocker votre propre ensemble de données, et l'application utilisera celui approprié en fonction de l'appareil et de l'orientation de l'écran au moment de l'exécution, identifiant ainsi la classe de taille actuelle.Si certains paramètres de mise en page sont les mêmes pour toutes les classes de taille, ils peuvent être configurés dans la catégorie " Tout ", qui est déjà sélectionnée par défaut.

Par exemple, configurez la taille de police en fonction de la classe de taille. Nous sélectionnons l'appareil iPhone 8 Plus pour l'affichage dans Storyboard en orientation portrait et ajoutons une nouvelle condition pour font: si la largeur est Régulière (définissez tout le reste sur «Tout»), alors la taille de la police doit être 37:

Maintenant, si nous changeons l'orientation de l'écran, la taille de la police augmenter - une nouvelle condition fonctionnera, car en orientation paysage, l'iPhone 8 Plus a une classe de taille (wR hC) . Dans le Storyboard, selon la classe de taille, vous pouvez également masquer les vues, activer / désactiver les contraintes, changer leur valeurconstantet bien plus. En savoir plus sur la façon de faire tout cela ici .

Dans la capture d'écran ci-dessus, il convient de noter le panneau inférieur avec le choix de l'appareil pour afficher la disposition. Il vous permet de vérifier rapidement l'adaptabilité de l'interface utilisateur sur n'importe quel appareil et avec n'importe quelle orientation d'écran, et affiche également la classe de taille de la configuration actuelle (à côté du nom de l'appareil). Entre autres choses, il y a un bouton Vary for Traits sur la droite . Son but est de permettre des variations de traits uniquement pour une catégorie spécifique de largeur, hauteur ou largeur et hauteur en même temps. Par exemple, en sélectionnant un iPad avec une classe de taille (wR hR) , cliquez sur «Varier pour les traits» et cochez la case à côté de la largeur et de la hauteur. Désormais, toutes les modifications de disposition ultérieures ne s'appliqueront qu'aux appareils avec (wR hR) jusqu'à ce que nous cliquions sur Terminé .

Conclusion

#
Inconvénients
Les avantages
1
Conflits difficiles à gouverner
Visualisation et contraintes de l'interface utilisateur
2
Pas aussi flexible que le code
La possibilité de voir instantanément le résultat de vos actions
3
Une erreur peut entraîner un crash lors de l'exécution.
Prévisualisez toutes les tailles d'écran à la fois
4
Vous ne pouvez pas utiliser d'initialiseurs personnalisés pour UIViewControllers
Suppression du code de l'interface utilisateur du modèle
5
Classes de taille
Nous avons vu que les storyboards ont leurs forces et leurs faiblesses. À mon avis, vous ne devez pas refuser complètement de les utiliser. Lorsqu'ils sont utilisés correctement, ils apportent de grands avantages et aident à résoudre efficacement les tâches. Vous avez juste besoin d'apprendre à hiérarchiser et à oublier des arguments comme «Je n'aime pas les storyboards» ou «J'ai l'habitude de faire ça».

Source: https://habr.com/ru/post/fr456086/


All Articles