Création d'éléments d'interface par programme à l'aide de PureLayout (partie 1)

Bonjour, Habr! Je vous présente la traduction de l'article Création de contraintes UIViews par programme à l'aide de PureLayout par Aly Yaka.

image

Aujourd'hui, je vais vous guider à travers la création d'une interface utilisateur d'application mobile simple avec du code, sans utiliser de storyboards ou de NIB. Je n'entrerai pas dans les discussions sur ce qui est le mieux, car tout a ses avantages et ses inconvénients, je vais donc simplement laisser un lien qui va dans cette affaire .

Dans la deuxième partie de ce guide, nous allons créer certains des éléments d'interface utilisateur d'application mobile les plus couramment utilisés avec du code, y compris une barre de navigation, une vue tabulaire et des cellules de taille dynamique.

Revue


Ce tutoriel a été écrit en utilisant Xcode 9 et Swift 4. Je suppose également que vous connaissez bien Xcode, Swift et CocoaPods.

Sans plus tarder, commençons à créer notre projet: une simple demande de carte de contact. Le but de cet article est de vous apprendre à créer l'interface utilisateur de votre application en code et, par conséquent, il ne contiendra aucune logique concernant la fonctionnalité de l'application, sauf si cela est nécessaire aux fins de ce guide.

Création de contraintes par programme avec PureLayout


Configuration du projet


Commencez par lancer Xcode -> "Créer un nouveau projet Xcode". Sélectionnez «Single View App» et cliquez sur «Suivant».

image

Nommez le projet comme vous le souhaitez, j'ai décidé de l'appeler ContactCard. Désactivez les trois options ci-dessous et sélectionnez Swift comme langage de programmation, puis cliquez sur Suivant.

image

Sélectionnez un emplacement sur votre ordinateur pour enregistrer le projet. Décochez "Créer un référentiel Git sur mon Mac".

Étant donné que nous n'utiliserons pas de storyboards ou de NIB dans ce projet, supprimez le «Main.storyboard», qui se trouve dans Project Navigator:

image

Après cela, cliquez sur le projet dans le navigateur de projet et sur l'onglet «Général», recherchez la section avec les informations de déploiement et supprimez tout ce qui est écrit dans «l'interface principale». C'est ce qui indique à Xcode le fichier Storyboard à charger au démarrage de l'application, mais comme nous venons de supprimer «Main.storyboard», Xcode ne trouvera pas ce fichier, ce qui entraînera le blocage de l'application.

image

Création d'un ViewController


Si vous exécutez l'application maintenant, un écran noir apparaîtra, puisque l'application n'a plus de source d'interface utilisateur, donc dans la partie suivante nous la créerons. Ouvrez "AppDelegate.swift" et à l'intérieur de l' application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) , Collez ce fragment de code:

 self.window = UIWindow(frame: UIScreen.main.bounds) let viewController = ViewController() self.window?.rootViewController = viewController self.window?.makeKeyAndVisible() 

Ce code fournit une fenêtre d'interaction de l'utilisateur avec l'application, qui se trouve généralement dans "ViewController.swift". Pour vérifier rapidement que tout fonctionne, accédez à «ViewController.swift» et dans la méthode viewDidLoad() , insérez la ligne suivante:

 self.view.backgroundColor = .blue 

Exécutez maintenant l'application.

Pour naviguer entre les fichiers dans Xcode, utilisez les touches de raccourci «⇧⌘O», puis entrez le nom de fichier ou même le fragment de code que vous recherchez, et une liste de fichiers parmi lesquels vous pouvez choisir apparaîtra à l'écran.

Après avoir démarré l'application, cela devrait être le résultat sur l'écran de votre simulateur:

image

Bien sûr, nous n'utiliserons pas ce bleu dégoûtant, alors changez simplement l'arrière-plan en blanc en remplaçant .blue par .white dans viewDidLoad () .

Développement de l'interface utilisateur


Pour créer notre interface utilisateur, nous utiliserons une bibliothèque qui nous facilitera la vie. Pour installer PureLayout, vous devez d'abord ouvrir votre terminal et taper cd, puis un espace, faites glisser votre dossier de projet dans le terminal et appuyez sur "Entrée". Exécutez maintenant les commandes suivantes à l'intérieur du terminal:

  • pod init
  • installation de pod

Cela devrait être la sortie de votre terminal après la deuxième commande:

image

Après cela, fermez Xcode, ouvrez le dossier dans le Finder et vous devriez trouver "<votre nom de projet> .xcworkspace". C'est ce que nous ouvrirons pour accéder à notre application si jamais nous avons besoin d'utiliser CocoaPods. Maintenant, trouvez le fichier nommé «PodFile» et écrivez la ligne suivante sous la phrase use_frameworks!

 pod “PureLayout 

Exécutez à nouveau pod install dans votre terminal, puis générez votre projet en appuyant sur «Commande + B».

