I\'m trying to add vertical lines, between labels inside a stack view all programatically.
The desired finish will be something like this image:
I c
Here's a more flexible UIStackView
subclass that supports to arbitrary addition of arranged subviews and is suitable for those that need a clear background on their UIStackView
and subviews to put on top of a UIVisualEffectView
, like the picture below.
import UIKit
@IBDesignable class SeparatorStackView: UIStackView {
@IBInspectable var separatorColor: UIColor? = .black {
didSet {
invalidateSeparators()
}
}
@IBInspectable var separatorWidth: CGFloat = 0.5 {
didSet {
invalidateSeparators()
}
}
@IBInspectable private var separatorTopPadding: CGFloat = 0 {
didSet {
separatorInsets.top = separatorTopPadding
}
}
@IBInspectable private var separatorBottomPadding: CGFloat = 0 {
didSet {
separatorInsets.bottom = separatorBottomPadding
}
}
@IBInspectable private var separatorLeftPadding: CGFloat = 0 {
didSet {
separatorInsets.left = separatorLeftPadding
}
}
@IBInspectable private var separatorRightPadding: CGFloat = 0 {
didSet {
separatorInsets.right = separatorRightPadding
}
}
var separatorInsets: UIEdgeInsets = .zero {
didSet {
invalidateSeparators()
}
}
private var separators: [UIView] = []
override func layoutSubviews() {
super.layoutSubviews()
invalidateSeparators()
}
override func awakeFromNib() {
super.awakeFromNib()
invalidateSeparators()
}
override func prepareForInterfaceBuilder() {
super.prepareForInterfaceBuilder()
invalidateSeparators()
}
private func invalidateSeparators() {
guard arrangedSubviews.count > 1 else {
separators.forEach({$0.removeFromSuperview()})
separators.removeAll()
return
}
if separators.count > arrangedSubviews.count {
separators.removeLast(separators.count - arrangedSubviews.count)
} else if separators.count < arrangedSubviews.count {
separators += Array<UIView>(repeating: UIView(), count: arrangedSubviews.count - separators.count)
}
separators.forEach({$0.backgroundColor = self.separatorColor; self.addSubview($0)})
for (index, subview) in arrangedSubviews.enumerated() where arrangedSubviews.count >= index + 2 {
let nextSubview = arrangedSubviews[index + 1]
let separator = separators[index]
let origin: CGPoint
let size: CGSize
if axis == .horizontal {
let originX = (nextSubview.frame.maxX - subview.frame.minX)/2 + separatorInsets.left - separatorInsets.right
origin = CGPoint(x: originX, y: separatorInsets.top)
let height = frame.height - separatorInsets.bottom - separatorInsets.top
size = CGSize(width: separatorWidth, height: height)
} else {
let originY = (nextSubview.frame.maxY - subview.frame.minY)/2 + separatorInsets.top - separatorInsets.bottom
origin = CGPoint(x: separatorInsets.left, y: originY)
let width = frame.width - separatorInsets.left - separatorInsets.right
size = CGSize(width: width, height: separatorWidth)
}
separator.frame = CGRect(origin: origin, size: size)
}
}
}
The result?
a nice cocoa-pod that do the job pretty well. It uses Swizzeling, well coded.
https://github.com/barisatamer/StackViewSeparator
You can use interface builder to do this. Set the distribution of the parent UIStackview to Equal Centering and add two UIView with width 0 in the beginnging and ending of the parent UIStackView. Then add a UIView with width 1 in the middle and set the background color of the UIView.
You can try the following.
Thus you'll achieve the required scene. See these pictures for reference.
I've upvoted @FrankByte.com's answer because he helped me get to my solution, which is pretty similar to what the OP wanted to do:
extension UIStackView {
func addVerticalSeparators(color : UIColor, multiplier: CGFloat = 0.5) {
var i = self.arrangedSubviews.count - 1
while i > 0 {
let separator = createSeparator(color: color)
insertArrangedSubview(separator, at: i)
separator.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: multiplier).isActive = true
i -= 1
}
}
private func createSeparator(color: UIColor) -> UIView {
let separator = UIView()
separator.widthAnchor.constraint(equalToConstant: 1).isActive = true
separator.backgroundColor = color
return separator
}
}
@GOR answer extension only for vertical line and only in centers
Stackview settings: set width contraints of each subview and parent stackview should be fill
Here's a simple extension for adding vertical separators between each row.
func addVerticalSeparators(color : UIColor) {
var i = self.arrangedSubviews.count
while i > 1 {
let separator = verticalCreateSeparator(color: color)
insertArrangedSubview(separator, at: i-1) // (i-1) for centers only
separator.heightAnchor.constraint(equalTo: self.heightAnchor, multiplier: 1).isActive = true
i -= 1
}
}
private func verticalCreateSeparator(color : UIColor) -> UIView {
let separator = UIView()
separator.widthAnchor.constraint(equalToConstant: 1).isActive = true
separator.backgroundColor = color
return separator
}