Reputation: 20078
This is my setup: I have an UIScrollView
with leading,top, trialing edge set to 0. Inside this I add an UIStackView
with this constraints:
stackView.centerYAnchor.constraintEqualToAnchor(selectedContactsScrollView.centerYAnchor).active = true
stackView.leadingAnchor.constraintEqualToAnchor(selectedContactsScrollView.leadingAnchor).active = true
Inside the stack view I add some views.
My issue is that because of the constraints the first view added to stack view will also have leading edge = 0.
What are the ways that I could add some padding to the first view ? Without adjusting the scroll view constraints.
Upvotes: 211
Views: 163586
Reputation: 12292
You can now trivially add any padding you want to a stack view.
isLayoutMarginsRelativeArrangement = true
directionalLayoutMargins = NSDirectionalEdgeInsets(
top: 8, leading: 8, bottom: 8, trailing: 8)
[OP] has one vertical stack and 7 subviews in it. He needs horizontal padding for the first subview.
You just put the 1st subview inside a horizontal stack view.
And then set the padding of that "row" any way you like, as usual, with directionalLayoutMargins
.
Almost always when you have a vert stack view, each "row" is itself a stack view.
(So that you can manipulate its alignment, padding etc.)
Totally random example, a common layout is top right screen buttons, then some sort of bar, then the "items", then some sort of options split at the bottom.
This is completely trivial using stackviews. (Each row is a stackview, and of course, the whole thing is a stack view.) It literally couldn't be simpler - you just tap left, right, fill, whatever as you want each row. It would be an absolute nightmare to do this with constraints on storyboard, and, an insane nuisance, days of work, to do it with constraints when assembling it dynamically! However it is totally trivial with stackviews inside stackviews - which is indeed the whole reason stackviews exist in UIKit!!
Upvotes: 2
Reputation: 3245
A xib / storyboard trick is to add uiviews at start & end of the uistackview and add width constraints on it. Make it clear to be sure it's not showing up.
Upvotes: 0
Reputation: 235
Set your stackview alignment to "center". After that you can give every subview different leading and trailing.
Upvotes: 10
Reputation: 31
The solution would be to have a regular view in the stack view to hold whatever views you are wanting to add constraints to, and then you can add constraints for your items that are relative to the views in the stack view. That way, your original views can have leading and trailing constraints within the stack view.
This can be done in the interface builder and programatically.
Upvotes: 3
Reputation: 4958
I have found that constraints don't work inside a Stack View, or they seem somewhat strange.
(Such as if I add leading/trailing constraint to selected on image stackview, that adds leading to collectionview too, but doesn't add trailing; and it be conflict for sure).
To set layout margins for all views inside the stackview, select:
Stack View > Size Inspector > Layout Margins > Fixed
Note: "Fixed"
option was formerly called "Explicit"
, as seen in the screenshots.
Then add your padding:
Upvotes: 224
Reputation: 2179
This question already has good answers,
One suggestion though, use spacing
property to set the spacing between the views. For first and last views there can be two options, either set insets as @tolpp suggested or add constraint attaching to parent (stackview) with constant to add padding.
Upvotes: 1
Reputation: 34523
What we did was add transparent components (e.g., UIButton/UIView) as the first and last children of the UIStackView. Then set constrain the width of these invisible children to adjust the padding.
Upvotes: 0
Reputation: 16189
swift 3: You just need set offset by:
firstView.leadingAnchor.constraint(equalTo: parentView.leadingAnchor, constant: 200).isActive = true
Be sure this constraint set after you parentView.addArrangdSubView(firstView)
Upvotes: 7
Reputation: 7123
When isLayoutMarginsRelativeArrangement
property is true, the stack view will layout its arranged views relative to its layout margins.
stackView.layoutMargins = UIEdgeInsets(top: 0, left: 20, bottom: 0, right: 20)
stackView.isLayoutMarginsRelativeArrangement = true
But it affects all arranged views inside to the stack view. If you want this padding for only one arranged view, you need to use nested UIStackView
Upvotes: 597
Reputation: 91
If you only need leading padding, then you can set the stack view's Alignment to "Trailing" and then you will be free to specify unique Leading constraints on each of its contained subviews.
As a bonus, you can also set the stack view's alignment to "Center" and then you can use Leading and/or Trailing constraints to give each item its own padding on both sides.
Upvotes: 9
Reputation: 945
What worked for me is to add to stack view another UIView that's just a spacer (works at least with stackView.distribution = .Fill):
let spacerView = UIView(frame: CGRect(x: 0, y: 0, width: 10, height: 10))
stackView.addArrangedSubview(spacerView)
stackView.addArrangedSubview(viewThatNeedsSpaceBeforeIt)
stackView.addArrangedSubview(NextView)...
Upvotes: 26
Reputation: 28819
The solution you have provided doesn't add a padding for your views inside your UIStackView (as you wanted in the question), but it adds a leading for the UIStackView.
A solution could be to add another UIStackView inside your original UIStackView and give the leading to this new UIStackVIew. Then, add your views to this new UIStackView.
Hint, you can do that completely using Interface Builder. In other words, no need to write code for it.
Upvotes: 36
Reputation: 20078
It seems that the solution was pretty simple. Instead of:
stackView.leadingAnchor.constraintEqualToAnchor(selectedContactsScrollView.leadingAnchor).active = true
I just wrote:
stackView.leadingAnchor.constraintEqualToAnchor(selectedContactsScrollView.leadingAnchor, constant: 15).active = true
Upvotes: -3