From 1c09e11c4e88a76816e12756380a79d9a7182949 Mon Sep 17 00:00:00 2001 From: Nam Kennic Date: Wed, 27 Oct 2021 23:09:22 +0700 Subject: [PATCH] NKButtonStack supports border and shadow --- Example/NKButton/ViewController.swift | 8 +- NKButton.podspec | 2 +- NKButton/Classes/NKButtonStack.swift | 128 +++++++++++++++++++++++++- 3 files changed, 134 insertions(+), 4 deletions(-) diff --git a/Example/NKButton/ViewController.swift b/Example/NKButton/ViewController.swift index c38ef43..d826193 100644 --- a/Example/NKButton/ViewController.swift +++ b/Example/NKButton/ViewController.swift @@ -139,9 +139,15 @@ class ViewController: UIViewController { // Example of NKButtonStack usage: let buttonStack = NKButtonStack() + buttonStack.backgroundColor = .systemRed + buttonStack.borderSize = 2 + buttonStack.borderColor = .systemRed + buttonStack.shadowColor = .gray + buttonStack.shadowRadius = 4 + buttonStack.shadowOpacity = 1.0 buttonStack.configurationBlock = { (button, item, index) in - button.backgroundColors[.normal] = .brown + button.backgroundColors[.normal] = .lightGray button.backgroundColors[.highlighted] = .gray button.backgroundColors[.selected] = .red button.backgroundColors[[.selected, .highlighted]] = .green diff --git a/NKButton.podspec b/NKButton.podspec index 133c613..54e7ee1 100644 --- a/NKButton.podspec +++ b/NKButton.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'NKButton' - s.version = '4.5' + s.version = '4.6' s.summary = 'A fully customizable UIButton' s.description = <<-DESC A fully customizable button that fills all lacked functions from UIButton like: diff --git a/NKButton/Classes/NKButtonStack.swift b/NKButton/Classes/NKButtonStack.swift index eb98a87..5357971 100644 --- a/NKButton/Classes/NKButtonStack.swift +++ b/NKButton/Classes/NKButtonStack.swift @@ -71,8 +71,75 @@ open class NKButtonStack: UIControl { open var cornerRadius: CGFloat = 0 { didSet { - layer.cornerRadius = cornerRadius - if (cornerRadius > 0) { layer.masksToBounds = true } + guard cornerRadius != oldValue else { return } + setNeedsDisplay() + } + } + + /** Shadow color */ + open var shadowColor: UIColor? = nil { + didSet { + guard shadowColor != oldValue else { return } + setNeedsDisplay() + } + } + + /** Shadow radius */ + open var shadowRadius: CGFloat = 0 { + didSet { + guard shadowRadius != oldValue else { return } + setNeedsDisplay() + } + } + + /** Shadow opacity */ + open var shadowOpacity: Float = 0.5 { + didSet { + guard shadowOpacity != oldValue else { return } + setNeedsDisplay() + } + } + + /** Shadow offset */ + open var shadowOffset: CGSize = .zero { + didSet { + guard shadowOffset != oldValue else { return } + setNeedsDisplay() + } + } + + /** Border color */ + open var borderColor: UIColor? = nil { + didSet { + guard borderColor != oldValue else { return } + setNeedsDisplay() + } + } + + /** Size of border */ + open var borderSize: CGFloat = 0 { + didSet { + guard borderSize != oldValue else { return } + setNeedsDisplay() + } + } + + /** Border dash pattern */ + open var borderDashPattern: [NSNumber]? = nil { + didSet { + guard borderDashPattern != oldValue else { return } + setNeedsDisplay() + } + } + + /** Border color */ + private var _backgroundColor: UIColor? = nil + open override var backgroundColor: UIColor?{ + get { _backgroundColor } + set { + _backgroundColor = newValue + setNeedsDisplay() + super.backgroundColor = .clear } } @@ -136,6 +203,9 @@ open class NKButtonStack: UIControl { public let scrollView = UIScrollView() public let frameLayout = StackFrameLayout(axis: .horizontal, distribution: .equal) + fileprivate let shadowLayer = CAShapeLayer() + fileprivate let backgroundLayer = CAShapeLayer() + // MARK: - convenience public init(items: [NKButtonItem], axis: NKLayoutAxis = .horizontal) { @@ -150,6 +220,9 @@ open class NKButtonStack: UIControl { public init() { super.init(frame: .zero) + layer.addSublayer(shadowLayer) + layer.addSublayer(backgroundLayer) + frameLayout.spacing = 1.0 frameLayout.isIntrinsicSizeEnabled = true frameLayout.shouldCacheSize = false @@ -174,9 +247,44 @@ open class NKButtonStack: UIControl { return frameLayout.sizeThatFits(size) } + override open func draw(_ rect: CGRect) { + super.draw(rect) + + let backgroundFrame = bounds + let fillColor = backgroundColor + let strokeColor = borderColor + let strokeSize = borderSize + let roundedPath = UIBezierPath(roundedRect: backgroundFrame, cornerRadius: cornerRadius) + let path = roundedPath.cgPath + + backgroundLayer.path = path + backgroundLayer.fillColor = fillColor?.cgColor + backgroundLayer.strokeColor = strokeColor?.cgColor + backgroundLayer.lineWidth = strokeSize + backgroundLayer.miterLimit = roundedPath.miterLimit + backgroundLayer.lineDashPattern = borderDashPattern + + if let shadowColor = shadowColor { + shadowLayer.isHidden = false + shadowLayer.path = path + shadowLayer.shadowPath = path + shadowLayer.fillColor = shadowColor.cgColor + shadowLayer.shadowColor = shadowColor.cgColor + shadowLayer.shadowRadius = shadowRadius + shadowLayer.shadowOpacity = shadowOpacity + shadowLayer.shadowOffset = shadowOffset + } + else { + shadowLayer.isHidden = true + } + } + override open func layoutSubviews() { super.layoutSubviews() + shadowLayer.frame = bounds + backgroundLayer.frame = bounds + let viewSize = bounds.size let contentSize = frameLayout.sizeThatFits(CGSize(width: CGFloat.infinity, height: CGFloat.infinity)) scrollView.contentSize = contentSize @@ -201,6 +309,15 @@ open class NKButtonStack: UIControl { cornerRadius = viewSize.height / 2 setNeedsDisplay() } + + if cornerRadius > 0 { + scrollView.layer.cornerRadius = cornerRadius + scrollView.layer.masksToBounds = true + } + else { + scrollView.layer.cornerRadius = 0 + scrollView.layer.masksToBounds = false + } } // MARK: - @@ -209,6 +326,13 @@ open class NKButtonStack: UIControl { return frameLayout.frameLayout(at: index)?.targetView as? T } + open func setShadow(color: UIColor?, radius: CGFloat, opacity: Float = 1.0, offset: CGSize = .zero) { + self.shadowColor = color + self.shadowOpacity = opacity + self.shadowRadius = radius + self.shadowOffset = offset + } + // MARK: - fileprivate func updateLayout() {