Can You Give Uistackview Borders

Bottom border is not added to view in StackView (ios)

have you checked the view frame here

layer.frame = CGRect(x: 0.0, y: view.frame.size.height - 2.0, width: view.frame.size.width, height: 2.0)

view.frame could be (0,0),then you will not see the bottom line.

always be careful when you work with view frame.

My suggestions:
1.Adding sub view instead of adding sub layer,then use snapkit to layout.
2.Build a seperate view class called bottomedView,then add sub view there with snapkit.
3.Build a seperate view class called bottomedView,and draw your bottom line in onDraw.

Always be aware view frame may not be determined when view is missing unexpectedly.

How can I set the cornerRadius of a UIStackView?

UIStackView just manages the position and size of its arranged views, the cornerRadius has no effect. Try to add a custom view below the stackView and set the cornerRadius of it.

Can we acces a UIStackView's subview's size?

OK - part of the problem is that you are modifying the titleLabel properties -- specifically, setting its .numberOfLines = 0. Auto-layout does not take that into account, without a little help.

You'll want to use a button subclass, such as this:

class MultiLineButton: UIButton {

required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
commonInit()
}

override init(frame: CGRect) {
super.init(frame: frame)
commonInit()
}

func commonInit() -> Void {
titleLabel?.numberOfLines = 0
titleLabel?.textAlignment = .center
// if you want to give your buttons some "padding" around the title
//contentEdgeInsets = UIEdgeInsets(top: 8.0, left: 8.0, bottom: 8.0, right: 8.0)
}

override var intrinsicContentSize: CGSize {
guard let tl = titleLabel else {
return .zero
}
let size = tl.intrinsicContentSize
return CGSize(width: size.width + contentEdgeInsets.left + contentEdgeInsets.right, height: size.height + contentEdgeInsets.top + contentEdgeInsets.bottom)
}

override func layoutSubviews() {
super.layoutSubviews()
guard let tl = titleLabel else { return }
tl.preferredMaxLayoutWidth = tl.frame.size.width
}

}

Using that class, here is an example view controller where we add a vertical stack view, and 2 horizontal "row" stack views:

class PruViewController: UIViewController {

func newButton(text: String) -> MultiLineButton {
let b = MultiLineButton()
b.titleLabel?.font = .systemFont(ofSize: 15.0)
b.setTitle(text, for: [])
b.setTitleColor(.blue, for: .normal)
b.setTitleColor(.lightGray, for: .highlighted)
b.setTitleColor(.black, for: .disabled)
b.layer.borderWidth = 1
b.layer.borderColor = UIColor.black.cgColor
return b
}

override func viewDidLoad() {
super.viewDidLoad()

let button = newButton(text: "name")
let button2 = newButton(text: "John Smith")
let button3 = newButton(text: "Description")
let button4 = newButton(text: "text text text text text text text text text text text \n text text text text text \n text text text text text")

let vStack = UIStackView()
vStack.axis = .vertical
vStack.distribution = .fill

let hStack = UIStackView()
hStack.axis = .horizontal
hStack.distribution = .fillEqually

let hStack2 = UIStackView()
hStack2.axis = .horizontal
hStack2.distribution = .fillEqually

hStack.addArrangedSubview(button)
hStack.addArrangedSubview(button2)

hStack2.addArrangedSubview(button3)
hStack2.addArrangedSubview(button4)

vStack.addArrangedSubview(hStack)
vStack.addArrangedSubview(hStack2)

vStack.translatesAutoresizingMaskIntoConstraints = false

view.addSubview(vStack)

// respect safe area
let g = view.safeAreaLayoutGuide

NSLayoutConstraint.activate([
vStack.topAnchor.constraint(equalTo: g.topAnchor, constant: 20.0),
vStack.leadingAnchor.constraint(equalTo: g.leadingAnchor, constant: 20.0),
vStack.trailingAnchor.constraint(equalTo: g.trailingAnchor, constant: -20.0),
])

}
}

The result:

Sample Image

And, you'll notice in my MultiLineButton class a comment about adding "padding" around the button title labels... here's how it looks with that line un-commented:

Sample Image

How to change the background color of UIStackView?


You can't do this – UIStackView is a non-drawing view, meaning that
drawRect() is never called and its background color is ignored. If you
desperately want a background color, consider placing the stack view
inside another UIView and giving that view a background color.

Reference from HERE.

EDIT:

You can add a subView to UIStackView as mentioned HERE or in this answer (below) and assign a color to it. Check out below extension for that:

extension UIStackView {
func addBackground(color: UIColor) {
let subView = UIView(frame: bounds)
subView.backgroundColor = color
subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
insertSubview(subView, at: 0)
}
}

And you can use it like:

