-
-
Save iamtchelo/9a4581802daf61d9bf5a96017f5af4fe to your computer and use it in GitHub Desktop.
(Ab)using UIVisualEffectView effect settings
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
| //: Playground - noun: a place where people can play | |
| import UIKit | |
| import PlaygroundSupport | |
| import ObjectiveC | |
| let image = UIImage(named: "berlinerdom.jpg")! | |
| let imageView = UIImageView(image: image) | |
| imageView.frame.size.width = 540 | |
| imageView.frame.size.height = 363 | |
| let effectView = UIVisualEffectView(effect: UIBlurEffect(style: .light)) | |
| effectView.frame.size.width = 540//360 | |
| effectView.frame.size.height = 363//242 | |
| effectView.center = imageView.center | |
| imageView.addSubview(effectView) | |
| PlaygroundPage.current.liveView = imageView | |
| PlaygroundPage.current.needsIndefiniteExecution = true | |
| func properties(_ instance: NSObject) { | |
| var count = UInt32() | |
| let classToInspect = type(of: instance) | |
| let properties : UnsafeMutablePointer<objc_property_t?> = class_copyPropertyList(classToInspect, &count) | |
| var propertyNames = [String]() | |
| let intCount = Int(count) | |
| for i in 0..<intCount { | |
| let property : objc_property_t = properties[i]! | |
| guard let propertyName = NSString(utf8String: property_getName(property)) as? String else { | |
| debugPrint("Couldn't unwrap property name for \(property)") | |
| break | |
| } | |
| let v = instance.value(forKey: propertyName) | |
| print(v!) | |
| propertyNames.append(propertyName) | |
| } | |
| free(properties) | |
| print(propertyNames) | |
| } | |
| extension UIVisualEffectView { | |
| fileprivate var filterLayer: CALayer? { | |
| return layer.sublayers?.first | |
| } | |
| fileprivate var blurFilter: NSObject? { | |
| return filterLayer? | |
| .filters?.flatMap({ $0 as? NSObject }) | |
| .first(where: { $0.value(forKey: "name") as? String == "gaussianBlur" }) | |
| } | |
| fileprivate var saturationFilter: NSObject? { | |
| return filterLayer? | |
| .filters?.flatMap({ $0 as? NSObject }) | |
| .first(where: { $0.value(forKey: "name") as? String == "colorSaturate" }) | |
| } | |
| fileprivate var matrixFilter: NSObject? { | |
| return filterLayer? | |
| .filters?.flatMap({ $0 as? NSObject }) | |
| .first(where: { $0.value(forKey: "name") as? String == "colorMatrix" }) | |
| } | |
| var blurRadius: CGFloat? { | |
| get { | |
| return blurFilter?.value(forKey: kCIInputRadiusKey) as? CGFloat | |
| } | |
| set { | |
| blurFilter?.setValue(newValue, forKey: kCIInputRadiusKey) | |
| } | |
| } | |
| var enableBlur: Bool { | |
| get { | |
| let dimLayer = layer.sublayers?.last?.opacity != 0 | |
| return blurRadius != 0 && dimLayer | |
| } | |
| set { | |
| blurRadius = 0 | |
| layer.sublayers?.last?.opacity = newValue ? 1 : 0 | |
| } | |
| } | |
| /// the same as saturation amount 1 | |
| var enableSaturation: Bool { | |
| get { | |
| return saturationFilter?.value(forKey: "enabled") as? Bool ?? false | |
| } | |
| set { | |
| saturationFilter?.setValue(newValue, forKey: "enabled") | |
| } | |
| } | |
| var enableColorMatrix: Bool { | |
| get { | |
| return matrixFilter?.value(forKey: "enabled") as? Bool ?? false | |
| } | |
| set { | |
| matrixFilter?.setValue(newValue, forKey: "enabled") | |
| } | |
| } | |
| var saturationAmount: CGFloat? { | |
| get { | |
| return saturationFilter?.value(forKey: "inputAmount") as? CGFloat | |
| } | |
| set { | |
| saturationFilter?.setValue(newValue, forKey: "inputAmount") | |
| } | |
| } | |
| var scale: CGFloat? { | |
| get { | |
| return filterLayer?.value(forKey: "scale") as? CGFloat | |
| } | |
| set { | |
| filterLayer?.setValue(newValue, forKey: "scale") | |
| } | |
| } | |
| } | |
| func animateScale() { | |
| effectView.filterLayer?.removeAllAnimations() | |
| effectView.enableSaturation = false | |
| effectView.enableBlur = false | |
| let anim = CABasicAnimation(keyPath: "scale") | |
| anim.fromValue = 0.05 | |
| anim.toValue = 1 | |
| anim.duration = 5 | |
| anim.repeatCount = .infinity | |
| effectView.scale = 1 | |
| effectView.filterLayer?.add(anim, forKey: "scale") | |
| } | |
| func animateBlur() { | |
| effectView.filterLayer?.removeAllAnimations() | |
| effectView.enableSaturation = false | |
| effectView.scale = 1 | |
| effectView.enableBlur = false | |
| CATransaction.begin() | |
| CATransaction.setAnimationDuration(5) | |
| var anim = CABasicAnimation(keyPath: "filters.gaussianBlur.inputRadius") | |
| anim.fromValue = 30 | |
| anim.toValue = 0 | |
| anim.repeatCount = .infinity | |
| effectView.filterLayer?.add(anim, forKey: "filters.gaussianBlur.inputRadius") | |
| anim = CABasicAnimation(keyPath: "opacity") | |
| anim.fromValue = 1 | |
| anim.toValue = 0 | |
| anim.repeatCount = .infinity | |
| effectView.layer.sublayers?.last?.add(anim, forKey: "opacity") | |
| CATransaction.commit() | |
| } | |
| func animateBlurUIKit() { | |
| effectView.filterLayer?.removeAllAnimations() | |
| UIView.animate(withDuration: 5, delay: 0, options: .repeat, animations: { | |
| effectView.effect = nil | |
| }, completion: nil) | |
| } | |
| func animateSaturation() { | |
| effectView.filterLayer?.removeAllAnimations() | |
| effectView.enableBlur = false | |
| effectView.scale = 1 | |
| let anim = CABasicAnimation(keyPath: "filters.colorSaturate.inputAmount") | |
| anim.fromValue = 0 | |
| anim.toValue = 1.8 | |
| anim.duration = 5 | |
| anim.repeatCount = .infinity | |
| effectView.saturationAmount = 1.8 | |
| effectView.filterLayer?.add(anim, forKey: "filters.colorSaturate.inputAmount") | |
| } | |
| //animateScale() | |
| //animateBlur() | |
| //animateBlurUIKit() | |
| //animateSaturation() | |
| effectView.enableSaturation = false | |
| effectView.scale = 0.5 | |
| effectView.blurRadius = 5 |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment