J'ai un simple UIStackView
horizontal avec plusieurs UIViews empilés à l'intérieur. Mon objectif est de créer un espacement variable entre les vues. Je suis bien conscient que je peux créer un espace constant entre les sous-vues en utilisant la propriété "espacement". Cependant, mon objectif est de créer un espace variable. Veuillez noter que, dans la mesure du possible, j'aimerais éviter d'utiliser des vues invisibles qui agissent comme des entretoises.
Le mieux que j’ai proposé était de placer ma UIViews
dans une UIStackView
séparée et d’utiliser layoutMarginsRelativeArrangement = YES
pour respecter les marges de la disposition de ma pile interne. J'espérais pouvoir faire quelque chose de similaire avec n'importe quelle UIView
sans recourir à cette horrible solution de contournement. Voici mon exemple de code:
// Create stack view
UIStackView *stackView = [[UIStackView alloc] init];
stackView.translatesAutoresizingMaskIntoConstraints = NO;
stackView.axis = UILayoutConstraintAxisHorizontal;
stackView.alignment = UIStackViewAlignmentCenter;
stackView.layoutMarginsRelativeArrangement = YES;
// Create subview
UIView *view1 = [[UIView alloc] init];
view1.translatesAutoresizingMaskIntoConstraints = NO;
// ... Add Auto Layout constraints for height / width
// ...
// I was hoping the layoutMargins would be respected, but they are not
view1.layoutMargins = UIEdgeInsetsMake(0, 25, 0, 0);
// ... Create more subviews
// UIView view2 = [[UIView alloc] init];
// ...
// Stack the subviews
[stackView addArrangedSubview:view1];
[stackView addArrangedSubview:view2];
Le résultat est une pile avec des vues côte à côte avec espacement:
Mise à jour pour iOS 11, StackViews avec espacement personnalisé
Apple a ajouté la possibilité de définir l'espacement personnalisé dans iOS 11. Vous devez simplement spécifier l'espacement après chaque sous-vue arrangée. Malheureusement, vous ne pouvez pas spécifier d'espacement auparavant.
stackView.setCustomSpacing(10.0, after: firstLabel)
stackView.setCustomSpacing(10.0, after: secondLabel)
Encore mieux que d’utiliser vos propres vues.
Pour iOS 10 et inférieur
Vous pouvez simplement ajouter des vues transparentes dans votre vue de pile et leur ajouter des contraintes de largeur.
(Label - UIView - Label - UIView -Label)
et si vous laissez distribution
pour remplir, vous pouvez configurer des contraintes de largeur variable sur vos vues UIV.
Mais je considérerais si c'est la bonne situation pour utiliser des vues de pile si c'est le cas. La fonction Autolayout facilite grandement l’installation de largeurs variables entre les vues.
De Rob's response j'ai créé une extension UIStackView qui pourrait aider:
extension UIStackView {
func addCustomSpacing(_ spacing: CGFloat, after arrangedSubview: UIView) {
if #available(iOS 11.0, *) {
self.setCustomSpacing(spacing, after: arrangedSubview)
} else {
let separatorView = UIView(frame: .zero)
separatorView.translatesAutoresizingMaskIntoConstraints = false
switch axis {
case .horizontal:
separatorView.widthAnchor.constraint(equalToConstant: spacing).isActive = true
case .vertical:
separatorView.heightAnchor.constraint(equalToConstant: spacing).isActive = true
}
if let index = self.arrangedSubviews.firstIndex(of: arrangedSubview) {
insertArrangedSubview(separatorView, at: index + 1)
}
}
}
}
Vous pouvez l'utiliser et le modifier à votre guise, par exemple si vous voulez la référence "separatorView", vous pouvez simplement renvoyer l'UIView:
func addCustomSpacing(_ spacing: CGFloat, after arrangedSubview: UIView) -> UIView?
Swift 4
Après la réponse de lilpit, voici une extension de UIStackView pour ajouter un espacement supérieur et inférieur à votre vue arrangée
extension UIStackView {
func addCustomSpacing(top: CGFloat, bottom: CGFloat) {
//If the stack view has just one arrangedView, we add a dummy one
if self.arrangedSubviews.count == 1 {
self.insertArrangedSubview(UIView(frame: .zero), at: 0)
}
//Getting the second last arrangedSubview and the current one
let lastTwoArrangedSubviews = Array(self.arrangedSubviews.suffix(2))
let arrSpacing: [CGFloat] = [top, bottom]
//Looping through the two last arrangedSubview to add spacing in each of them
for (index, anArrangedSubview) in lastTwoArrangedSubviews.enumerated() {
//After iOS 11, the stackview has a native method
if #available(iOS 11.0, *) {
self.setCustomSpacing(arrSpacing[index], after: anArrangedSubview)
//Before iOS 11 : Adding dummy separator UIViews
} else {
guard let arrangedSubviewIndex = arrangedSubviews.firstIndex(of: anArrangedSubview) else {
return
}
let separatorView = UIView(frame: .zero)
separatorView.translatesAutoresizingMaskIntoConstraints = false
//calculate spacing to keep a coherent spacing with the ios11 version
let isBetweenExisitingViews = arrangedSubviewIndex != arrangedSubviews.count - 1
let existingSpacing = isBetweenExisitingViews ? 2 * spacing : spacing
let separatorSize = arrSpacing[index] - existingSpacing
guard separatorSize > 0 else {
return
}
switch axis {
case .horizontal:
separatorView.widthAnchor.constraint(equalToConstant: separatorSize).isActive = true
case .vertical:
separatorView.heightAnchor.constraint(equalToConstant: separatorSize).isActive = true
}
insertArrangedSubview(separatorView, at: arrangedSubviewIndex + 1)
}
}
}
}
Ensuite, vous l'utiliseriez comme ceci:
//Creating label to add to the UIStackview
let label = UILabel(frame: .zero)
//Adding label to the UIStackview
stackView.addArrangedSubview(label)
//Create margin on top and bottom of the UILabel
stackView.addCustomSpacing(top: 40, bottom: 100)