Pause café


Maintenant que tout est configuré, commençons par le vrai travail. Allez sur "ViewController.swift" et prenez une tasse de café, car voici à quoi ressemblera le résultat final:

image

Créer ImageView


Insérez la ligne d' import PureLayout sous import UIKit afin de pouvoir utiliser la bibliothèque de ce fichier. Ensuite, sous la déclaration de classe et en dehors de toute fonction, nous commençons par créer la variable Avatar ImageView paresseux (paresseux) comme suit:

 lazy var avatar: UIImageView = { let imageView = UIImageView(image: UIImage(named: "avatar.jpg")) imageView.autoSetDimensions(to: CGSize(width: 128.0, height: 128.0)) imageView.layer.borderWidth = 3.0 imageView.layer.borderColor = UIColor.lightGray.cgColor imageView.layer.cornerRadius = 64.0 imageView.clipsToBounds = true return imageView }() 

Quant à l'image, enregistrez sur le bureau toute image que vous utiliserez comme avatar et faites-la glisser dans Xcode dans le dossier <Your Project Name>, qui dans mon cas s'appelle «ContactCard», et cochez la case «Copier les éléments si nécessaire» .

image

Après cela, écrivez le nom de ce fichier avec son extension dans la déclaration UIImage au lieu de «avatar.jpg».

Pour ceux d'entre vous qui ne le savent pas, les variables paresseuses sont similaires aux variables ordinaires, sauf qu'elles ne sont pas initialisées (ou qu'un espace mémoire est alloué) jusqu'à ce qu'elles soient nécessaires ou appelées pour la première fois . Cela signifie que les variables paresseuses ne sont pas initialisées lorsque le contrôleur de vue est initialisé, mais attendent plutôt un point ultérieur quand elles sont vraiment nécessaires, ce qui économise de la puissance de traitement et de l'espace mémoire pour d'autres processus. Cela est particulièrement utile lors de l'initialisation des composants de l'interface utilisateur.

PureLayout en action


Comme vous pouvez le voir à l'intérieur de l'initialisation, la ligne imageView.autoSetDimensions (to: CGSize (width: 128.0, height: 128.0)) est PureLayout en action. En une seule ligne, nous avons défini une limite pour la hauteur et la largeur de UIImageView, et toutes les NSLayoutConstraints nécessaires sont créées sans avoir besoin d'énormes appels de fonction. Si vous deviez créer des restrictions par programme, vous êtes probablement déjà tombé amoureux de cette merveilleuse bibliothèque.

Pour rendre cette image ronde, nous avons défini son rayon angulaire à la moitié de sa largeur ou de sa hauteur, soit 64,0 points. De plus, définissez la propriété clipsToBounds sur true , qui indique à l'image qu'elle doit écraser tout ce qui se trouve en dehors du rayon que nous venons de définir.

Ensuite, nous passons à la création d'une vue UIV qui servira de haut de la vue derrière l'avatar peint en gris. Déclarez la variable paresseuse suivante pour cette vue:

 lazy var upperView: UIView = { let view = UIView() view.autoSetDimension(.height, toSize: 128) view.backgroundColor = .gray return view }() 

Ajout de sous-vues


Avant de continuer, créons une func addSubviews () qui ajoute les vues que nous venons de créer (et toutes les autres que nous allons créer) en tant que sous-vues au contrôleur de vue:

 func addSubviews() { self.view.addSubview(avatar) self.view.addSubview(upperView) } 

Ajoutez maintenant la ligne suivante à viewDidLoad (): self.addSubviews ()

Définition de restrictions


Pour avoir une idée du chemin parcouru, fixons des limites à ces deux types. Créez une autre fonction appelée func setupConstraints() et insérez les contraintes suivantes:

 func setupConstraints() { avatar.autoAlignAxis(toSuperviewAxis: .vertical) avatar.autoPinEdge(toSuperviewEdge: .top, withInset: 64.0) upperView.autoPinEdge(toSuperviewEdge: .left) upperView.autoPinEdge(toSuperviewEdge: .right) upperView.autoPinEdgesToSuperviewEdges(with: .zero, excludingEdge: .bottom) } 

Maintenant à l'intérieur de viewDidLoad() appelez setupConstraints() , comme suit: self.setupConstraints() . Ajoutez ceci APRÈS avoir appelé addSubviews() . Cela devrait être la conclusion finale:

image

Mettez l'avatar au premier plan


Malheureusement, ce n'est pas ce que j'aimerais recevoir. Comme vous pouvez le voir, notre vue upperView se trouve au-dessus de l'avatar. Cela est dû au fait que nous avons ajouté un avatar en tant que sous- subviews avant la vue upperView , et puisque ces sous-vues sont situées sous une forme quelconque sur la pile, nous obtenons ce résultat. Pour résoudre ce problème, nous pouvons simplement remplacer ces deux lignes l'une avec l'autre, mais il y a une autre astuce que je veux vous montrer, à savoir: self.view.bringSubview (toFront: avatar) .

Cette méthode transfère l'avatar du bas de la pile vers le haut, alors choisissez la méthode que vous préférez. Bien sûr, pour plus de lisibilité, il est préférable d'ajouter des sous-vues dans l'ordre dans lequel elles doivent être affichées si elles se croisent, tout en se souvenant que les premières sous-vues ajoutées seront au bas de la pile, et donc toutes les autres vues qui se croisent apparaîtront au-dessus.
Et voici à quoi cela devrait ressembler:

image

Créer un contrôle segmenté


Ensuite, nous allons créer un contrôle segmenté, qui est une barre grise contenant trois sections. En fait, un contrôle segmenté est facile à créer. Procédez comme suit:

 lazy var segmentedControl: UISegmentedControl = { let control = UISegmentedControl(items: ["Personal", "Social", "Resumè"]) control.autoSetDimension(.height, toSize: 32.0) control.selectedSegmentIndex = 0 control.layer.borderColor = UIColor.gray.cgColor control.tintColor = .gray return control }() 

Je crois que tout est clair, la seule différence est qu'après l'initialisation, nous lui fournissons un tableau de chaînes, chaque ligne représente l'en-tête de l'une de nos sections souhaitées. Nous avons également défini selectedSegmentIndex sur 0, ce qui indique au contrôle segmenté de sélectionner / sélectionner le premier segment lors de l'initialisation. Le reste n'est qu'un style avec lequel jouer.

Continuons maintenant et ajoutons-le en tant que sous-vue en insérant la ligne suivante à la fin de la fonction addCubviews(): self.view.addSubview(segmentedControl) et ses limitations seront comme ceci:

  segmentedControl.autoPinEdge(toSuperviewEdge: .left, withInset: 8.0) segmentedControl.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0) segmentedControl.autoPinEdge(.top, to: .bottom, of: avatar, withOffset: 16.0) 

