Monday, March 25, 2019

Add borders to a stackview

This post is based on Xcode 9 and Swift 3. I used UIStackView to divide the page into different sections with gray borders as shown in the image below.



I created a custom UIStackView class named BorderStackView as followings:
    
import Foundation
import UIKit

class BorderStackView : UIStackView {
    
    @IBInspectable var inset:Bool = true {
        didSet {
            setNeedsLayout()
        }
    }
    
    @IBInspectable var bottomBorder: CGFloat = 1 {
        didSet {
            setNeedsLayout()
        }
    }
    
    @IBInspectable var rightBorder: CGFloat = 1 {
        didSet {
           
            setNeedsLayout()
        }
    }
    
    @IBInspectable var leftBorder: CGFloat = 1 {
        didSet {
            setNeedsLayout()
        }
    }
    
    @IBInspectable var topBorder: CGFloat = 1 {
        didSet {
            setNeedsLayout()
        }
    }
    
    @IBInspectable var borderColor: UIColor = UIColor.lightGray {
        didSet {
            setNeedsLayout()
        }
    }
    
    public override func layoutSubviews() {
        super.layoutSubviews()
        
        ViewUtil.setBorders(view: self, top: topBorder, bottom: bottomBorder, left: leftBorder, right: rightBorder, color: borderColor, inset: inset)
    }
   
}
    

To remove a border, for example the top border, set topBorder property either programmatically or in Interface Builder to zero.

When the inset property is true, the borders are drawn inside the stackview's frame. Otherwise, they are drawn outside the frame.

And here is the body of the ViewUtil class:
    
import Foundation
import UIKit

class ViewUtil {
    private static let layerNameTopBorder = "topBorder"
    private static let layerNameBottomBorder = "bottomBorder"
    private static let layerNameLeftBorder = "leftBorder"
    private static let layerNameRightBorder = "rightBorder"
    
    static func setBorders(view: UIView, top topWidth: CGFloat, bottom bottomWidth: CGFloat, left leftWidth: CGFloat, right rightWidth: CGFloat, color: UIColor,inset:Bool = true) {
        var topBorderLayer:CALayer?
        var bottomBorderLayer:CALayer?
        var leftBorderLayer:CALayer?
        var rightBorderLayer:CALayer?
        for borderLayer in (view.layer.sublayers)! {
            if borderLayer.name == layerNameTopBorder {
                topBorderLayer = borderLayer
            } else if borderLayer.name == layerNameRightBorder {
                rightBorderLayer = borderLayer
            } else if borderLayer.name == layerNameLeftBorder {
                leftBorderLayer = borderLayer
            } else if borderLayer.name == layerNameBottomBorder {
                bottomBorderLayer = borderLayer
            }
        }


        // top border
        if topBorderLayer == nil {
            topBorderLayer = CALayer()
            topBorderLayer!.name = layerNameTopBorder
            view.layer.addSublayer(topBorderLayer!)
        }
        if inset {
            topBorderLayer!.frame = CGRect(x: view.bounds.minX, y: view.bounds.minY, width: view.bounds.width, height: topWidth)
        } else {
            topBorderLayer!.frame = CGRect(x: view.bounds.minX - leftWidth, y: view.bounds.minY - topWidth, width: view.bounds.width + leftWidth + rightWidth, height: topWidth)
        }
        topBorderLayer!.backgroundColor = color.cgColor


        // bottom border
        if bottomBorderLayer == nil {
            bottomBorderLayer = CALayer()
            bottomBorderLayer!.name = layerNameBottomBorder
            view.layer.addSublayer(bottomBorderLayer!)
        }
        if bottomWidth >= 0 {
            if inset {
                bottomBorderLayer!.frame = CGRect(x: view.bounds.minX, y:view.bounds.size.height - bottomWidth, width:view.bounds.size.width, height: bottomWidth)
            } else {
                bottomBorderLayer!.frame = CGRect(x: view.bounds.minX - leftWidth, y:view.bounds.size.height, width:view.bounds.size.width + leftWidth + rightWidth, height: bottomWidth)
            }
            bottomBorderLayer!.backgroundColor = color.cgColor
        }


        // left border
        if leftBorderLayer == nil {
            leftBorderLayer = CALayer()
            leftBorderLayer!.name = layerNameLeftBorder
            view.layer.addSublayer(leftBorderLayer!)
        }
        if inset {
            leftBorderLayer!.frame = CGRect(x: view.bounds.minX, y: view.bounds.minY, width: leftWidth, height: view.bounds.height)
        } else {
            leftBorderLayer!.frame = CGRect(x: view.bounds.minX - leftWidth, y: view.bounds.minY, width: leftWidth, height: view.bounds.height)
        }
        leftBorderLayer!.backgroundColor = color.cgColor


        // right border
        if rightBorderLayer == nil {
            rightBorderLayer = CALayer()
            rightBorderLayer!.name = layerNameRightBorder
            view.layer.addSublayer(rightBorderLayer!)
        }
        if inset {
            rightBorderLayer!.frame = CGRect(x: view.bounds.width - rightWidth, y: 0, width: rightWidth, height: view.bounds.height)
        } else {
            rightBorderLayer!.frame = CGRect(x: view.bounds.width, y: 0, width: rightWidth, height: view.bounds.height)
        }
        rightBorderLayer!.backgroundColor = color.cgColor
    }
    
}
    



No comments:

Post a Comment