J'utilise une UITableView
groupée avec des cellules statiques pour un écran/une scène d'options. Tout est fait dans Xcode 6.1/iOS 8.1.x/Storyboard avec Autolayout. Dans les groupes de tables, il y a plusieurs types de cellules et il y a deux types de problèmes:
Sur la cellule n ° 1, je peux définir une contrainte pour la marge gauche entre l'étiquette et le conteneur de tête. Dans la cellule 2, je ne peux pas définir de contrainte dans Interface Builder pour autant que je sache. J'ai défini la marge de gauche sur l'étiquette de la cellule n ° 1 afin qu'elle s'aligne sur l'étiquette de la cellule n ° 2. Tout semble bien sur un iPhone, mais si je montre la même table sur un iPad où la taille du conteneur de la vue de table est la moitié de la taille de l'écran, la cellule n ° 2 obtient plus de marge (dynamiquement?), Tandis que la cellule n ° 1 conserve la marge absolue. définir dans les contraintes. J'ai aussi essayé de changer la marge de gauche dans la cellule n ° 1 avec l'attribut "relatif à la marge" mais en vain.
iPhone:
iPad (avec une largeur de table = 1/2 taille d'écran)
La question est donc la suivante: comment définir les contraintes pour l’étiquette dans la cellule n ° 1 afin qu’elle s’aligne comme la cellule n ° 2.
Voici également un lien vers un exemple de projet Xcode 6.1 illustrant le problème. Courez sur iPhone et iPad pour voir la différence:
https://dl.dropboxusercontent.com/u/5252156/Code/tableViewTest.Zip
Cette question peut être liée à Cellule de tableau statique Layout pour iPhone et iPad , mais elle pourrait également différer pour iOS 8, étant donné que tout est censé être adaptatif maintenant. C'est pourquoi j'ai décidé de poster cette question de toute façon.
Après avoir lutté contre l'équipe de rapports de bogues d'Apple avec de nombreux exemples de projets et de captures d'écran et disséqué cette réponse , j'ai trouvé la solution pour que vos cellules de style personnalisé se comportent de manière cohérente en ce qui concerne leurs marges et soient exactement comme les UITableViewCells par défaut, vous devez faire ce qui suit (principalement basé sur la réponse de Becky , j'ai souligné ce qui est différent et ce qui l'a fait fonctionner pour moi):
Dans la section Marges de mise en page, cochez Conserver les marges de superview} (ne cliquez pas sur le signe plus).
(Et voici la clé) Faites la même chose {pour la cellule elle-même} _ (le parent de la vue de contenu si vous voulez)
Configurez vos contraintes comme suit: Label.Leading = Superview.Leading Margin (avec une constante de 0)
Désormais, toutes vos cellules auront leur étiquette conforme aux cellules par défaut! Cela fonctionne pour moi dans Xcode 7 et versions ultérieures et inclut le correctif mentionné dans le fil auquel j'ai fait référence. IB et le simulateur doivent maintenant afficher des étiquettes correctement alignées.
Vous pouvez également le faire par programme, par exemple dans la classe du contrôleur de vue:
cell.preservesSuperviewLayoutMargins = true
cell.contentView.preservesSuperviewLayoutMargins = true
Vous pouvez également le configurer en appelant UIAppearance une fois au démarrage (je ne connais que Swift, désolé):
UITableViewCell.appearance().preservesSuperviewLayoutMargins = true
UITableViewCell.appearance().contentView.preservesSuperviewLayoutMargins = true
Comme Ethan a gentiment fait remarquer, la documentation d’Apple sur UIView décrit preservesSuperviewLayoutMargins
comme suit:
Lorsque la valeur de cette propriété est
true
, les marges de superview sont également prises en compte lors de la présentation du contenu. Cette marge affecte les dispositions où la distance entre le bord d'une vue et son aperçu est inférieure à la marge correspondante. Par exemple, vous pouvez avoir une vue de contenu dont le cadre correspond précisément aux limites de son aperçu. Lorsque l’une des marges de la vue de dessus est à l’intérieur de la zone représentée par la vue du contenu et de ses propres marges, UIKit ajuste la disposition de la vue de contenu pour respecter les marges de la vue de dessus. Le montant de l’ajustement est le plus petit montant nécessaire pour que le contenu se trouve également dans les marges de Superview.
Par conséquent, si vous souhaitez que le contenu de votre cellule s'aligne sur les marges TableView (c'est un arrière-grand-parent si vous le souhaitez), vous devez conserver les deux ascendants de votre contenu, Affichage du contenu et la cellule du tableau de leur propre superview.
Pourquoi ce comportement n'est pas par défaut me surprend: je pense que la plupart des développeurs qui ne souhaitent pas tout personnaliser s'attendent à ce que cet "héritage" soit configuré par défaut.
J'ai eu le même problème que vous et j'ai trouvé une solution.
Tout d’abord, un peu d’arrière-plan: depuis iOS 8, les cellules d’affichage de tableau par défaut respectent la variable layoutMargins
de la cellule et s’adaptent à différents traits (écrans, ou appareils). Par exemple, les marges de mise en page sur tous les iPhones (à l'exception de l'iPhone 6 Plus dans une feuille de formulaire) sont {8, 16, 8, 16}
. Sur iPad, ils sont {8, 20, 8, 20}
. Nous savons maintenant qu'il existe une différence de 4 pixels, ce que votre cellule d'affichage de tableau personnalisé ne respecte probablement pas.
La sous-classe de cellules de votre vue tableau doit adapter la contrainte de marge de gauche lorsque layoutMargins change.
Voici l'extrait de code pertinent:
- (void)layoutMarginsDidChange
{
[super layoutMarginsDidChange];
self.leftLayoutMarginConstraint.constant = self.layoutMargins.left;
self.rightLayoutMarginConstraint.constant = self.layoutMargins.right;
}
L’adaptation aux marges du code de mise en page vous permet d’obtenir le bon remplissage pour votre titre.
Vous pouvez également consulter l'une de mes sous-classes UITableViewCell qui respecte déjà layoutMargins: https://github.com/bhr/BHRExtensions/blob/master/BHRExtensions/Utilities/BHRTitleAndValueTableCell.m
À votre santé
Après avoir lu les réponses existantes et ne pas avoir trouvé de solution programmatique évidente, j’ai creusé un peu plus et ai maintenant une bonne réponse pour tous ceux qui sont confrontés à ce problème.
Tout d'abord, il n'est pas nécessaire de définir preservesSuperviewLayoutMargins
dans la vue de la cellule ou dans la vue du contenu sous autreréponses imply. Alors que la valeur par défaut est false
, le changer en true
n'a eu aucun effet notable que je pouvais voir.
La clé pour que cela fonctionne réellement est la propriété layoutMarginsGuide
sur UIView
. En utilisant cette valeur, nous pouvons simplement épingler la leadingAnchor
de toute sous-vue à la leadingAnchor
du guide. Voici à quoi cela ressemble dans le code (et peut très bien être ce que fait IB dans les coulisses comme dans réponse de Jonas ).
Dans une sous-classe UITableViewCell
, vous feriez quelque chose comme ceci:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraintEqualToAnchor(leading).active = true
subview2.leadingAnchor.constraintEqualToAnchor(leading).active = true
super.updateConstraints()
}
Mise à jour Swift 4.1
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
let leading = margins.leadingAnchor
subview1.leadingAnchor.constraint(equalTo: leading).isActive = true
subview2.leadingAnchor.constraint(equalTo: leading).isActive = true
super.updateConstraints()
}
C'est tout! Si vous développez des versions pour iOS antérieures à iOS 9, vous devrez remplacer les ancres de présentation et utiliser plutôt l'encart layoutMargins
.
Note: J'ai écrit une bibliothèque pour que l'ancre soit un peu plus jolie, si vous préférez une syntaxe plus propre. Il s'appelle SuperLayout et est disponible sur Cocoapods. En haut de votre fichier source, importez SuperLayout
:
import SuperLayout
Ensuite, dans votre bloc de présentation, utilisez ~~
, ≤≤
et ≥≥
pour épingler des contraintes:
override func updateConstraints() {
let margins = contentView.layoutMarginsGuide
subview1.leadingAnchor ~~ margins.leadingAnchor
subview2.leadingAnchor ~~ margins.leadingAnchor
super.updateConstraints()
}
J'ai pu obtenir des cellules avec des styles personnalisés alignés sur les cellules standard en procédant comme suit:
Cela a fonctionné pour moi dans Xcode 7; J'espère que cela fonctionnera également dans Xcode 6.
J'ai eu ce problème lors de tests sur un iPad Air, OS 10.1.1. Les en-têtes de table étaient en retrait beaucoup plus loin qu'ils n'auraient dû l'être, et c'était encore pire en orientation paysage. Mais ils étaient bien sur les iphones jusqu’à OS 11.
La solution surprenante était la ligne de code suivante, juste après la création de la table (désolé, je ne travaille qu'en C #, mais il est facile de résoudre les équivalents Obj-C et Swift):
myTableView.SeparatorInset = myTableView.SeparatorInset;
Ensuite, tout était en retrait comme il se doit!