Nous indiquons au contrôle segmenté que nous voulons l'attacher au côté gauche de sa vue d'ensemble, mais nous voulons augmenter légèrement l'intervalle, et non l'attacher directement au bord de l'écran. Si vous remarquez, j'utilise la soi-disant grille à huit points, où toutes les distances et tailles sont des multiples de huit. Je fais de même sur le côté droit du contrôle segmenté. Quant à la dernière limitation, il dit attacher un sommet à la base de l'avatar avec un intervalle de 16 points.

Après avoir ajouté les limitations ci-dessus à func setupConstraints() exécutez le code et assurez-vous qu'il ressemble à ceci:

image

Ajout d'un bouton


Passons maintenant à la dernière partie de l'interface utilisateur du manuel, qui est un bouton «Modifier». Ajoutez la variable paresseuse suivante:

 lazy var editButton: UIButton = { let button = UIButton() button.setTitle("Edit", for: .normal) button.setTitleColor(.gray, for: .normal) button.layer.cornerRadius = 4.0 button.layer.borderColor = UIColor.gray.cgColor button.layer.borderWidth = 1.0 button.tintColor = .gray button.backgroundColor = .clear button.autoSetDimension(.width, toSize: 96.0) button.autoSetDimension(.height, toSize: 32.0) return button }() 

Ne vous inquiétez pas de la taille de l'initialisation, mais faites attention à la façon dont je définis le titre et sa couleur en appelant les fonctions button.setTitle et button.setTitleColor . Pour certaines raisons, nous ne pouvons pas définir le titre d'un bouton en accédant directement à son titleLabel , et cela parce qu'il existe différents états pour le bouton, et il serait pratique pour beaucoup d'avoir des en-têtes / couleurs différents pour différents états.

Ajoutez maintenant le bouton en tant que sous-vue, comme le reste des composants, et ajoutez les restrictions suivantes pour qu'il apparaisse où il devrait être:

 editButton.autoPinEdge(.top, to: .bottom, of: upperView, withOffset: 16.0) editButton.autoPinEdge(toSuperviewEdge: .right, withInset: 8.0) 

Ici, nous définissons uniquement les limites droite et supérieure du bouton, car nous lui avons donné une taille, il ne se développera pas et rien d'autre ne sera nécessaire. Exécutez maintenant le projet pour voir le résultat final:

image

Quelques notes récentes


Entrainez-vous, ajoutez autant d'éléments d'interface que vous le souhaitez. Créez des vues de toute application que vous trouvez difficile. Commencez simplement et augmentez progressivement la difficulté. Essayez de dessiner des composants d'interface utilisateur sur une feuille de papier pour imaginer comment ils s'emboîtent.
Dans la deuxième partie, j'étends ce guide pour créer une barre de navigation, une vue tabulaire et des cellules de taille dynamique dans le code.

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


All Articles