Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I create UIStackView with variable spacing between views?

I have a simple horizontal UIStackView with several UIViews stacked inside. My goal is to create variable spacing between views. I am well aware that I can create constant space between the subviews using "spacing" property. However my goal is to create variable space. Please note, if at all possible, I would like to avoid using invisible views that act as spacers.

The best I came up with was to wrap my UIViews in a separate UIStackView, and use layoutMarginsRelativeArrangement = YES to respect layout margins of my inner stack. I was hoping I could do something similar with any UIView without resorting to this ugly work-around. Here is my sample 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]; 

The result is a stack with views right next to each other with spacing:

enter image description here

like image 245
yura Avatar asked Oct 07 '15 17:10

yura


People also ask

How do you add a space in a stack?

1) Adjust the external space at the top and bottom outside the stack you are currently editing. Pull the slider right and space above and below your stack will increase, and vice versa if the bar is moved to the left. 2) Adjust the internal space, the top and bottom areas inside the stack you are currently editing.

What is Stackview alignment?

A layout where the stack view aligns the center of its arranged views with its center along its axis. case leading. A layout for vertical stacks where the stack view aligns the leading edge of its arranged views along its leading edge.

What is Uistackview?

A streamlined interface for laying out a collection of views in either a column or a row.


2 Answers

Update For iOS 11, StackViews with Custom Spacing

Apple has added the ability to set custom spacing in iOS 11. You simply have to specify the spacing after each arranged subview. Unfortunately you can't specify spacing before.

stackView.setCustomSpacing(10.0, after: firstLabel) stackView.setCustomSpacing(10.0, after: secondLabel) 

Still way better than using your own views.

For iOS 10 and Below

You could simply add a transparent views into your stack view and add width constraints to them.

(Label - UIView - Label - UIView -Label)

and if you keep distribution to fill, then you can setup variable width constraints on your UIViews.

But I would consider if this is the right situation to use stackviews if that's the case. Autolayout makes it very easy to setup variable widths between views.

like image 91
Rob Norback Avatar answered Oct 25 '22 18:10

Rob Norback


SWIFT 4

Following lilpit answer, here is an extension of the UIStackView to add a top and a bottom spacing to your arrangedSubview

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)             }         }     } } 

Then you would use it like this:

//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) 
like image 30
Ugo Marinelli Avatar answered Oct 25 '22 19:10

Ugo Marinelli