What I want: A SwiftUI style .padding
method in UIKit.
What I tried:
class Padding<T: UIView>: UIView {
var base: T { viewToPad }
let defaultPadding: UIEdgeInsets = .init(top: 8, left: 12, bottom: 8, right: 12)
private var viewToPad: T
init(view: T, padding: UIEdgeInsets? = nil) {
self.viewToPad = view
self.viewToPad.translatesAutoresizingMaskIntoConstraints = false
super.init(frame: .zero)
addSubview(viewToPad)
self.viewToPad.attachToContainer(side: .top, constant: padding?.top ?? defaultPadding.top)
self.viewToPad.attachToContainer(side: .bottom, constant: padding?.bottom ?? defaultPadding.bottom)
self.viewToPad.attachToContainer(side: .left, constant: padding?.left ?? defaultPadding.left)
self.viewToPad.attachToContainer(side: .right, constant: padding?.right ?? defaultPadding.right)
}
required init?(coder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
}
extension UIView {
func padded<T: UIView>(with padding: UIEdgeInsets? = nil) -> Padding<T> {
return Padding(view: self as! T, padding: padding)
}
}
My issue: I can't make base
be the actual T
type:
let label = UILabel(text: "Instructions").padding()
label.base.textColor = UIColor.black // Value of type 'UIView' has no member 'textColor'
label.base
is of type UIView
here. Is there a way to make base
be of type UILabel
?
Thanks
Instead of being generic, padded
should return Padding<Self>
, but it cannot do that directly in a an extension of UIView
. You can work around this by introducing a protocol, and extending that protocol.
protocol Paddable: UIView {}
extension UIView: Paddable {}
extension Paddable {
func padded(with padding: UIEdgeInsets? = nil) -> Padding<Self> {
return Padding(view: self, padding: padding)
}
}
Now this is possible:
let label = UILabel().padded()
label.base.textColor = UIColor.black