// // ButtonIcon.swift // VDS // // Created by Matt Bruce on 5/12/23. // import Foundation import UIKit @objc(VDSButtonIcon) open class ButtonIcon: Control { //-------------------------------------------------- // MARK: - Models //-------------------------------------------------- //-------------------------------------------------- // MARK: - Enums //-------------------------------------------------- public enum Kind: String, CaseIterable { case ghost, lowContrast, highContrast } public enum SurfaceType: String, CaseIterable { case colorFill, media } public enum Size: String, EnumSubset { case large case small public var defaultValue: Icon.Size { .large } public var containerSize: CGFloat { switch self { case .large: return 44.0 case .small: return 32.0 } } } //-------------------------------------------------- // MARK: - Private Properties //-------------------------------------------------- private var centerXConstraint: NSLayoutConstraint? private var centerYConstraint: NSLayoutConstraint? private var layoutGuideWidthConstraint: NSLayoutConstraint? private var layoutGuideHeightConstraint: NSLayoutConstraint? //-------------------------------------------------- // MARK: - Public Properties //-------------------------------------------------- open var icon = Icon() open var kind: Kind = .ghost { didSet { setNeedsUpdate() } } open var surfaceType: SurfaceType = .colorFill { didSet { setNeedsUpdate() } } open var iconName: Icon.Name? { didSet { setNeedsUpdate() } } open var size: Size = .large { didSet { setNeedsUpdate() } } open var customSize: Int? { didSet { setNeedsUpdate() }} open var floating: Bool = false { didSet { setNeedsUpdate() } } open var hideBorder: Bool = true { didSet { setNeedsUpdate() } } open var iconOffset: CGPoint = .init(x: 0, y: 0) { didSet { setNeedsUpdate() } } //-------------------------------------------------- // MARK: - Configuration //-------------------------------------------------- //-------------------------------------------------- // MARK: - Initializers //-------------------------------------------------- required public init() { super.init(frame: .zero) } public override init(frame: CGRect) { super.init(frame: .zero) } public required init?(coder: NSCoder) { super.init(coder: coder) } //-------------------------------------------------- // MARK: - Lifecycle //-------------------------------------------------- open override func setup() { super.setup() //create a layoutGuide for the icon to key off of let iconLayoutGuide = UILayoutGuide() addLayoutGuide(iconLayoutGuide) //add the icon addSubview(icon) //determines the height/width of the icon layoutGuideWidthConstraint = iconLayoutGuide.widthAnchor.constraint(equalToConstant: size.containerSize) layoutGuideHeightConstraint = iconLayoutGuide.heightAnchor.constraint(equalToConstant: size.containerSize) //determines the center point of the icon centerXConstraint = icon.centerXAnchor.constraint(equalTo: iconLayoutGuide.centerXAnchor, constant: 0) centerYConstraint = icon.centerYAnchor.constraint(equalTo: iconLayoutGuide.centerYAnchor, constant: 0) //activate the constraints NSLayoutConstraint.activate([layoutGuideWidthConstraint!, layoutGuideHeightConstraint!, centerXConstraint!, centerYConstraint!, iconLayoutGuide.topAnchor.constraint(equalTo: topAnchor), iconLayoutGuide.bottomAnchor.constraint(equalTo: bottomAnchor), iconLayoutGuide.leadingAnchor.constraint(equalTo: leadingAnchor), iconLayoutGuide.trailingAnchor.constraint(equalTo: trailingAnchor)]) } open override func reset() { super.reset() shouldUpdateView = false kind = .ghost surfaceType = .colorFill size = .large floating = false hideBorder = true iconOffset = .init(x: 0, y: 0) iconName = nil shouldUpdateView = true setNeedsUpdate() } open override func updateView() { super.updateView() //ensure there is an icon to set if let iconName { icon.name = iconName icon.size = size.value icon.surface = surface icon.disabled = disabled icon.customSize = customSize } else { icon.reset() } // colors let bgColor = UIColor.red //backgroundColorConfiguration.getColor(self) let borderColor = UIColor.green// borderColorConfiguration.getColor(self) backgroundColor = bgColor layer.borderColor = borderColor.cgColor icon.layer.borderColor = UIColor.purple.cgColor setNeedsLayout() } open override func layoutSubviews() { super.layoutSubviews() let borderWidth = 2.0 let cornerRadius = min(frame.width, frame.height) / 2.0 // calculate center point for child view with offset let childCenter = CGPoint(x: center.x + iconOffset.x, y: center.y + iconOffset.y) centerXConstraint?.constant = childCenter.x - center.x centerYConstraint?.constant = childCenter.y - center.y // calculate the icon's container size ensuring the padding var iconLayoutSize = size.containerSize if let customSize { iconLayoutSize = CGFloat(customSize) } layoutGuideWidthConstraint?.constant = iconLayoutSize layoutGuideHeightConstraint?.constant = iconLayoutSize //container layer.cornerRadius = cornerRadius layer.borderWidth = borderWidth //icon icon.layer.borderWidth = borderWidth } } // MARK: AppleGuidlinesTouchable extension ButtonIcon: AppleGuidlinesTouchable { override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { Self.acceptablyOutsideBounds(point: point, bounds: bounds) } }