Last active
June 13, 2019 23:15
-
-
Save p-larson/c1910523ad85cf34d3e08150b65c7074 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import UIKit | |
// Bug Recreation Playground | |
// Peter Larson | |
// Util | |
extension UIColor { | |
func lighter(by percentage: CGFloat = 25.0) -> UIColor { | |
return self.adjust(by: abs(percentage) ) ?? self | |
} | |
func darker(by percentage: CGFloat = 25.0) -> UIColor { | |
return self.adjust(by: -abs(percentage)) ?? self | |
} | |
func adjust(by percentage: CGFloat = 30.0) -> UIColor? { | |
var red: CGFloat = 0, green: CGFloat = 0, blue: CGFloat = 0, alpha: CGFloat = 0 | |
if self.getRed(&red, green: &green, blue: &blue, alpha: &alpha) { | |
return UIColor( | |
red: min(red + percentage/100, 1.0), | |
green: min(green + percentage/100, 1.0), | |
blue: min(blue + percentage/100, 1.0), | |
alpha: alpha) | |
} else { | |
return nil | |
} | |
} | |
} | |
final public class OverlayLayer: CALayer { | |
var color: UIColor = #colorLiteral(red: 0.9607843161, green: 0.7058823705, blue: 0.200000003, alpha: 1) { | |
didSet { | |
print("set color to", self.color) | |
self.display() | |
} | |
} | |
public var defaultShadowHeight: CGFloat = 12.0 | |
@objc public var shadowHeight: CGFloat = 12.0 | |
init(frame: CGRect, color: UIColor) { | |
super.init() | |
self.frame = frame | |
self.color = color | |
self.common() | |
} | |
public override init(layer: Any) { | |
super.init(layer: layer) | |
self.common() | |
} | |
public required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
self.common() | |
} | |
public override init() { | |
super.init() | |
self.common() | |
} | |
private func common() { | |
self.drawsAsynchronously = true | |
self.display() | |
} | |
public func animate(pressed: Bool, duration: TimeInterval = 0.5) { | |
self.display() | |
let animation = CABasicAnimation(keyPath: #keyPath(OverlayLayer.shadowHeight)) | |
animation.toValue = pressed ? 0.0 : defaultShadowHeight | |
animation.fromValue = pressed ? shadowHeight : 0.0 | |
animation.timingFunction = CAMediaTimingFunction(name: .easeOut) | |
animation.duration = duration | |
self.shadowHeight = animation.toValue as! CGFloat | |
self.add(animation, forKey: "press") | |
} | |
override public class func needsDisplay(forKey key: String) -> Bool { | |
if key == #keyPath(OverlayLayer.shadowHeight) { | |
return true | |
} | |
return super.needsDisplay(forKey: key) | |
} | |
public override func draw(in ctx: CGContext) { | |
print(self.color) // Not == to the color that was set in init | |
let shadowBackground = CGRect.init(origin: .zero, size: .init(width: frame.width, height: frame.height)) | |
let fillBackground = CGRect.init(origin: .zero, size: .init(width: frame.width, height: frame.height - shadowHeight)) | |
ctx.setFillColor(self.color.darker().cgColor) | |
ctx.addPath(UIBezierPath(roundedRect: shadowBackground, cornerRadius: cornerRadius).cgPath) | |
ctx.fillPath() | |
ctx.setFillColor(self.color.cgColor) | |
ctx.closePath() | |
ctx.beginPath() | |
ctx.addPath(UIBezierPath(roundedRect: fillBackground, cornerRadius: cornerRadius).cgPath) | |
ctx.fillPath() | |
super.draw(in: ctx) | |
} | |
} | |
final public class TestView: UIView { | |
public override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) { | |
overlayLayer?.animate(pressed: true) | |
} | |
public override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) { | |
overlayLayer?.animate(pressed: false) | |
} | |
public required init?(coder aDecoder: NSCoder) { | |
super.init(coder: aDecoder) | |
} | |
public override init(frame: CGRect) { | |
super.init(frame: frame) | |
} | |
override public class var layerClass: AnyClass { | |
return OverlayLayer.self | |
} | |
public var overlayLayer: OverlayLayer? { | |
return layer as? OverlayLayer | |
} | |
public init(frame: CGRect, color: UIColor) { | |
super.init(frame: frame) | |
// color not being set in layer? | |
overlayLayer?.color = color | |
} | |
} | |
let view = TestView(frame: CGRect(origin: .zero, size: .init(width: 250, height: 250)), color: #colorLiteral(red: 0.9372549057, green: 0.3490196168, blue: 0.1921568662, alpha: 1)) | |
// The first display uses the correct color, but when the animation is run after being triggered by user interaction, | |
// it uses the default value instead of what should be the current value. | |
import PlaygroundSupport | |
PlaygroundPage.current.liveView = view |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Run this in a xCode Playground
Thanks for checking this out StackOverflow