Meetup CocoaHeads Montpellier : conférence sur l'Auto Layout
-
Upload
backelite -
Category
Technology
-
view
2.199 -
download
2
Transcript of Meetup CocoaHeads Montpellier : conférence sur l'Auto Layout
AUTO LAYOUTCOCOAHEADS - MONTPELLIER - 12 MAI 2016
13 MAI 2016 BACKELITEBACKELITE
SOMMAIRE
Introduction Comprendre l’Auto Layout Utiliser l’Auto Layout Maîtriser l’Auto Layout Bonnes pratiques
2
INTRODUCTION
13 MAI 2016 BACKELITE
UTILISATION MULTI-CONTEXTE
L’interface utilisateur doit répondre dynamiquement à 2 types de changements :
• changements externes
• changements internes
4
13 MAI 2016 BACKELITE
CHANGEMENTS EXTERNES
• Utilisateur redimensionne la fenêtre de l’application (OS X) • Utilisateur ouvre / ferme le Split View sur un iPad • La rotation de l’appareil • L’apparition / disparition de la barre de status en mode (enregistrement,
appel en cours…) • Le support de différentes catégories de tailles d’écran (size classes) • Le support de différentes tailles d’écran
5
13 MAI 2016 BACKELITE
CHANGEMENTS INTERNES
• Le contenu affiché change • Le support de l’internationalisation • le support des types dynamiques
6
LES TROIS APPROCHES PRINCIPALES
7
Les Frames L’AutoresizingMask L’Auto Layout
13 MAI 2016 BACKELITE
LES FRAMES
Le calcul des frames : le moyen le plus flexible et le plus puissant
mais…
• ne supporte que les changements externes • requiert un effort considérable pour designer, à débogguer et à maintenir • l’effort augmente d'autant plus que l'interface doit être dynamique.
8
13 MAI 2016 BACKELITE
L’AUTORESIZINGMASK
Simplifie la création de mise en page (layout) Permet d’alléger l’effort de design
mais…
• Ne convient que pour des agencements simples. • Ne supporte que les changements externes.
9
13 MAI 2016 BACKELITE
L’AUTO LAYOUT
• Supporte les changements externes et internes. • Gère une plus large palette d’agencement. • Allége l’effort de design, de déboggage et de maintenance même pour les
mises en page complexe.
10
COMPRENDRE L'AUTO LAYOUT
13 MAI 2016 BACKELITE
QU’EST CE QUE L’AUTO LAYOUT ?
L’Auto Layout
est un système d’agencement, de mise en page, descriptif basé sur des contraintes
12
Calcule dynamiquement la taille ainsi que les dimensions de toutes les vues de la hiérarchie en fonction de contraintes placées sur ces vues.
13 MAI 2016 BACKELITE
ANATOMIE D’UNE CONTRAINTE
13
13 MAI 2016 BACKELITE
LES ATTRIBUTS
14
13 MAI 2016 BACKELITE
LES RELATIONS
// Egalité Blue.leading = 1.0 * Red.trailing + 8.0
// Supériorité View.width >= 0.0 * NotAnAttribute + 40.0 // Infériorité View.width <= 0.0 * NotAnAttribute + 280.0
15
13 MAI 2016 BACKELITE
LES PRIORITÉS
• Priorité vont de 1 à 1000 • Required est 1000 • DefaultHigh est 750 • DefaultLow est 250 • Les priorités les plus fortes l’emporte
16
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• La plupart des vues n’ont pas de taille préfixée • D’autres ont une taille prédéfinie
• sizeToFit • sizeThatFits:
• Avec l’Auto Layout, cette taille se nomme l’intrinsicContentSize
17
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
18
Vue Intrinsic Content Size
UIView -
UISlider Largeur
UILabels, UIButton, UISwitch, UITextfield Hauteur et largeur
UITextView, UIImageView Peut varié
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• intrinsicContentSize() est mieux que sizeToFit() • Appeler invalidateIntrinsicContentSize() à chaque que l’intrinsicContentSize
doit être recalculé
19
public func intrinsicContentSize() -> CGSize
public func invalidateIntrinsicContentSize()
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• L’intrinsicContentSize génère deux contraintes par dimensions
20
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• L’intrinsicContentSize génère deux contraintes par dimensions
21
view.height >= 0.0 x NotAnAttribute + intrinsicContentSize.height
view.height <= 0.0 x NotAnAttribute + intrinsicContentSize.height
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• L’intrinsicContentSize génère deux contraintes par dimensions
22
view.height >= 0.0 x NotAnAttribute + intrinsicContentSize.height view.width >= 0.0 x NotAnAttribute + intrinsicContentSize.width
view.height <= 0.0 x NotAnAttribute + intrinsicContentSize.height view.width <= 0.0 x NotAnAttribute + intrinsicContentSize.width
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• L’intrinsicContentSize génère deux contraintes par dimensions
23
view.height >= 0.0 x NotAnAttribute + intrinsicContentSize.height view.width >= 0.0 x NotAnAttribute + intrinsicContentSize.width
view.height <= 0.0 x NotAnAttribute + intrinsicContentSize.height view.width <= 0.0 x NotAnAttribute + intrinsicContentSize.width
Content Compression Resistance
13 MAI 2016 BACKELITE
INTRINSIC CONTENT SIZE
• L’intrinsicContentSize génère deux contraintes par dimensions
24
view.height >= 0.0 x NotAnAttribute + intrinsicContentSize.height view.width >= 0.0 x NotAnAttribute + intrinsicContentSize.width
view.height <= 0.0 x NotAnAttribute + intrinsicContentSize.height view.width <= 0.0 x NotAnAttribute + intrinsicContentSize.width
Content Compression Resistance
Content Hugging
13 MAI 2016 BACKELITE
CONTENT HUGGING & CONTENT COMPRESSION
25
13 MAI 2016 BACKELITE
CONTENT HUGGING & CONTENT COMPRESSION
• Il est possible de modifier leur priorités
26
func setContentHuggingPriority(priority: UILayoutPriority, forAxis axis: UILayoutConstraintAxis)
func setContentCompressionResistancePriority(priority: UILayoutPriority, forAxis axis: UILayoutConstraintAxis)
13 MAI 2016 BACKELITE
LE PROCESSUS D’AGENCEMENT
27
Vues
Contraintes
Priorités
intrinsic ContentSize
Moteur d’agencement (layout engine)
Mise en page (layout)
13 MAI 2016 BACKELITE
LE PROCESSUS D’AGENCEMENT
28
Constraints
change
Update Pass
Layout Pass
Display
Application Run Loop
13 MAI 2016 BACKELITE
LE PROCESSUS D’AGENCEMENT
Les changements d’une contrainte • activation / désactivation • changement de la constant ou de la priorité • suppression de la vue dans la hiérarchie
Le moteur d’agencement recalcule la mise en page : • lorsqu’il reçoit de nouvelles valeurs • Les vues appellent superview.setNeedsLayout()
29
13 MAI 2016 BACKELITE
LE PROCESSUS D’AGENCEMENT
updateConstraintes est appelé • A chaque cycle du moteur d’agencement • Lorsqu’on fait appel à setNeedsUpdateConstraintes()
Overrider lorsque : • Les changements des contraintes est trop lents • Une vue fait régulièrement des changements sur ses contraintes • Appel du super à la fin de la méthode
30
13 MAI 2016 BACKELITE
LE PROCESSUS D’AGENCEMENT
La phase de Layout
Traverse la hiérarchie de vue de haut en bas • Appel à layoutSubviews()
Positionne les frames de chaque sous-vue • Copie les frames venant du moteur d’agencement
31
13 MAI 2016 BACKELITE
LES PROBLÈMES QUE L’ON PEUT RENCONTRER
Layout ambiguë : plusieurs agencements sont possibles • Pas assez de contraintes • Contraintes optionnels dont la priorité sont égales
Layout insatisfait : aucun agencement possible • Certaines contraintes se contredisent
32
UTILISER L'AUTO LAYOUT
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
Le canvas permet :
• de créer rapidement, via un clique droit + glisser, une contrainte entre deux vue.
34
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
Le panneau « Structure de document » permet :
• de lister les contraintes • de créer via un clique droit +
glisser rapidement des contraintes entre deux vues.
35
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
L’outil d’alignement permet de rapidement ajouter des contraintes sur les centres et les bordures
36
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
L’outils de résolutions des problèmes d’Auto Layout permet :
• d’ajouter les contraintes manquantes
• de repositionner et redimensionner les vues mal positionnées
• de faire une remise à zéro des contraintes
• de supprimer tous les contraintes
37
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
L’inspecteur de taille permet :
• de lister toutes les contraintes qui affectent la vue sélectionnée.
• de filtrer les contraintes suivant les classes de tailles.
• de filtrer les contraintes par leur type attributs (leading, trailing…)
38
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
L’inspecteur de taille permet :
• de modifier rapidement la constante, la relation et la priorité d’une contrainte
39
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
L’inspecteur d’attributs permet :
• de modifier la relation, la priorité, la constante, le multiplier de la contrainte
• d’intervertir le premier et le deuxième élément
• de marquer la contrainte comme fictive
40
13 MAI 2016 BACKELITE
VIA INTERFACE BUILDER
L’inspecteur d’attributs permet :
• de modifier les priorités des content hugging et content compression
• de définir une largeur et une hauteur fictives pour le contenu (intrinsicContentSize)
41
13 MAI 2016 BACKELITE
VIA LE CODE
item1.attribute1 = multiplier x item2.attribute2 + constant
42
public convenience init(item view1: AnyObject, attribute attr1: NSLayoutAttribute, relatedBy relation: NSLayoutRelation, toItem view2: AnyObject?, attribute attr2: NSLayoutAttribute, multiplier: CGFloat, constant c: CGFloat)
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX
43
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX
44
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX
45
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX
46
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = 1.0 x superview.centerX
47
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX
48
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX
49
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
VIA LE CODE
• button.centerX = superview.centerX + 0.0
50
NSLayoutConstraint(item: button, attribute: .CenterX, relatedBy: .Equal, toItem: superview, attribute: .CenterX, multiplier: 1.0,
constant: 0.0)
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
• button.bottom = superview.bottom - <padding>
NSLayoutConstraint(item: button, attribute: .Bottom, relatedBy: .Equal, toItem: superview, attribute: .Bottom, multiplier: 1.0,
constant: -padding)
VIA LE CODE
51
item1.attribute1 = multiplier x item2.attribute2 + constant
13 MAI 2016 BACKELITE
NSLAYOUTANCHOR
• Simplifie la création de contrainte • Facilite la lisibilité
52
b.topAnchor.constraintEqualToAnchor(view.topAnchor, constant:10)
b.leadingAnchor.constraintEqualToAnchor(view.leadingAnchor, constant:10)
NSLayoutConstraint(item:b, attribute: .Top, relatedBy: .Equal, toItem:view, attribute:.Top, multiplier:1, constant:10)
NSLayoutConstraint(item:b, attribute:.Leading, relatedBy:.Equal, toItem:view, attribute:.Leading, multiplier:1, constant:10)
13 MAI 2016 BACKELITE
NSLAYOUTANCHOR
• Empêche la création de contrainte invalide
53
v1.leadingAnchor.constraintEqualToConstant(100) // Error: may not respond to method
v1.leadingAnchor.constraintEqualToAnchor(v2.widthAnchor) // Error: incompatible pointer type
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
• Simplifie la création de contraintes • Facilite la lisibilité • Supporte les relations, les priorités, les alignements
54
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
55
cancelButton acceptButton
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
56
[cancelButton]-[acceptButton]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
57
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton]-[acceptButton]", options: [], metrics: nil, views: viewsDictionary)
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
58
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton]-[acceptButton]", options: [], metrics: nil, views: viewsDictionary)
let cancelButton: UIButton = … let acceptButton: UIButton = … let viewsDictionary = ["cancelButton": cancelButton, "acceptButton": acceptButton]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
59
[cancelButton]-[acceptButton]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
60
[cancelButton ]— -[acceptButton ]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
61
[cancelButton(72)]—12-[acceptButton(50)]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
62
[cancelButton(72 )]—12-[acceptButton(50)]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
63
[cancelButton(72@250)]—12-[acceptButton(50)]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
64
[cancelButton(72@250)]—12-[acceptButton(50)]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
65
[cancelButton(72@250)]—12-[acceptButton( 50)]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
66
[cancelButton(72@250)]—12-[acceptButton(>=50)]
13 MAI 2016 BACKELITE
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton(72@250)]—12-[acceptButton(>=50)]", options: [], metrics: nil, views: viewsDictionary)
LE LANGUAGE DU FORMAT VISUEL
67
13 MAI 2016 BACKELITE
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton(72@250)]—( )-[acceptButton(>=50)]", options: [], metrics: metricsDictionary, views: viewsDictionary)
LE LANGUAGE DU FORMAT VISUEL
68
13 MAI 2016 BACKELITE
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton(72@250)]—(spacing)-[acceptButton(>=50)]", options: [], metrics: metricsDictionary, views: viewsDictionary)
LE LANGUAGE DU FORMAT VISUEL
69
13 MAI 2016 BACKELITE
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton(72@ )]—(spacing)-[acceptButton(>=50)]", options: [], metrics: metricsDictionary, views: viewsDictionary)
LE LANGUAGE DU FORMAT VISUEL
70
13 MAI 2016 BACKELITE
NSLayoutConstraint.constraintsWithVisualFormat( "[cancelButton(72@p)]—(spacing)-[acceptButton(>=50)]", options: [], metrics: metricsDictionary, views: viewsDictionary)
LE LANGUAGE DU FORMAT VISUEL
71
let metricsDictionary = ["spacing": 12, "p": 250]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
72
[cancelButton]-[acceptButton]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
73
[cancelButton]-[acceptButton ]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
74
[cancelButton]-[acceptButton(==cancelButton)]
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
75
|[cancelButton]-[acceptButton(==cancelButton)]|
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
76
| [cancelButton]-[acceptButton(==cancelButton)] |
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
77
|-[cancelButton]-[acceptButton(==cancelButton)]-|
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
78
|- -[cancelButton]-[acceptButton(==cancelButton)]- -|
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
79
|-5-[cancelButton]-[acceptButton(==cancelButton)]-5-|
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
80
H:|-5-[cancelButton]-[acceptButton(==cancelButton)]-5-|
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
81
H:|-5-[cancelButton]-[acceptButton(==cancelButton)]-5-|
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
82
NSLayoutConstraint.constraintsWithVisualFormat( "H:|-5-[cancelButton]-[acceptButton(==cancelButton)]-5-|", options: [], metrics: metricsDictionary, views: viewsDictionary)
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
83
NSLayoutConstraint.constraintsWithVisualFormat( "H:|-5-[cancelButton]-[acceptButton(==cancelButton)]-5-|", options: options, metrics: metricsDictionary, views: viewsDictionary)
let options: NSLayoutFormatOptions = .AlignAllTop
13 MAI 2016 BACKELITE
LE LANGUAGE DU FORMAT VISUEL
84
NSLayoutConstraint.constraintsWithVisualFormat( "V:|-5-[cancelButton]-[acceptButton(==cancelButton)]-5-|", options: options, metrics: metricsDictionary, views: viewsDictionary)
let options: NSLayoutFormatOptions = .AlignAllCenterX
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
• Méthodes sur UIView
85
// ajout public func addConstraint(constraint: NSLayoutConstraint) public func addConstraints(constraints: [NSLayoutConstraint])
// suppression public func removeConstraint(constraint: NSLayoutConstraint) public func removeConstraints(constraints: [NSLayoutConstraint])
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
translatesAutoresizingMaskIntoConstraints • convertit les frames en contraintes • est à true pour les contraintes créer via le code
• Si on utilise les frames, le mettre à true • Sinon ne pas oublier de le mettre a false !
86
v1.translatesAutoresizingMaskIntoConstraints = false
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
87
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
88
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
89
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
90
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
91
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
92
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
93
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
AJOUT DE CONTRAINTES
94
Sur quelle vue ajouter les contraintes ?
13 MAI 2016 BACKELITE
ACTIVATION / DÉSACTIVATION DE CONTRAINTES
• Méthodes sur NSLayoutConstraint
95
// activation - désactivation + (void)activateConstraints:(NSArray *)constraint; + (void)deactivateConstraints:(NSArray *)constraint;
13 MAI 2016 BACKELITE
AUTO LAYOUT ET LES LABELS
UILabel multi-ligne : • Mettre le nombre de ligne à 0 • preferredMaxLayoutWidth indique la largeur pour le retour à la ligne • Ajuster les priorités de content hugging et content compression
< iOS 8 : • preferredMaxLayoutWidth != frame • doit mettre la jour preferredMaxLayoutWidth à la main
96
13 MAI 2016 BACKELITE
AUTO LAYOUT ET SCROLLVIEW
• Défini la contentSize de la scrollView • L’ensemble des contraintes doit relier les bords de la scrollview • Utilise une contentView pour facilité la création du layout • Scroll horizontal : contentView.width > scrollview.width • Scroll vertical : contentView.height > scrollview.height
97
13 MAI 2016 BACKELITE
AUTO LAYOUT ET SCROLLVIEW
98
UIScrollview
ContentView
View View
View
View
13 MAI 2016 BACKELITE
ANIMATION
// Ensures that all pending layout operations have been completed containerView.layoutIfNeeded()
UIView.animateWithDuration(1.0) { // Make all constraint changes here myConstraint.constant = 0.0 // Forces the layout of the subtree animation block // and then captures all of the frame changes containerView.layoutIfNeeded()
}
99
MAÎTRISER L'AUTO LAYOUT
13 MAI 2016 BACKELITE
COMPRENDRE LES LOGS DE LA CONSOLE
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "<NSLayoutConstraint:0x7fff2b5b1050 H:[UIButton:0x7fff2b5ad100'Envoyer'(200)]>", "<NSLayoutConstraint:0x7fff2b5b0550 UITextField:0x7fff2b5a34a0.leading == UIView:0x7fff2b5a3e70.leadingMargin>", "<NSLayoutConstraint:0x7fff2b5b0be0 H:[UITextField:0x7fff2b5a34a0(>=250)]>", "<NSLayoutConstraint:0x7fff2b5b0d40 H:[UITextField:0x7fff2b5a34a0]-(NSSpace(8))-[UIButton:0x7fff2b5ad100'Envoyer']>", "<NSLayoutConstraint:0x7fff2b5b0e00 UIView:0x7fff2b5a3e70.trailingMargin == UIButton:0x7fff2b5ad100'Envoyer'.trailing>", "<NSLayoutConstraint:0x7fff2b646d30 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fff2b5a3e70(414)]>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fff2b5b1050 H:[UIButton:0x7fff2b5ad100'Envoyer'(200)]>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
101
13 MAI 2016 BACKELITE
COMPRENDRE LES LOGS DE LA CONSOLE
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "<NSLayoutConstraint:0x7fff2b5b1050 H:[UIButton:0x7fff2b5ad100'Envoyer'(200)]>", "<NSLayoutConstraint:0x7fff2b5b0550 UITextField:0x7fff2b5a34a0.leading == UIView:0x7fff2b5a3e70.leadingMargin>", "<NSLayoutConstraint:0x7fff2b5b0be0 H:[UITextField:0x7fff2b5a34a0(>=250)]>", "<NSLayoutConstraint:0x7fff2b5b0d40 H:[UITextField:0x7fff2b5a34a0]-(NSSpace(8))-[UIButton:0x7fff2b5ad100'Envoyer']>", "<NSLayoutConstraint:0x7fff2b5b0e00 UIView:0x7fff2b5a3e70.trailingMargin == UIButton:0x7fff2b5ad100'Envoyer'.trailing>", "<NSLayoutConstraint:0x7fff2b646d30 'UIView-Encapsulated-Layout-Width' H:[UIView:0x7fff2b5a3e70(414)]>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fff2b5b1050 H:[UIButton:0x7fff2b5ad100'Envoyer'(200)]>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
102
13 MAI 2016 BACKELITE
COMPRENDRE LES LOGS DE LA CONSOLE
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "<NSLayoutConstraint:0x7ff6da1803e0 H:[sendButton(200)] (Names: sendButton:0x7ff6da17b940 )>", "<NSLayoutConstraint:0x7ff6da17f1e0 messageTextField.leading == Superview.leadingMargin (Names: messageTextField:0x7ff6da145570, Superview:0x7ff6da173c20 )>", "<NSLayoutConstraint:0x7ff6da17fd70 H:[messageTextField(>=250)] (Names: messageTextField:0x7ff6da145570 )>", "<NSLayoutConstraint:0x7ff6da17fed0 H:[messageTextField]-(NSSpace(8))-[sendButton] (Names: sendButton:0x7ff6da17b940, messageTextField:0x7ff6da145570 )>", "<NSLayoutConstraint:0x7ff6da180190 Superview.trailingMargin == sendButton.trailing (Names: Superview:0x7ff6da173c20, sendButton:0x7ff6da17b940 )>", "<NSLayoutConstraint:0x7ff6d8c1c780 'UIView-Encapsulated-Layout-Width' H:[Superview(414)] (Names: Superview:0x7ff6da173c20 )>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7ff6da1803e0 H:[sendButton(200)] (Names: sendButton:0x7ff6da17b940 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
103
13 MAI 2016 BACKELITE
COMPRENDRE LES LOGS DE LA CONSOLE
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. ( "<NSLayoutConstraint:0x7fbeabc50340 messageTextField.leading == Superview.leadingMargin (Names: messageTextField:0x7fbeabc31020, Superview:0x7fbeabc43ce0 )>", "<NSLayoutConstraint:0x7fbeabc509b0 H:[messageTextField(>=250)] (Names: messageTextField:0x7fbeabc31020 )>", "<NSLayoutConstraint:0x7fbeabc50b10 H:[messageTextField]-(NSSpace(8))-[sendButton] (Names: sendButton:0x7fbeabc4ce10, messageTextField:0x7fbeabc31020 )>", "<NSLayoutConstraint:0x7fbeabc50bd0 Superview.trailingMargin == sendButton.trailing (Names: Superview:0x7fbeabc43ce0, sendButton:0x7fbeabc4ce10 )>", "<NSLayoutConstraint:0x7fbeabc50e20 'fixedWidthLayout' H:[sendButton(200)] (Names: sendButton:0x7fbeabc4ce10 )>", "<NSLayoutConstraint:0x7fbead92e6d0 'UIView-Encapsulated-Layout-Width' H:[Superview(414)] (Names: Superview:0x7fbeabc43ce0 )>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7fbeabc50e20 'fixedWidthLayout' H:[sendButton(200)] (Names: sendButton:0x7fbeabc4ce10 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
104
13 MAI 2016 BACKELITE
COMPRENDRE LES LOGS DE LA CONSOLE
Unable to simultaneously satisfy constraints. Probably at least one of the constraints in the following list is one you don't want. Try this: (1) look at each constraint and try to figure out which you don't expect; (2) find the code that added the unwanted constraint or constraints and fix it. (Note: If you're seeing NSAutoresizingMaskLayoutConstraints that you don't understand, refer to the documentation for the UIView property translatesAutoresizingMaskIntoConstraints) ( "<NSAutoresizingMaskLayoutConstraint:0x7ff2e5243430 h=--& v=--& messageTextField.midY == (Names: messageTextField:0x7ff2e522e700 )>", "<NSAutoresizingMaskLayoutConstraint:0x7ff2e52432b0 h=--& v=--& V:[messageTextField(0)] (Names: messageTextField:0x7ff2e522e700 )>", "<NSLayoutConstraint:0x7ff2e522ad40 V:[messageTextField]-(20)-| (Names: Superview:0x7ff2e522bcf0, messageTextField:0x7ff2e522e700, '|':Superview:0x7ff2e522bcf0 )>", "<NSLayoutConstraint:0x7ff2e354dc70 'UIView-Encapsulated-Layout-Height' V:[Superview(736)] (Names: Superview:0x7ff2e522bcf0 )>", "<NSAutoresizingMaskLayoutConstraint:0x7ff2e3567470 h=-&- v=-&- 'UIView-Encapsulated-Layout-Top' V:|-(0)-[Superview] (Names: Superview:0x7ff2e522bcf0, '|':UIWindow:0x7ff2e522b7c0 )>" )
Will attempt to recover by breaking constraint <NSLayoutConstraint:0x7ff2e522ad40 V:[messageTextField]-(20)-| (Names: Superview:0x7ff2e522bcf0, messageTextField:0x7ff2e522e700, '|':Superview:0x7ff2e522bcf0 )>
Make a symbolic breakpoint at UIViewAlertForUnsatisfiableConstraints to catch this in the debugger. The methods in the UIConstraintBasedLayoutDebugging category on UIView listed in <UIKit/UIView.h> may also be helpful.
105
13 MAI 2016 BACKELITE
COMPRENDRE LES LOGS DE LA CONSOLE
Ajout d’identifiants sur les contraintes
Ajout d’identifiants d’accessibilité sur les vues
Désactiver le translateAutoresizingMaskIntoConstraints
106
labelToTop.identifier = "labelToTop"
titleLabel.accessibilityIdentifier = "titleLabel"
sendButton.translatesAutoresizingMaskIntoConstraints = false
13 MAI 2016 BACKELITE
DETECTION DES LAYOUTS AMBIGUS
• hasAmbigousLayout retourne vrai si la vue a sa frame mal placé
• exerciceAmbiguityInLayout commute entre les différentes possibilité de layout
• constraintAffectingLayoutForAxis return la liste des contraintes associés à un axe
• _autolayoutTrace affiche un diagnostique sur la hiérarchie de vue entière
107
13 MAI 2016 BACKELITE
RÉSOUDRE LES LAYOUTS AMBIGUS
• Ajout de contraintes supplémentaires • Mais ce n’est pas toujours le cas • Modification des priorités des contraintes existantes
Content Hugging, Content Compression
108
13 MAI 2016 BACKELITE
DÉSACTIVER LE SCROLL VERTICAL D’UNE SCROLLVIEW
109
UIScrollview
ContentView
View View
View
View
0
0
=
=
13 MAI 2016 BACKELITE
DÉSACTIVER LE SCROLL HORIZONTAL D’UNE SCROLLVIEW
110
UIScrollview
ContentView
View View
View
View
0 0
=
=
13 MAI 2016 BACKELITE
VUE FLOTTANTE DANS UNE SCROLLVIEW
111
UIScrollview Container
UIScrollview
ContentView
View View
View
ViewView flottante
0
0
0
0
13 MAI 2016 BACKELITE
LE SPLIT VIEW
112
Split View
Master View Detail View
00
0 0
0
0
0
= 1/3 = x 3
13 MAI 2016 BACKELITE
LE SPLIT VIEW
113
Split View
Master View Detail View
0
0
0
0
0
= 1/3 = x 3
13 MAI 2016 BACKELITE
RÉPARTITION DE VUES DE MÊME TAILLE SUR UN AXE
114
Superview
Vue 1 Vue 2 Vue 3 Vue 4
= =
= =
= =
13 MAI 2016 BACKELITE
RÉPARTITION DE VUES DE MÊME TAILLE SUR UN AXE
115
Superview
=
Vue 1 Vue 2 Vue 3 Vue 4
= =
= =
=
13 MAI 2016 BACKELITE
RÉPARTITION DE VUES AVEC ESPACEMENT DE MÊME TAILLE SUR UN AXE
116
Superview
Vue 1 Vue 2 Vue 3
= =
=
= =
=
13 MAI 2016 BACKELITE
CENTRER UN GROUPE DE VUES
117
Superview
ConteneurVue
Vue
Vue
Vue0
0
0
0
13 MAI 2016 BACKELITE
UILAYOUTGUIDE
• Définie un rectangle qui peut interagir avec le moteur d’agencement. • Remplace les dummy views
118
let space1 = UILayoutGuide() view.addLayoutGuide(space1)
let space2 = UILayoutGuide() view.addLayoutGuide(space2)
space1.widthAnchor.constraintEqualToAnchor(space2.widthAnchor).active = true
saveButton.trailingAnchor.constraintEqualToAnchor(space1.leadingAnchor).active = true cancelButton.leadingAnchor.constraintEqualToAnchor(space1.trailingAnchor).active = true cancelButton.trailingAnchor.constraintEqualToAnchor(space2.leadingAnchor).active = true clearButton.leadingAnchor.constraintEqualToAnchor(space2.trailingAnchor).active = true
13 MAI 2016 BACKELITE
UILAYOUTGUIDE
• Définie un rectangle qui peut interagir avec le moteur d’agencement. • Remplace les dummy views
119
let space1 = UILayoutGuide() view.addLayoutGuide(space1)
let space2 = UILayoutGuide() view.addLayoutGuide(space2)
NSLayoutConstraint.constraintsWithVisualFormat( "H:[saveButton][space1][cancelButton][space2(==space1)][clearButton]",
options: .AlignAllBaseline, metrics: nil, views: views)
13 MAI 2016 BACKELITE
TOP/BOTTOM LAYOUT GUIDE
• Représente le bord du haut et du bas de la surface visible du viewController courant
• En dessous de la statusBar ou navigationBar • Au dessus de tabBar
120
13 MAI 2016 BACKELITE
LAYOUT MARGINS GUIDE
• Représente les marges de la vue • Utilise les valeurs le la propriété layoutMargins • Marges de 8 points par défaut sur chaque bord • Les marges de la vue racine d’un contrôleur ne sont pas modifiable
121
13 MAI 2016 BACKELITE
READABLE CONTENT GUIDE
• Définie la largeur maximal pour le texte • Dépends de la taille du type dynamique • Reste toujours entre les margins
122
13 MAI 2016 BACKELITE
SEMANTIC CONTENT ATTRIBUTES
• Détermine lorsque si la vue doit basculer lors d’un changement du sens de la lecture
• Les position Leading et trailing s’inversent • Alors que Top, Bottom, Left et Right ne bouge pas
123
BONNES PRATIQUES
13 MAI 2016 BACKELITE
BONNES PRATIQUES
• Ne plus utiliser les frames, bounds ou center pour changer les dimensions et la position de la vue
• Éviter de donner un largeur et longueur fixe à une vue • Donner des noms qui ont du sens à vos vues • Toujours utiliser Leading et Trailing • translateAutoresizingMaskIntoConstraints = NO • Utiliser les layoutMarginsGuides • Utiliser les readableContentGuides pour les textes
125
13 MAI 2016 BACKELITE
BONNES PRATIQUES
• Utiliser les topLayoutGuide et BottomLayoutGuide lorsque la vue s’étend sous les bars
• Evitez d’overrider le layoutSubviews() • Ne pensez plus frames mais relations • Activer / Désactiver les contraintes au lieu de les ajouter / retirer • Utiliser les baselines au lieu de top/bottom • Déterminer la taille d’un composant via ses contraintes • Override intrinsicContentSize judicieusement
126
13 MAI 2016 BACKELITE
BONNES PRATIQUES
• Utiliser les priorités pour résoudre votre layout • Garder en tête la localisation • Overrider updateContraints judicieusement • Ne jamais désactiver toutes les contraintes : self.view.constraints
127
13 MAI 2016 BACKELITE
QUELQUES LIENS
128
Références
Auto Layout Guide https://developer.apple.com/library/ios/documentation/UserExperience/Conceptual/AutolayoutPG/index.html#//apple_ref/doc/uid/TP40010853-CH7-SW1
Adopting Auto Layout
https://developer.apple.com/library/watchos/documentation/UserExperience/Conceptual/AutolayoutPG/AutoLayoutbyExample/AutoLayoutbyExample.html#//apple_ref/doc/uid/TP40010853-CH5-SW7
Mysteries of Auto Layout, Part 1
https://developer.apple.com/videos/play/wwdc2015/218/
Mysteries of Auto Layout, Part 2
https://developer.apple.com/videos/play/wwdc2015/219/
www.backelite.com
CONTACTEZ-NOUS
13 MAI 2016 BACKELITE 129
Mickael Laloum iOS Lead Developer