Add layoutMargins to one element in a UIStackView
Asked Answered
S

5

6

I would like to create a vertical stackview with 3 elements in it. I want a bit more space only between the 2nd and the last element. So I thought about adding to the last element :

mylastelement.layoutMargins = UIEdgeInsets(top:30, left:0,bottom:0, right:0)

But the layoutmargins are not applied in my stackview. Is there any easy way to achieve that (Id like to avoid to modify the last element inner height).

EDIT : I just tried to increase 2nd element height (+50) within its frame by doing :

my2ndElementLabel.sizeToFit()
my2ndElementLabel.frame = CGRect(x:my2ndElementLabel.frame.origin.x,y:lmy2ndElementLabel.frame.origin.y,
                                 width:my2ndElementLabel.frame.width, height:my2ndElementLabel.frame.height + 50)

but it has no effect.

EDIT2 : I tried to add a random view to my UIStackView, but the the view is just ignored ! May have missed something in understanding how UIKit work ?... :

let v = UIView(frame:CGRect(x:0,y:0,width:100,height:400))
v.backgroundColor = .red
myStackView.addArrangedSubview(v)
//...
Shelter answered 31/3, 2019 at 13:17 Comment(3)
Have you tried using autolayout constraints on the top anchor?Habakkuk
What do you mean exactly ? Actually I could constraint every view top to bottom of each other, but i wanted to use a stackview to train using it.Shelter
It's strange that there is no way to add a margin to only one element of a Stackview. Looks like changing frame of the views has no effectShelter
S
7

Here is an extension I made that helps to achieve fast such margins :

extension UIStackView {

    func addArrangedSubview(_ v:UIView, withMargin m:UIEdgeInsets )
    {
        let containerForMargin = UIView()
        containerForMargin.addSubview(v)
        v.translatesAutoresizingMaskIntoConstraints = false
        NSLayoutConstraint.activate([
            v.topAnchor.constraint(equalTo: containerForMargin.topAnchor, constant:m.top ),
            v.bottomAnchor.constraint(equalTo: containerForMargin.bottomAnchor, constant: m.bottom ),
            v.leftAnchor.constraint(equalTo: containerForMargin.leftAnchor, constant: m.left),
            v.rightAnchor.constraint(equalTo: containerForMargin.rightAnchor, constant: m.right)
        ])

        addArrangedSubview(containerForMargin)
    }
}
Shelter answered 14/4, 2019 at 9:28 Comment(0)
F
4

What you could do is set a custom spacing between the second and third element.

myStackView.setCustomSpacing(30.0, after: my2ndElementLabel)
Flasher answered 20/1, 2020 at 13:31 Comment(0)
H
1

In the same general vein, you can constrain the top (or bottom) anchor of your view relative to the corresponding edge of any view in which it's embedded. What's ugly being somewhat a matter of taste, I find autolayout constraints easy to use and easy to reason about.

A simple example from Mac OS rather than iOS:

        let button = ControlFactory.labeledButton("Filter")
        addSubview(button)
        button.bottomAnchor.constraint(equalTo: bottomAnchor, constant: -20).isActive = true
        button.centerXAnchor.constraint(equalTo: centerXAnchor).isActive = true

This particular code lives in the view initializer, and positions a button in the middle of a view, 20 points up from the bottom.

Habakkuk answered 31/3, 2019 at 14:9 Comment(0)
S
0

I found myself : It looks like UIStackView doesn't work at all with old sizing system (with .frame). It seems you have to constraint height and width, and StackView will constraint left/top/right/bottom position for you when you add the arrangedSubview.

My second view was a label : I wanted a margin of 40, under the text. So i first computed the label height into its .frame property, and constraint the height at frame.height + 40(= my margin)

labelDesc.sizeToFit()
labelDesc.heightAnchor.constraint(equalToConstant:40).isActive = true

I find my own solution utterly ugly though. I'm sure UIKit provide a better way to achieve such a simple goal, without having to make these kind of DIY solutions. So please if you're used to work with UIKit, tell me if there is any better solution.

Shelter answered 31/3, 2019 at 14:2 Comment(0)
T
0

Consider adding a "margin" by inserting a correctly-sized UIView within the Stack View as needed.

If you need a 40px margin between 2 specific elements... add a UIView with a height constraint of 40px. Assign a clearColor background to make it invisible.

You can add IBOutlets to this view and hide it as you would any other item in the Stack View.

Toodleoo answered 11/9, 2020 at 10:34 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.