Skip to content

Instantly share code, notes, and snippets.

@auramagi
Created January 14, 2019 09:11
Show Gist options
  • Save auramagi/a9fed61bcabec082cc0ea808c204afa9 to your computer and use it in GitHub Desktop.
Save auramagi/a9fed61bcabec082cc0ea808c204afa9 to your computer and use it in GitHub Desktop.
Rounded opaque buttons for iOS
// Rounded opaque buttons for iOS
// Drop-in replacement for UIButton with Interface Builder support
// UIButton.buttonType type should be set to .custom
// Color is chosen based on the tint color. Supports highlighted and selected states
// Assumes that tint color has high brightness and saturation (e.g. not white or black)
// Written for iOS 12 with Swift 4.2
import UIKit
let kRoundedButtonDefaultFont = UIFont.systemFont(ofSize: 14.0, weight: .medium)
let kRoundedButtonDefaultCornerRadius: CGFloat = 4.0
let kRoundedButtonDefaultVerticalMargin: CGFloat = 6.0
let kRoundedButtonDefaultHorizontalMargin: CGFloat = 12.0
@IBDesignable class RoundedButton: UIButton {
@IBInspectable var highlightDimmingFactor: CGFloat = 0.85 {
didSet { updateColors() }
}
@IBInspectable var backgroundSaturationFactor: CGFloat = 0.1 {
didSet { updateColors() }
}
override init(frame: CGRect) {
super.init(frame: frame)
setDefaultValues()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
setDefaultValues()
}
func setDefaultValues() {
titleLabel?.font = kRoundedButtonDefaultFont
cornerRadius = kRoundedButtonDefaultCornerRadius
verticalMargin = kRoundedButtonDefaultVerticalMargin
horizontalMargin = kRoundedButtonDefaultHorizontalMargin
updateColors()
}
@IBInspectable var cornerRadius: CGFloat {
get { return layer.cornerRadius }
set {
layer.cornerRadius = newValue
layer.masksToBounds = newValue > 0
}
}
@IBInspectable var verticalMargin: CGFloat {
get { return contentEdgeInsets.top }
set {
contentEdgeInsets.top = newValue
contentEdgeInsets.bottom = newValue
}
}
@IBInspectable var horizontalMargin: CGFloat {
get { return contentEdgeInsets.left }
set {
contentEdgeInsets.left = newValue
contentEdgeInsets.right = newValue
}
}
func updateColors() {
let primaryColor = tintColor!
let desaturatedColor = tintColor.multipliedHSBColor(1.0, backgroundSaturationFactor, 1.0)
let customTextColor = isSelected ? .white : primaryColor
setTitleColor(customTextColor, for: .normal)
setTitleColor(customTextColor.multipliedHSBColor(1.0, 1.0, highlightDimmingFactor), for: .highlighted)
let currentDimmingFactor = isHighlighted ? highlightDimmingFactor : 1.0
let customBackgroundColor = isSelected ? primaryColor : desaturatedColor
backgroundColor = customBackgroundColor.multipliedHSBColor(1.0, 1.0, currentDimmingFactor)
}
override var isHighlighted: Bool {
didSet { updateColors() }
}
override var isSelected: Bool {
didSet { updateColors() }
}
override func tintColorDidChange() {
super.tintColorDidChange()
updateColors()
}
}
extension UIColor {
func multipliedHSBColor(_ hueFactor: CGFloat, _ saturationFactor: CGFloat, _ brightnessFactor: CGFloat) -> UIColor {
var h: CGFloat = 0.0
var s: CGFloat = 0.0
var b: CGFloat = 0.0
var a: CGFloat = 0.0
getHue(&h, saturation: &s, brightness: &b, alpha: &a)
h = clamp(h * hueFactor, in: 0.0...1.0)
s = clamp(s * saturationFactor, in: 0.0...1.0)
b = clamp(b * brightnessFactor, in: 0.0...1.0)
return UIColor(hue: h, saturation: s, brightness: b, alpha: a)
}
}
public func clamp<T>(_ value: T, in range: ClosedRange<T>) -> T where T : Comparable {
return min(max(value, range.lowerBound), range.upperBound)
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment