Skip to content

Instantly share code, notes, and snippets.

@kristopherjohnson
Last active January 4, 2021 14:35
Show Gist options
  • Save kristopherjohnson/99783393889e6b3b9830 to your computer and use it in GitHub Desktop.
Save kristopherjohnson/99783393889e6b3b9830 to your computer and use it in GitHub Desktop.
Swift: Custom UIButton subclass that displays a rounded rectangle in the background
import UIKit
/// UIButton subclass that draws a rounded rectangle in its background.
public class RoundRectButton: UIButton {
// MARK: Public interface
/// Corner radius of the background rectangle
public var roundRectCornerRadius: CGFloat = 8 {
didSet {
self.setNeedsLayout()
}
}
/// Color of the background rectangle
public var roundRectColor: UIColor = UIColor.whiteColor() {
didSet {
self.setNeedsLayout()
}
}
// MARK: Overrides
override public func layoutSubviews() {
super.layoutSubviews()
layoutRoundRectLayer()
}
// MARK: Private
private var roundRectLayer: CAShapeLayer?
private func layoutRoundRectLayer() {
if let existingLayer = roundRectLayer {
existingLayer.removeFromSuperlayer()
}
let shapeLayer = CAShapeLayer()
shapeLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: roundRectCornerRadius).CGPath
shapeLayer.fillColor = roundRectColor.CGColor
self.layer.insertSublayer(shapeLayer, atIndex: 0)
self.roundRectLayer = shapeLayer
}
}
@carstenhag
Copy link

carstenhag commented Jul 24, 2018

I improved the code a bit, and set it up for my use case.

// TODO: Improve background color handling, make it show up right in the IB
// https://gist.github.com/kristopherjohnson/99783393889e6b3b9830
public class RectBorderButton: UIButton {

    public override func awakeFromNib() {

        let paddingLeftRight: CGFloat = 24.0
        let paddingTopBottom: CGFloat = 16.0

        let size = self.titleLabel!.text!.size(
            withAttributes: [NSAttributedStringKey.font: UIFont.systemFont(ofSize: self.titleLabel!.font.pointSize)]
        )

        self.frame.size = CGSize(width: size.width + paddingLeftRight * 2,
                                 height: size.height + paddingTopBottom * 2)


        self.contentEdgeInsets = UIEdgeInsets(top: paddingTopBottom,
                                              left: paddingLeftRight,
                                              bottom: paddingTopBottom,
                                              right: paddingLeftRight)
    }

    // MARK: Public interface

    @IBInspectable public var cornerRadius: CGFloat = 8 {
        didSet {
            self.setNeedsLayout()
        }
    }

    @IBInspectable public var bgColor: UIColor = UIColor.white {
        didSet {
            self.setNeedsLayout()
        }
    }

    @IBInspectable public var borderColor: UIColor = UIColor.appleDefaultTint {
        didSet {
            self.setNeedsLayout()
        }
    }

    // MARK: Overrides

    override public func layoutSubviews() {
        super.layoutSubviews()
        layoutRoundRectLayer()
    }

    override public var isEnabled: Bool {
        didSet {
            layoutSubviews()
        }
    }

    // MARK: Private

    private var roundRectLayer: CAShapeLayer?

    private func layoutRoundRectLayer() {
        if let existingLayer = roundRectLayer {
            existingLayer.removeFromSuperlayer()
        }
        let shapeLayer = CAShapeLayer()
        shapeLayer.path = UIBezierPath(roundedRect: self.bounds, cornerRadius: cornerRadius).cgPath
        shapeLayer.fillColor = bgColor.cgColor

        if self.isEnabled {
            shapeLayer.strokeColor = borderColor.cgColor
        } else {
            shapeLayer.strokeColor = UIColor.gray.cgColor
        }


        self.layer.insertSublayer(shapeLayer, at: 0)
        self.roundRectLayer = shapeLayer
    }
}

You add this as a file to your project, and then in a Storyboard, while having selected an UIButton, you assign this class to it.
It then lets you change the Colors via the IB.

Paddings etc are messed up in the Storyboard if you use this, because it gets changed programatically. Works great though for me.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment