Setting masked corners in Interface Builder
I've just randomly bumped into this same "issue" and wrote another solution, using an extension (no subclassing) and visual toggles in IB for each corner (without setting / adding the bit flags manually).
Keep in mind that the default settings are On / true
(so that "cornerRadius" affects all corners of the view). If you want to round all corners except one, just set that particular corner to false
.
import UIKit
@IBDesignable
public extension UIView {
@IBInspectable var cornerRadius: CGFloat {
get { return layer.cornerRadius }
set { layer.cornerRadius = newValue }
}
@IBInspectable var topLeft: Bool {
get { return layer.maskedCorners.contains(.layerMinXMinYCorner) }
set {
if newValue {
layer.maskedCorners.insert(.layerMinXMinYCorner)
} else {
layer.maskedCorners.remove(.layerMinXMinYCorner)
}
}
}
@IBInspectable var topRight: Bool {
get { return layer.maskedCorners.contains(.layerMaxXMinYCorner) }
set {
if newValue {
layer.maskedCorners.insert(.layerMaxXMinYCorner)
} else {
layer.maskedCorners.remove(.layerMaxXMinYCorner)
}
}
}
@IBInspectable var bottomLeft: Bool {
get { return layer.maskedCorners.contains(.layerMinXMaxYCorner) }
set {
if newValue {
layer.maskedCorners.insert(.layerMinXMaxYCorner)
} else {
layer.maskedCorners.remove(.layerMinXMaxYCorner)
}
}
}
@IBInspectable var bottomRight: Bool {
get { return layer.maskedCorners.contains(.layerMaxXMaxYCorner) }
set {
if newValue {
layer.maskedCorners.insert(.layerMaxXMaxYCorner)
} else {
layer.maskedCorners.remove(.layerMaxXMaxYCorner)
}
}
}
}
In interface builder I set these by selecting the object you want to transform at run time and in user defined runtime attribute the KeyPath is layer.cornerRadius
or layer.maskedCorners
and the Type is Number
and add the raw value of the corner you want to change.
maskedCorners
is a CACornerMask, which is an OptionSet, or bit mask. The raw value is an integer: in code, you can try printing the value of someView.layer.maskedCorners.rawValue
, or setting it via someView.layer.maskedCorners.setValue(3, forKey: "maskedCorners")
.
So you should be able to set the value of layer.maskedCorners
to the integer 3 (or whatever you need) in Interface Builder, and I don't see why it would be unsafe to do this. Though it will be a pain to figure out what set of corners that integer value actually maps to if you forget.
Did not check if it works, but you may try c:
(Don't forget to apply the mask to your view ð)
@IBDesignable
class ViewController: UIViewController {
// Preprocessor macro, you won't be able
// to use code inside this "if" statement from your... code
// Just use cornerMask property directly
#if TARGET_INTERFACE_BUILDER
@IBInspectable
var topLeft: Bool = false {
didSet {
updateCornerMask()
}
}
@IBInspectable
var topRight: Bool = false {
didSet {
updateCornerMask()
}
}
@IBInspectable
var bottomLeft: Bool = false {
didSet {
updateCornerMask()
}
}
@IBInspectable
var bottomRight: Bool = false {
didSet {
updateCornerMask()
}
}
func updateCornerMask() {
cornerMask = CACornerMask(
TL: topLeft,
TR: topRight,
BL: bottomLeft,
BR: bottomRight)
}
#endif
var cornerMask: CACornerMask?
}
extension CACornerMask {
init(TL: Bool = false, TR: Bool = false, BL: Bool = false, BR: Bool = false) {
var value: UInt = 0
if TL { value += 1 }
if TR { value += 2 }
if BL { value += 4 }
if BR { value += 8 }
self.init(rawValue: value)
}
}
// And yeah maybe using UIView makes more sense ð