// // 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 iconCenterXConstraint: NSLayoutConstraint? private var iconCenterYConstraint: NSLayoutConstraint? private var containerViewWidthConstraint: NSLayoutConstraint? private var containerViewHeightConstraint: NSLayoutConstraint? private var containerView = UIView().with { $0.translatesAutoresizingMaskIntoConstraints = false $0.backgroundColor = .clear } //-------------------------------------------------- // 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() addSubview(containerView) containerView.addSubview(icon) containerView.pinToSuperView() containerViewWidthConstraint = containerView.widthAnchor.constraint(equalToConstant: size.containerSize) containerViewHeightConstraint = containerView.heightAnchor.constraint(equalToConstant: size.containerSize) iconCenterXConstraint = icon.centerXAnchor.constraint(equalTo: centerXAnchor, constant: 0) iconCenterYConstraint = icon.centerYAnchor.constraint(equalTo: centerYAnchor, constant: 0) NSLayoutConstraint.activate([containerViewWidthConstraint!, containerViewHeightConstraint!, iconCenterXConstraint!, iconCenterYConstraint!]) } 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() if let iconName { icon.name = iconName icon.size = size.value icon.surface = surface icon.disabled = disabled icon.customSize = customSize } else { icon.reset() } setNeedsLayout() } open override func layoutSubviews() { super.layoutSubviews() let bgColor = UIColor.red //backgroundColorConfiguration.getColor(self) let borderColor = UIColor.green// borderColorConfiguration.getColor(self) 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) iconCenterXConstraint?.constant = childCenter.x - containerView.center.x iconCenterYConstraint?.constant = childCenter.y - containerView.center.y // calculate the icon's container size ensuring the padding if let customSize { containerViewWidthConstraint?.constant = CGFloat(customSize) containerViewHeightConstraint?.constant = CGFloat(customSize) } else { containerViewWidthConstraint?.constant = size.containerSize containerViewHeightConstraint?.constant = size.containerSize } //container backgroundColor = bgColor layer.borderColor = borderColor.cgColor layer.cornerRadius = cornerRadius layer.borderWidth = borderWidth //icon icon.layer.borderColor = UIColor.purple.cgColor icon.layer.borderWidth = 2 } } // MARK: AppleGuidlinesTouchable extension ButtonIcon: AppleGuidlinesTouchable { override open func point(inside point: CGPoint, with event: UIEvent?) -> Bool { Self.acceptablyOutsideBounds(point: point, bounds: bounds) } }