iOS - Add vertical line programatically inside a stack view

后端 未结 10 863
悲哀的现实
悲哀的现实 2020-12-25 09:04

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

相关标签:
10条回答
  • 2020-12-25 09:21

    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?

    0 讨论(0)
  • 2020-12-25 09:21

    a nice cocoa-pod that do the job pretty well. It uses Swizzeling, well coded.

    https://github.com/barisatamer/StackViewSeparator

    0 讨论(0)
  • 2020-12-25 09:25

    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.

    0 讨论(0)
  • 2020-12-25 09:31

    You can try the following.

    1. First of all take a UIView and apply the same constraints of UIStackView to this UIView.
    2. Make the Background color of this UIView to Black (The color of the lines)
    3. Now take a UIStackView and add it as a child of above UIView.
    4. Add constraints of the UIStackView i.e. bind it to all the edges of parent UIView.
    5. Now make the bakckground color of UIStackView to Clear Color.
    6. Set the spacing of UIStackView to 1 or 2 (the width of lines)
    7. Now add the 3 labels into stackview.
    8. Make sure the labels have background color to White Color and Text Color to Black Color.

    Thus you'll achieve the required scene. See these pictures for reference.

    0 讨论(0)
  • 2020-12-25 09:32

    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
        }
    }
    
    0 讨论(0)
  • 2020-12-25 09:35

    @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
    } 
    
    0 讨论(0)
提交回复
热议问题