stackView.addBackground(color: .red)

UIStackView rounded corners for deployment target 12.3

You could place your stackView inside another view and set background color/corner radius for this container view:

override func viewDidLoad() {
super.viewDidLoad()

view.backgroundColor = .black

// The following is "supposed" to create rounded corners for the stackview
let subView = UIView()
subView.backgroundColor = .yellow // this ends up showing through instead of the systemPink
subView.autoresizingMask = [.flexibleWidth, .flexibleHeight]
subView.layer.cornerRadius = 10
subView.layer.masksToBounds = true
subView.clipsToBounds = true
view.addSubview(subView)
subView.translatesAutoresizingMaskIntoConstraints = false

let stackView = UIStackView()
stackView.axis = .vertical
stackView.distribution = .fillEqually
stackView.alignment = .fill
stackView.spacing = 6
stackView.backgroundColor = .systemPink // this actually works

subView.addSubview(stackView)
stackView.translatesAutoresizingMaskIntoConstraints = false

// Fill the stackview with buttons
for index in 0..<buttonList.count {
let button = UIButton()
button.setTitle(buttonList[index], for: .normal)
button.backgroundColor = .cyan
button.setTitleColor(.black, for: .normal)
button.titleLabel?.font = UIFont.systemFont(ofSize: 14)
stackView.addArrangedSubview(button)
}

NSLayoutConstraint.activate([
stackView.trailingAnchor.constraint(equalTo: subView.trailingAnchor),
stackView.leadingAnchor.constraint(equalTo: subView.leadingAnchor),
stackView.topAnchor.constraint(equalTo: subView.topAnchor),
stackView.bottomAnchor.constraint(equalTo: subView.bottomAnchor),

subView.centerXAnchor.constraint(equalTo: view.centerXAnchor),
subView.centerYAnchor.constraint(equalTo: view.centerYAnchor),
subView.widthAnchor.constraint(equalToConstant: 140)
])
}

As far as I know, it is also better to activate NSLayoutConstraint in a group, not one by one

Sample Image

How to add corner radius to UIStackView and mask subviews

Instead of adding background to stack view, you can add stack view as a child to the background and mask background with corners.

let wrapper = UIView()               // Creating background
wrapper.layer.cornerRadius = 10
wrapper.layer.masksToBounds = true
wrapper.backgroundColor = .yellow

let stack = UIStackView() // Creating stack
stack.frame = wrapper.bounds
stack.autoresizingMask = [.flexibleWidth, .flexibleHeight]
wrapper.addSubview(stack)

How to add a border just on the top side of a UIView

I consider subclassing UIView and overriding drawRect overkill here. Why not add an extension on UIView and add border subviews?

@discardableResult
func addBorders(edges: UIRectEdge,
color: UIColor,
inset: CGFloat = 0.0,
thickness: CGFloat = 1.0) -> [UIView] {

var borders = [UIView]()

@discardableResult
func addBorder(formats: String...) -> UIView {
let border = UIView(frame: .zero)
border.backgroundColor = color
border.translatesAutoresizingMaskIntoConstraints = false
addSubview(border)
addConstraints(formats.flatMap {
NSLayoutConstraint.constraints(withVisualFormat: $0,
options: [],
metrics: ["inset": inset, "thickness": thickness],
views: ["border": border]) })
borders.append(border)
return border
}


if edges.contains(.top) || edges.contains(.all) {
addBorder(formats: "V:|-0-[border(==thickness)]", "H:|-inset-[border]-inset-|")
}

if edges.contains(.bottom) || edges.contains(.all) {
addBorder(formats: "V:[border(==thickness)]-0-|", "H:|-inset-[border]-inset-|")
}

if edges.contains(.left) || edges.contains(.all) {
addBorder(formats: "V:|-inset-[border]-inset-|", "H:|-0-[border(==thickness)]")
}

if edges.contains(.right) || edges.contains(.all) {
addBorder(formats: "V:|-inset-[border]-inset-|", "H:[border(==thickness)]-0-|")
}

return borders
}

// Usage:
view.addBorder(edges: [.all]) // All with default arguments
view.addBorder(edges: [.top], color: .green) // Just Top, green, default thickness
view.addBorder(edges: [.left, .right, .bottom], color: .red, thickness: 3) // All except Top, red, thickness 3

With this code you're not tied to your subclass too, you can apply it to anything and everything that inherits from UIView - reusable in your project, and any others. Pass in other arguments to your methods to define other colours and widths. Many options.

iOS layer masking doesn't work on UIStackView

Apparently, you can't mask UIStackViews! When I wrapped the stack view in a regular UIView, and applied the mask on it - the masking started to work.



Related Topics



Leave a reply



Submit