diff --git a/.swift-version b/.swift-version new file mode 100644 index 0000000..b8626c4 --- /dev/null +++ b/.swift-version @@ -0,0 +1 @@ +4 diff --git a/README.md b/README.md index 3ec18ae..34f1430 100644 --- a/README.md +++ b/README.md @@ -1,10 +1,14 @@ -![](http://cl.ly/image/3a1r1d3l3D1j/spring-logo.jpg) +## Updated for Swift 4.2 +Requires Xcode 10 and Swift 4.2. ## Installation -Drop in the Spring folder to your Xcode project. +Drop in the Spring folder to your Xcode project (make sure to enable "Copy items if needed" and "Create groups"). -Or via CocoaPods pre-release: -`pod 'Spring', '~> 1.0.1'` +Or via CocoaPods: +``` +use_frameworks! +pod 'Spring', :git => 'https://github.com/MengTo/Spring.git' +``` ## Usage with Storyboard In Identity Inspector, connect the UIView to SpringView Class and set the animation properties in Attribute Inspector. @@ -61,9 +65,9 @@ In Identity Inspector, connect the UIView to SpringView Class and set the animat ## Curve spring - linear - easeIn - easeOut + linear + easeIn + easeOut easeInOut ## Properties @@ -82,7 +86,7 @@ In Identity Inspector, connect the UIView to SpringView Class and set the animat ## Autostart -Allows you to animate without code. Don't need to use this is if you plan to start the animation in code. +Allows you to animate without code. Don't need to use this if you plan to start the animation in code. ## Autohide Saves you the hassle of adding a line "layer.alpha = 0" in viewDidLoad(). @@ -90,8 +94,6 @@ Saves you the hassle of adding a line "layer.alpha = 0" in viewDidLoad(). ## Known issue Animations won't autostart when view is reached via performSegueWithIdentifier. -Animations using IBInspectables are currently not working in iOS 7. iOS 8 is supported. We're looking for a fix. Animations in code works for both iOS 7 and 8. - ## Tutorials - Tutorials available on [Design+Code](https://designcode.io/swiftapp). - [Integrate Spring to existing Objective-C projects](https://medium.com/ios-apprentice/using-swift-in-objective-c-projects-f7e7a09f8be) @@ -102,4 +104,3 @@ Animations using IBInspectables are currently not working in iOS 7. iOS 8 is sup ## License Spring is released under the MIT license. See LICENSE for details. - diff --git a/Spring.podspec b/Spring.podspec index c588b1d..a43ed30 100644 --- a/Spring.podspec +++ b/Spring.podspec @@ -1,6 +1,6 @@ Pod::Spec.new do |s| s.name = 'Spring' - s.version = '1.0.1' + s.version = '1.0.6' s.license = 'MIT' s.summary = 'A library to simplify iOS animations in Swift.' s.homepage = 'https://github.com/MengTo/Spring' @@ -8,5 +8,8 @@ Pod::Spec.new do |s| s.source = { :git => 'https://github.com/MengTo/Spring.git', :tag => s.version.to_s } s.requires_arc = true s.ios.deployment_target = '8.0' + s.tvos.deployment_target = '11.0' s.source_files = 'Spring/*.swift' + s.ios.resources = ['Spring/*.xib', 'SpringApp/*.xcassets'] + s.tvos.resources = ['SpringApp/*.xcassets'] end diff --git a/Spring/AsyncButton.swift b/Spring/AsyncButton.swift index d92937c..6e03ac9 100644 --- a/Spring/AsyncButton.swift +++ b/Spring/AsyncButton.swift @@ -23,28 +23,29 @@ import UIKit public class AsyncButton: UIButton { - + private var imageURL = [UInt:NSURL]() private var placeholderImage = [UInt:UIImage]() - - - public func setImageURL(url: NSURL?, placeholderImage placeholder:UIImage?, forState state:UIControlState) { - + + + public func setImageURL(url: NSURL?, placeholderImage placeholder:UIImage?, forState state:UIControl.State) { + imageURL[state.rawValue] = url placeholderImage[state.rawValue] = placeholder - + if let urlString = url?.absoluteString { - ImageLoader.sharedLoader.imageForUrl(urlString) { [weak self] image, url in - + ImageLoader.sharedLoader.imageForUrl(urlString: urlString) { [weak self] image, url in + if let strongSelf = self { - dispatch_async(dispatch_get_main_queue(), { () -> Void in + + DispatchQueue.main.async(execute: { () -> Void in if strongSelf.imageURL[state.rawValue]?.absoluteString == url { - strongSelf.setImage(image, forState: state) + strongSelf.setImage(image, for: state) } }) } } } } - + } diff --git a/Spring/AsyncImageView.swift b/Spring/AsyncImageView.swift index 0e20cdf..aa2f7e8 100644 --- a/Spring/AsyncImageView.swift +++ b/Spring/AsyncImageView.swift @@ -30,11 +30,11 @@ public class AsyncImageView: UIImageView { didSet { self.image = placeholderImage if let urlString = url?.absoluteString { - ImageLoader.sharedLoader.imageForUrl(urlString) { [weak self] image, url in + ImageLoader.sharedLoader.imageForUrl(urlString: urlString) { [weak self] image, url in if let strongSelf = self { - dispatch_async(dispatch_get_main_queue(), { () -> Void in + DispatchQueue.main.async(execute: { () -> Void in if strongSelf.url?.absoluteString == url { - strongSelf.image = image + strongSelf.image = image ?? strongSelf.placeholderImage } }) } diff --git a/Spring/AutoTextView.swift b/Spring/AutoTextView.swift index e1b3e31..1d0c7e6 100644 --- a/Spring/AutoTextView.swift +++ b/Spring/AutoTextView.swift @@ -8,17 +8,20 @@ import UIKit -class AutoTextView: UITextView { - override func intrinsicContentSize() -> CGSize { - var size = self.sizeThatFits(CGSizeMake(self.frame.size.width, CGFloat.max)) - size.width = self.frame.size.width - if text.length == 0 { - size.height = 0 +public class AutoTextView: UITextView { + + public override var intrinsicContentSize: CGSize { + get { + var size = self.sizeThatFits(CGSize(width: self.frame.size.width, height: CGFloat.greatestFiniteMagnitude)) + size.width = self.frame.size.width + if text.length == 0 { + size.height = 0 + } + + contentInset = UIEdgeInsets(top: -4, left: -4, bottom: -4, right: -4) + layoutIfNeeded() + + return size } - - contentInset = UIEdgeInsetsMake(-4, -4, -4, -4) - layoutIfNeeded() - - return size } -} \ No newline at end of file +} diff --git a/Spring/BlurView.swift b/Spring/BlurView.swift index 4583633..8de1611 100644 --- a/Spring/BlurView.swift +++ b/Spring/BlurView.swift @@ -22,11 +22,12 @@ import UIKit -public func insertBlurView (view: UIView, style: UIBlurEffectStyle) { - view.backgroundColor = UIColor.clearColor() +public func insertBlurView (view: UIView, style: UIBlurEffect.Style) -> UIVisualEffectView { + view.backgroundColor = UIColor.clear - var blurEffect = UIBlurEffect(style: style) - var blurEffectView = UIVisualEffectView(effect: blurEffect) + let blurEffect = UIBlurEffect(style: style) + let blurEffectView = UIVisualEffectView(effect: blurEffect) blurEffectView.frame = view.bounds - view.insertSubview(blurEffectView, atIndex: 0) -} \ No newline at end of file + view.insertSubview(blurEffectView, at: 0) + return blurEffectView +} diff --git a/Spring/DesignableButton.swift b/Spring/DesignableButton.swift index 5b0a9c7..0612083 100644 --- a/Spring/DesignableButton.swift +++ b/Spring/DesignableButton.swift @@ -24,9 +24,9 @@ import UIKit @IBDesignable public class DesignableButton: SpringButton { - @IBInspectable public var borderColor: UIColor = UIColor.clearColor() { + @IBInspectable public var borderColor: UIColor = UIColor.clear { didSet { - layer.borderColor = borderColor.CGColor + layer.borderColor = borderColor.cgColor } } @@ -42,9 +42,9 @@ import UIKit } } - @IBInspectable public var shadowColor: UIColor = UIColor.clearColor() { + @IBInspectable public var shadowColor: UIColor = UIColor.clear { didSet { - layer.shadowColor = shadowColor.CGColor + layer.shadowColor = shadowColor.cgColor } } diff --git a/Spring/DesignableImageView.swift b/Spring/DesignableImageView.swift index 60c5a16..32a90a2 100644 --- a/Spring/DesignableImageView.swift +++ b/Spring/DesignableImageView.swift @@ -24,9 +24,9 @@ import UIKit @IBDesignable public class DesignableImageView: SpringImageView { - @IBInspectable public var borderColor: UIColor = UIColor.clearColor() { + @IBInspectable public var borderColor: UIColor = UIColor.clear { didSet { - layer.borderColor = borderColor.CGColor + layer.borderColor = borderColor.cgColor } } diff --git a/Spring/DesignableLabel.swift b/Spring/DesignableLabel.swift index e982cb4..8d6994b 100644 --- a/Spring/DesignableLabel.swift +++ b/Spring/DesignableLabel.swift @@ -26,15 +26,15 @@ import UIKit @IBInspectable public var lineHeight: CGFloat = 1.5 { didSet { - var font = UIFont(name: self.font.fontName, size: self.font.pointSize) - var text = self.text + let font = UIFont(name: self.font.fontName, size: self.font.pointSize) + guard let text = self.text else { return } - var paragraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineHeight - var attributedString = NSMutableAttributedString(string: text!) - attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) - attributedString.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(0, attributedString.length)) + let attributedString = NSMutableAttributedString(string: text) + attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) + attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSMakeRange(0, attributedString.length)) self.attributedText = attributedString } diff --git a/Spring/DesignableTabBarController.swift b/Spring/DesignableTabBarController.swift index 5637f80..6c81095 100644 --- a/Spring/DesignableTabBarController.swift +++ b/Spring/DesignableTabBarController.swift @@ -24,77 +24,78 @@ import UIKit @IBDesignable class DesignableTabBarController: UITabBarController { - @IBInspectable var normalTint: UIColor = UIColor.clearColor() { + @IBInspectable var normalTint: UIColor = UIColor.clear { didSet { UITabBar.appearance().tintColor = normalTint - UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: normalTint], forState: UIControlState.Normal) + UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalTint], for: UIControl.State()) } } - @IBInspectable var selectedTint: UIColor = UIColor.clearColor() { + @IBInspectable var selectedTint: UIColor = UIColor.clear { didSet { - UITabBar.appearance().selectedImageTintColor = selectedTint - UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: selectedTint], forState:UIControlState.Selected) + UITabBar.appearance().tintColor = selectedTint + UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: selectedTint], for:UIControl.State.selected) } } @IBInspectable var fontName: String = "" { didSet { - UITabBarItem.appearance().setTitleTextAttributes([NSForegroundColorAttributeName: normalTint, NSFontAttributeName: UIFont(name: fontName, size: 11)!], forState: UIControlState.Normal) + UITabBarItem.appearance().setTitleTextAttributes([NSAttributedString.Key.foregroundColor: normalTint, NSAttributedString.Key.font: UIFont(name: fontName, size: 11)!], for: UIControl.State()) } } @IBInspectable var firstSelectedImage: UIImage? { didSet { - if let image = firstSelectedImage? { - var tabBarItems = self.tabBar.items as [UITabBarItem] - tabBarItems[0].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + if let image = firstSelectedImage { + var tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[0].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } } @IBInspectable var secondSelectedImage: UIImage? { didSet { - if let image = secondSelectedImage? { - var tabBarItems = self.tabBar.items as [UITabBarItem] - tabBarItems[1].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + if let image = secondSelectedImage { + var tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[1].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } } @IBInspectable var thirdSelectedImage: UIImage? { didSet { - if let image = thirdSelectedImage? { - var tabBarItems = self.tabBar.items as [UITabBarItem] - tabBarItems[2].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + if let image = thirdSelectedImage { + var tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[2].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } } @IBInspectable var fourthSelectedImage: UIImage? { didSet { - if let image = fourthSelectedImage? { - var tabBarItems = self.tabBar.items as [UITabBarItem] - tabBarItems[3].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + if let image = fourthSelectedImage { + var tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[3].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } } @IBInspectable var fifthSelectedImage: UIImage? { didSet { - if let image = fifthSelectedImage? { - var tabBarItems = self.tabBar.items as [UITabBarItem] - tabBarItems[4].selectedImage = image.imageWithRenderingMode(UIImageRenderingMode.AlwaysTemplate) + if let image = fifthSelectedImage { + var tabBarItems = self.tabBar.items as [UITabBarItem]? + tabBarItems?[4].selectedImage = image.withRenderingMode(UIImage.RenderingMode.alwaysTemplate) } } } override func viewDidLoad() { super.viewDidLoad() - - for item in self.tabBar.items as [UITabBarItem] { - if let image = item.image { - item.image = image.imageWithColor(self.normalTint).imageWithRenderingMode(UIImageRenderingMode.AlwaysOriginal) + if let items = self.tabBar.items { + for item in items { + if let image = item.image { + item.image = image.imageWithColor(tintColor: self.normalTint).withRenderingMode(UIImage.RenderingMode.alwaysOriginal) + } } } } @@ -104,19 +105,19 @@ extension UIImage { func imageWithColor(tintColor: UIColor) -> UIImage { UIGraphicsBeginImageContextWithOptions(self.size, false, self.scale) - let context = UIGraphicsGetCurrentContext() as CGContextRef - CGContextTranslateCTM(context, 0, self.size.height) - CGContextScaleCTM(context, 1.0, -1.0); - CGContextSetBlendMode(context, kCGBlendModeNormal) + let context = UIGraphicsGetCurrentContext() + context!.translateBy(x: 0, y: self.size.height) + context!.scaleBy(x: 1.0, y: -1.0); + context!.setBlendMode(CGBlendMode.normal) - let rect = CGRectMake(0, 0, self.size.width, self.size.height) as CGRect - CGContextClipToMask(context, rect, self.CGImage) + let rect = CGRect(x: 0, y: 0, width: self.size.width, height: self.size.height) + context?.clip(to: rect, mask: self.cgImage!) tintColor.setFill() - CGContextFillRect(context, rect) + context!.fill(rect) - let newImage = UIGraphicsGetImageFromCurrentImageContext() as UIImage + let newImage = UIGraphicsGetImageFromCurrentImageContext()! as UIImage UIGraphicsEndImageContext() return newImage } -} \ No newline at end of file +} diff --git a/Spring/DesignableTextField.swift b/Spring/DesignableTextField.swift index 7d70e2b..e334a8e 100644 --- a/Spring/DesignableTextField.swift +++ b/Spring/DesignableTextField.swift @@ -24,9 +24,10 @@ import UIKit @IBDesignable public class DesignableTextField: SpringTextField { - @IBInspectable public var placeholderColor: UIColor = UIColor.clearColor() { + @IBInspectable public var placeholderColor: UIColor = UIColor.clear { didSet { - attributedPlaceholder = NSAttributedString(string: placeholder!, attributes: [NSForegroundColorAttributeName: placeholderColor]) + guard let placeholder = placeholder else { return } + attributedPlaceholder = NSAttributedString(string: placeholder, attributes: [NSAttributedString.Key.foregroundColor: placeholderColor]) layoutSubviews() } @@ -34,37 +35,37 @@ import UIKit @IBInspectable public var sidePadding: CGFloat = 0 { didSet { - var padding = UIView(frame: CGRectMake(0, 0, sidePadding, sidePadding)) + let padding = UIView(frame: CGRect(x: 0, y: 0, width: sidePadding, height: sidePadding)) - leftViewMode = UITextFieldViewMode.Always + leftViewMode = UITextField.ViewMode.always leftView = padding - rightViewMode = UITextFieldViewMode.Always + rightViewMode = UITextField.ViewMode.always rightView = padding } } @IBInspectable public var leftPadding: CGFloat = 0 { didSet { - var padding = UIView(frame: CGRectMake(0, 0, leftPadding, 0)) + let padding = UIView(frame: CGRect(x: 0, y: 0, width: leftPadding, height: 0)) - leftViewMode = UITextFieldViewMode.Always + leftViewMode = UITextField.ViewMode.always leftView = padding } } @IBInspectable public var rightPadding: CGFloat = 0 { didSet { - var padding = UIView(frame: CGRectMake(0, 0, 0, rightPadding)) + let padding = UIView(frame: CGRect(x: 0, y: 0, width: rightPadding, height: 0)) - rightViewMode = UITextFieldViewMode.Always + rightViewMode = UITextField.ViewMode.always rightView = padding } } - @IBInspectable public var borderColor: UIColor = UIColor.clearColor() { + @IBInspectable public var borderColor: UIColor = UIColor.clear { didSet { - layer.borderColor = borderColor.CGColor + layer.borderColor = borderColor.cgColor } } @@ -82,15 +83,15 @@ import UIKit @IBInspectable public var lineHeight: CGFloat = 1.5 { didSet { - var font = UIFont(name: self.font.fontName, size: self.font.pointSize) - var text = self.text + let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) + guard let text = self.text else { return } - var paragraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineHeight - var attributedString = NSMutableAttributedString(string: text!) - attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) - attributedString.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(0, attributedString.length)) + let attributedString = NSMutableAttributedString(string: text) + attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length)) + attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSRange(location: 0, length: attributedString.length)) self.attributedText = attributedString } diff --git a/Spring/DesignableTextView.swift b/Spring/DesignableTextView.swift index cec69e6..779298a 100644 --- a/Spring/DesignableTextView.swift +++ b/Spring/DesignableTextView.swift @@ -24,9 +24,9 @@ import UIKit @IBDesignable public class DesignableTextView: SpringTextView { - @IBInspectable public var borderColor: UIColor = UIColor.clearColor() { + @IBInspectable public var borderColor: UIColor = UIColor.clear { didSet { - layer.borderColor = borderColor.CGColor + layer.borderColor = borderColor.cgColor } } @@ -41,21 +41,21 @@ import UIKit layer.cornerRadius = cornerRadius } } - + @IBInspectable public var lineHeight: CGFloat = 1.5 { didSet { - var font = UIFont(name: self.font.fontName, size: self.font.pointSize) - var text = self.text + let font = UIFont(name: self.font!.fontName, size: self.font!.pointSize) + guard let text = self.text else { return } - var paragraphStyle = NSMutableParagraphStyle() + let paragraphStyle = NSMutableParagraphStyle() paragraphStyle.lineSpacing = lineHeight - var attributedString = NSMutableAttributedString(string: text!) - attributedString.addAttribute(NSParagraphStyleAttributeName, value: paragraphStyle, range: NSMakeRange(0, attributedString.length)) - attributedString.addAttribute(NSFontAttributeName, value: font!, range: NSMakeRange(0, attributedString.length)) + let attributedString = NSMutableAttributedString(string: text) + attributedString.addAttribute(NSAttributedString.Key.paragraphStyle, value: paragraphStyle, range: NSRange(location: 0, length: attributedString.length)) + attributedString.addAttribute(NSAttributedString.Key.font, value: font!, range: NSRange(location: 0, length: attributedString.length)) self.attributedText = attributedString } } - + } diff --git a/Spring/DesignableView.swift b/Spring/DesignableView.swift index 62cca91..a82d23f 100644 --- a/Spring/DesignableView.swift +++ b/Spring/DesignableView.swift @@ -24,9 +24,9 @@ import UIKit @IBDesignable public class DesignableView: SpringView { - @IBInspectable public var borderColor: UIColor = UIColor.clearColor() { + @IBInspectable public var borderColor: UIColor = UIColor.clear { didSet { - layer.borderColor = borderColor.CGColor + layer.borderColor = borderColor.cgColor } } @@ -42,9 +42,9 @@ import UIKit } } - @IBInspectable public var shadowColor: UIColor = UIColor.clearColor() { + @IBInspectable public var shadowColor: UIColor = UIColor.clear { didSet { - layer.shadowColor = shadowColor.CGColor + layer.shadowColor = shadowColor.cgColor } } @@ -65,4 +65,4 @@ import UIKit layer.shadowOffset.height = shadowOffsetY } } -} \ No newline at end of file +} diff --git a/Spring/ImageLoader.swift b/Spring/ImageLoader.swift index fe13699..bcb626d 100755 --- a/Spring/ImageLoader.swift +++ b/Spring/ImageLoader.swift @@ -26,45 +26,61 @@ import Foundation public class ImageLoader { - var cache = NSCache() + var cache = NSCache() public class var sharedLoader : ImageLoader { - struct Static { - static let instance : ImageLoader = ImageLoader() + struct Static { + static let instance : ImageLoader = ImageLoader() } return Static.instance } - public func imageForUrl(urlString: String, completionHandler:(image: UIImage?, url: String) -> ()) { - dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), {()in - var data: NSData? = self.cache.objectForKey(urlString) as? NSData + public func imageForUrl(urlString: String, completionHandler: @escaping(_ image: UIImage?, _ url: String) -> ()) { + DispatchQueue.global(qos: DispatchQoS.QoSClass.background).async { + var data: NSData? + + if let dataCache = self.cache.object(forKey: urlString as NSString){ + data = (dataCache) as NSData + + }else{ + if (URL(string: urlString) != nil) + { + data = NSData(contentsOf: URL(string: urlString)!) + if data != nil { + self.cache.setObject(data!, forKey: urlString as NSString) + } + }else{ + return + } + } if let goodData = data { - let image = UIImage(data: goodData) - dispatch_async(dispatch_get_main_queue(), {() in - completionHandler(image: image, url: urlString) + let image = UIImage(data: goodData as Data) + DispatchQueue.main.async(execute: {() in + completionHandler(image, urlString) }) return } - var downloadTask: NSURLSessionDataTask = NSURLSession.sharedSession().dataTaskWithURL(NSURL(string: urlString)!, completionHandler: {(data: NSData!, response: NSURLResponse!, error: NSError!) -> Void in + let downloadTask: URLSessionDataTask = URLSession.shared.dataTask(with: URL(string: urlString)!, completionHandler: { (data, response, error) -> Void in + if (error != nil) { - completionHandler(image: nil, url: urlString) + completionHandler(nil, urlString) return } if data != nil { - let image = UIImage(data: data) - self.cache.setObject(data, forKey: urlString) - dispatch_async(dispatch_get_main_queue(), {() in - completionHandler(image: image, url: urlString) + let image = UIImage(data: data!) + self.cache.setObject(data! as NSData, forKey: urlString as NSString) + DispatchQueue.main.async(execute: {() in + completionHandler(image, urlString) }) return } - }) downloadTask.resume() - }) + + } } -} \ No newline at end of file +} diff --git a/Spring/Info.plist b/Spring/Info.plist index bd4db03..d3de8ee 100644 --- a/Spring/Info.plist +++ b/Spring/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - designcode.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/Spring/KeyboardLayoutConstraint.swift b/Spring/KeyboardLayoutConstraint.swift index b8dfe5e..1b45a56 100644 --- a/Spring/KeyboardLayoutConstraint.swift +++ b/Spring/KeyboardLayoutConstraint.swift @@ -22,74 +22,77 @@ import UIKit +#if !os(tvOS) +@available(tvOS, unavailable) public class KeyboardLayoutConstraint: NSLayoutConstraint { - + private var offset : CGFloat = 0 private var keyboardVisibleHeight : CGFloat = 0 - + + @available(tvOS, unavailable) override public func awakeFromNib() { super.awakeFromNib() - + offset = constant - - NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillShowNotification:", name: UIKeyboardWillShowNotification, object: nil) - NSNotificationCenter.defaultCenter().addObserver(self, selector: "keyboardWillHideNotification:", name: UIKeyboardWillHideNotification, object: nil) + + NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillShowNotification(_:)), name: UIWindow.keyboardWillShowNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(KeyboardLayoutConstraint.keyboardWillHideNotification(_:)), name: UIWindow.keyboardWillHideNotification, object: nil) } - + deinit { - NSNotificationCenter.defaultCenter().removeObserver(self) + NotificationCenter.default.removeObserver(self) } - + // MARK: Notification - - func keyboardWillShowNotification(notification: NSNotification) { + + @objc func keyboardWillShowNotification(_ notification: Notification) { if let userInfo = notification.userInfo { - if let frameValue = userInfo[UIKeyboardFrameEndUserInfoKey] as? NSValue { - let frame = frameValue.CGRectValue() + if let frameValue = userInfo[UIResponder.keyboardFrameEndUserInfoKey] as? NSValue { + let frame = frameValue.cgRectValue keyboardVisibleHeight = frame.size.height } - + self.updateConstant() - switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) { - case let (.Some(duration), .Some(curve)): - - let options = UIViewAnimationOptions(curve.unsignedLongValue) - - UIView.animateWithDuration( - NSTimeInterval(duration.doubleValue), + switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { + case let (.some(duration), .some(curve)): + + let options = UIView.AnimationOptions(rawValue: curve.uintValue) + + UIView.animate( + withDuration: TimeInterval(duration.doubleValue), delay: 0, options: options, animations: { - UIApplication.sharedApplication().keyWindow?.layoutIfNeeded() + UIApplication.shared.keyWindow?.layoutIfNeeded() return }, completion: { finished in }) default: - + break } - + } - + } - - func keyboardWillHideNotification(notification: NSNotification) { + + @objc func keyboardWillHideNotification(_ notification: NSNotification) { keyboardVisibleHeight = 0 self.updateConstant() - + if let userInfo = notification.userInfo { - - switch (userInfo[UIKeyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIKeyboardAnimationCurveUserInfoKey] as? NSNumber) { - case let (.Some(duration), .Some(curve)): - - let options = UIViewAnimationOptions(curve.unsignedLongValue) - - UIView.animateWithDuration( - NSTimeInterval(duration.doubleValue), + + switch (userInfo[UIResponder.keyboardAnimationDurationUserInfoKey] as? NSNumber, userInfo[UIResponder.keyboardAnimationCurveUserInfoKey] as? NSNumber) { + case let (.some(duration), .some(curve)): + + let options = UIView.AnimationOptions(rawValue: curve.uintValue) + + UIView.animate( + withDuration: TimeInterval(duration.doubleValue), delay: 0, options: options, animations: { - UIApplication.sharedApplication().keyWindow?.layoutIfNeeded() + UIApplication.shared.keyWindow?.layoutIfNeeded() return }, completion: { finished in }) @@ -98,9 +101,10 @@ public class KeyboardLayoutConstraint: NSLayoutConstraint { } } } - + func updateConstant() { self.constant = offset + keyboardVisibleHeight } - + } +#endif diff --git a/Spring/LoadingView.swift b/Spring/LoadingView.swift index 0e013a7..5f62ce8 100644 --- a/Spring/LoadingView.swift +++ b/Spring/LoadingView.swift @@ -22,6 +22,8 @@ import UIKit +#if !os(tvOS) +@available(tvOS, unavailable) public class LoadingView: UIView { @IBOutlet public weak var indicatorView: SpringView! @@ -29,15 +31,16 @@ public class LoadingView: UIView { override public func awakeFromNib() { let animation = CABasicAnimation() animation.keyPath = "transform.rotation.z" - animation.fromValue = degreesToRadians(0) - animation.toValue = degreesToRadians(360) + animation.fromValue = degreesToRadians(degrees: 0) + animation.toValue = degreesToRadians(degrees: 360) animation.duration = 0.9 animation.repeatCount = HUGE - indicatorView.layer.addAnimation(animation, forKey: "") + indicatorView.layer.add(animation, forKey: "") } class func designCodeLoadingView() -> UIView { - return NSBundle(forClass: self).loadNibNamed("LoadingView", owner: self, options: nil)[0] as UIView + + return Bundle(for: self).loadNibNamed("LoadingView", owner: self, options: nil)![0] as! UIView } } @@ -49,7 +52,7 @@ public extension UIView { public func showLoading() { - if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { + if self.viewWithTag(LoadingViewConstants.Tag) != nil { // If loading view is already found in current view hierachy, do nothing return } @@ -60,7 +63,7 @@ public extension UIView { self.addSubview(loadingXibView) loadingXibView.alpha = 0 - spring(0.7, { + SpringAnimation.spring(duration: 0.7, animations: { loadingXibView.alpha = 1 }) } @@ -70,13 +73,14 @@ public extension UIView { if let loadingXibView = self.viewWithTag(LoadingViewConstants.Tag) { loadingXibView.alpha = 1 - springWithCompletion(0.7, { + SpringAnimation.springWithCompletion(duration: 0.7, animations: { loadingXibView.alpha = 0 - loadingXibView.transform = CGAffineTransformMakeScale(3, 3) - }, { (completed) -> Void in + loadingXibView.transform = CGAffineTransform(scaleX: 3, y: 3) + }, completion: { (completed) -> Void in loadingXibView.removeFromSuperview() }) } } } +#endif diff --git a/Spring/Misc.swift b/Spring/Misc.swift index 7b9ed9d..96024b8 100644 --- a/Spring/Misc.swift +++ b/Spring/Misc.swift @@ -23,36 +23,37 @@ import UIKit public extension String { - public var length: Int { return countElements(self) } - - public func toURL() -> NSURL? { + var length: Int { return self.count } + + func toURL() -> NSURL? { return NSURL(string: self) } } public func htmlToAttributedString(text: String) -> NSAttributedString! { - let htmlData = text.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false) - let htmlString = NSAttributedString(data: htmlData!, options: [NSDocumentTypeDocumentAttribute: NSHTMLTextDocumentType], documentAttributes: nil, error: nil) + guard let htmlData = text.data(using: String.Encoding.utf8, allowLossyConversion: false) else { + return NSAttributedString() } + let htmlString: NSAttributedString? + do { + htmlString = try NSAttributedString(data: htmlData, options: [NSAttributedString.DocumentReadingOptionKey.documentType:NSAttributedString.DocumentType.html], documentAttributes: nil) + } catch _ { + htmlString = nil + } return htmlString } public func degreesToRadians(degrees: CGFloat) -> CGFloat { - return degrees * CGFloat(M_PI / 180) + return degrees * CGFloat(CGFloat.pi / 180) } -public func delay(delay:Double, closure:()->()) { - dispatch_after( - dispatch_time( - DISPATCH_TIME_NOW, - Int64(delay * Double(NSEC_PER_SEC)) - ), - dispatch_get_main_queue(), closure) +public func delay(delay:Double, closure: @escaping ()->()) { + DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + Double(Int64(delay * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC), execute: closure) } -public func imageFromURL(URL: String) -> UIImage { - let url = NSURL(string: URL) - let data = NSData(contentsOfURL: url!) +public func imageFromURL(_ Url: String) -> UIImage { + let url = Foundation.URL(string: Url) + let data = try? Data(contentsOf: url!) return UIImage(data: data!)! } @@ -65,14 +66,14 @@ public extension UIColor { var hex: String = hex if hex.hasPrefix("#") { - let index = advance(hex.startIndex, 1) - hex = hex.substringFromIndex(index) + let index = hex.index(hex.startIndex, offsetBy: 1) + hex = String(hex[index...]) } - - let scanner = NSScanner(string: hex) + + let scanner = Scanner(string: hex) var hexValue: CUnsignedLongLong = 0 - if scanner.scanHexLongLong(&hexValue) { - switch (countElements(hex)) { + if scanner.scanHexInt64(&hexValue) { + switch (hex.count) { case 3: red = CGFloat((hexValue & 0xF00) >> 8) / 15.0 green = CGFloat((hexValue & 0x0F0) >> 4) / 15.0 @@ -92,10 +93,10 @@ public extension UIColor { blue = CGFloat((hexValue & 0x0000FF00) >> 8) / 255.0 alpha = CGFloat(hexValue & 0x000000FF) / 255.0 default: - print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8") + print("Invalid RGB string, number of characters after '#' should be either 3, 4, 6 or 8", terminator: "") } } else { - println("Scan hex error") + print("Scan hex error") } self.init(red:red, green:green, blue:blue, alpha:alpha) } @@ -116,18 +117,18 @@ public func UIColorFromRGB(rgbValue: UInt) -> UIColor { } public func stringFromDate(date: NSDate, format: String) -> String { - let dateFormatter = NSDateFormatter() + let dateFormatter = DateFormatter() dateFormatter.dateFormat = format - return dateFormatter.stringFromDate(date) + return dateFormatter.string(from: date as Date) } -public func dateFromString(date: String, format: String) -> NSDate { - let dateFormatter = NSDateFormatter() +public func dateFromString(date: String, format: String) -> Date { + let dateFormatter = DateFormatter() dateFormatter.dateFormat = format - if let date = dateFormatter.dateFromString(date) { + if let date = dateFormatter.date(from: date) { return date } else { - return NSDate(timeIntervalSince1970: 0) + return Date(timeIntervalSince1970: 0) } } @@ -135,77 +136,128 @@ public func randomStringWithLength (len : Int) -> NSString { let letters : NSString = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789" - var randomString : NSMutableString = NSMutableString(capacity: len) + let randomString : NSMutableString = NSMutableString(capacity: len) - for (var i=0; i < len; i++){ - var length = UInt32 (letters.length) - var rand = arc4random_uniform(length) - randomString.appendFormat("%C", letters.characterAtIndex(Int(rand))) + for _ in 0 ..< len { + let length = UInt32 (letters.length) + let rand = arc4random_uniform(length) + randomString.appendFormat("%C", letters.character(at: Int(rand))) } return randomString } -public func timeAgoSinceDate(date:NSDate, numericDates:Bool) -> String { - let calendar = NSCalendar.currentCalendar() - let unitFlags = NSCalendarUnit.CalendarUnitMinute | NSCalendarUnit.CalendarUnitHour | NSCalendarUnit.CalendarUnitDay | NSCalendarUnit.CalendarUnitWeekOfYear | NSCalendarUnit.CalendarUnitMonth | NSCalendarUnit.CalendarUnitYear | NSCalendarUnit.CalendarUnitSecond - let now = NSDate() - let earliest = now.earlierDate(date) - let latest = now.laterDate(date) - let components:NSDateComponents = calendar.components(unitFlags, fromDate: earliest, toDate: latest, options: nil) +public func timeAgoSinceDate(date: Date, numericDates: Bool) -> String { + let calendar = Calendar.current + let unitFlags = Set(arrayLiteral: Calendar.Component.minute, Calendar.Component.hour, Calendar.Component.day, Calendar.Component.weekOfYear, Calendar.Component.month, Calendar.Component.year, Calendar.Component.second) + let now = Date() + let dateComparison = now.compare(date) + var earliest: Date + var latest: Date + + switch dateComparison { + case .orderedAscending: + earliest = now + latest = date + default: + earliest = date + latest = now + } + + let components: DateComponents = calendar.dateComponents(unitFlags, from: earliest, to: latest) + + guard + let year = components.year, + let month = components.month, + let weekOfYear = components.weekOfYear, + let day = components.day, + let hour = components.hour, + let minute = components.minute, + let second = components.second + else { + fatalError() + } - if (components.year >= 2) { - return "\(components.year)y" - } else if (components.year >= 1){ + if (year >= 2) { + return "\(year)y" + } else if (year >= 1) { if (numericDates){ return "1y" } else { return "1y" } - } else if (components.month >= 2) { - return "\(components.month * 4)w" - } else if (components.month >= 1){ + } else if (month >= 2) { + return "\(month * 4)w" + } else if (month >= 1) { if (numericDates){ return "4w" } else { return "4w" } - } else if (components.weekOfYear >= 2) { - return "\(components.weekOfYear)w" - } else if (components.weekOfYear >= 1){ + } else if (weekOfYear >= 2) { + return "\(weekOfYear)w" + } else if (weekOfYear >= 1){ if (numericDates){ return "1w" } else { return "1w" } - } else if (components.day >= 2) { - return "\(components.day)d" - } else if (components.day >= 1){ + } else if (day >= 2) { + return "\(components.day ?? 2)d" + } else if (day >= 1){ if (numericDates){ return "1d" } else { return "1d" } - } else if (components.hour >= 2) { - return "\(components.hour)h" - } else if (components.hour >= 1){ + } else if (hour >= 2) { + return "\(hour)h" + } else if (hour >= 1){ if (numericDates){ return "1h" } else { return "1h" } - } else if (components.minute >= 2) { - return "\(components.minute)m" - } else if (components.minute >= 1){ + } else if (minute >= 2) { + return "\(minute)m" + } else if (minute >= 1){ if (numericDates){ return "1m" } else { return "1m" } - } else if (components.second >= 3) { - return "\(components.second)s" + } else if (second >= 3) { + return "\(second)s" } else { return "now" } -} \ No newline at end of file +} + +extension UIImageView { + func setImage(url: URL, contentMode mode: UIView.ContentMode = .scaleAspectFit, placeholderImage: UIImage?) { + contentMode = mode + URLSession.shared.dataTask(with: url) { (data, response, error) in + guard + let httpURLResponse = response as? HTTPURLResponse, httpURLResponse.statusCode == 200, + let mimeType = response?.mimeType, mimeType.hasPrefix("image"), + let data = data, error == nil, + let image = UIImage(data: data) + else { + self.image = placeholderImage + return + } + DispatchQueue.main.async() { () -> Void in + self.image = image + + } + }.resume() + } + func setImage(urlString: String, contentMode mode: UIView.ContentMode = .scaleAspectFit, placeholderImage: UIImage?) { + guard let url = URL(string: urlString) else { + image = placeholderImage + return + } + setImage(url: url, contentMode: mode, placeholderImage: placeholderImage) + } +} diff --git a/Spring/SoundPlayer.swift b/Spring/SoundPlayer.swift index d39830c..d2451d9 100644 --- a/Spring/SoundPlayer.swift +++ b/Spring/SoundPlayer.swift @@ -23,40 +23,38 @@ import UIKit import AudioToolbox -public class SoundPlayer: NSObject { - - @IBInspectable var filename : String? - @IBInspectable var enabled : Bool = true - +public struct SoundPlayer { + + static var filename : String? + static var enabled : Bool = true + private struct Internal { - static var cache = [NSURL:SystemSoundID]() + static var cache = [URL:SystemSoundID]() } - - public func playSound(soundFile:String) { - + + public static func playSound(soundFile: String) { + if !enabled { return } - - if let url = NSBundle.mainBundle().URLForResource(soundFile, withExtension: nil) { - + + if let url = Bundle.main.url(forResource: soundFile, withExtension: nil) { + var soundID : SystemSoundID = Internal.cache[url] ?? 0 - + if soundID == 0 { - AudioServicesCreateSystemSoundID(url, &soundID) + AudioServicesCreateSystemSoundID(url as CFURL, &soundID) Internal.cache[url] = soundID } - + AudioServicesPlaySystemSound(soundID) - + } else { - println("Could not find sound file name `\(soundFile)`") + print("Could not find sound file name `\(soundFile)`") } } - - @IBAction public func play(sender: AnyObject?) { - if let filename = filename { - self.playSound(filename) - } + + static func play(file: String) { + self.playSound(soundFile: file) } } diff --git a/Spring/Spring.swift b/Spring/Spring.swift index 628ecd8..cf86e1a 100644 --- a/Spring/Spring.swift +++ b/Spring/Spring.swift @@ -40,45 +40,46 @@ import UIKit var opacity: CGFloat { get set } var animateFrom: Bool { get set } var curve: String { get set } - + // UIView var layer : CALayer { get } var transform : CGAffineTransform { get set } var alpha : CGFloat { get set } func animate() - func animateNext(completion: () -> ()) + func animateNext(completion: @escaping () -> ()) func animateTo() - func animateToNext(completion: () -> ()) + func animateToNext(completion: @escaping () -> ()) } public class Spring : NSObject { - + private unowned var view : Springable private var shouldAnimateAfterActive = false - + private var shouldAnimateInLayoutSubviews = true + init(_ view: Springable) { self.view = view super.init() commonInit() } - + func commonInit() { - NSNotificationCenter.defaultCenter().addObserver(self, selector: "didBecomeActiveNotification:", name: UIApplicationDidBecomeActiveNotification, object: nil) + NotificationCenter.default.addObserver(self, selector: #selector(Spring.didBecomeActiveNotification(_:)), name: UIApplication.didBecomeActiveNotification, object: nil) } - - func didBecomeActiveNotification(notification: NSNotification) { + + @objc func didBecomeActiveNotification(_ notification: NSNotification) { if shouldAnimateAfterActive { alpha = 0 animate() shouldAnimateAfterActive = false } } - + deinit { - NSNotificationCenter.defaultCenter().removeObserver(self, name: UIApplicationDidBecomeActiveNotification, object: nil) + NotificationCenter.default.removeObserver(self, name: UIApplication.didBecomeActiveNotification, object: nil) } - + private var autostart: Bool { set { self.view.autostart = newValue } get { return self.view.autostart }} private var autohide: Bool { set { self.view.autohide = newValue } get { return self.view.autohide }} private var animation: String { set { self.view.animation = newValue } get { return self.view.animation }} @@ -96,318 +97,346 @@ public class Spring : NSObject { private var opacity: CGFloat { set { self.view.opacity = newValue } get { return self.view.opacity }} private var animateFrom: Bool { set { self.view.animateFrom = newValue } get { return self.view.animateFrom }} private var curve: String { set { self.view.curve = newValue } get { return self.view.curve }} - + // UIView private var layer : CALayer { return view.layer } private var transform : CGAffineTransform { get { return view.transform } set { view.transform = newValue }} private var alpha: CGFloat { get { return view.alpha } set { view.alpha = newValue } } - + + public enum AnimationPreset: String { + case SlideLeft = "slideLeft" + case SlideRight = "slideRight" + case SlideDown = "slideDown" + case SlideUp = "slideUp" + case SqueezeLeft = "squeezeLeft" + case SqueezeRight = "squeezeRight" + case SqueezeDown = "squeezeDown" + case SqueezeUp = "squeezeUp" + case FadeIn = "fadeIn" + case FadeOut = "fadeOut" + case FadeOutIn = "fadeOutIn" + case FadeInLeft = "fadeInLeft" + case FadeInRight = "fadeInRight" + case FadeInDown = "fadeInDown" + case FadeInUp = "fadeInUp" + case ZoomIn = "zoomIn" + case ZoomOut = "zoomOut" + case Fall = "fall" + case Shake = "shake" + case Pop = "pop" + case FlipX = "flipX" + case FlipY = "flipY" + case Morph = "morph" + case Squeeze = "squeeze" + case Flash = "flash" + case Wobble = "wobble" + case Swing = "swing" + } + + public enum AnimationCurve: String { + case EaseIn = "easeIn" + case EaseOut = "easeOut" + case EaseInOut = "easeInOut" + case Linear = "linear" + case Spring = "spring" + case EaseInSine = "easeInSine" + case EaseOutSine = "easeOutSine" + case EaseInOutSine = "easeInOutSine" + case EaseInQuad = "easeInQuad" + case EaseOutQuad = "easeOutQuad" + case EaseInOutQuad = "easeInOutQuad" + case EaseInCubic = "easeInCubic" + case EaseOutCubic = "easeOutCubic" + case EaseInOutCubic = "easeInOutCubic" + case EaseInQuart = "easeInQuart" + case EaseOutQuart = "easeOutQuart" + case EaseInOutQuart = "easeInOutQuart" + case EaseInQuint = "easeInQuint" + case EaseOutQuint = "easeOutQuint" + case EaseInOutQuint = "easeInOutQuint" + case EaseInExpo = "easeInExpo" + case EaseOutExpo = "easeOutExpo" + case EaseInOutExpo = "easeInOutExpo" + case EaseInCirc = "easeInCirc" + case EaseOutCirc = "easeOutCirc" + case EaseInOutCirc = "easeInOutCirc" + case EaseInBack = "easeInBack" + case EaseOutBack = "easeOutBack" + case EaseInOutBack = "easeInOutBack" + } + func animatePreset() { - if animation == "" { - return - } - - switch animation { - case "slideLeft": - x = 300*force - case "slideRight": - x = -300*force - case "slideDown": - y = -300*force - case "slideUp": - y = 300*force - case "squeezeLeft": - x = 300 - scaleX = 3*force - case "squeezeRight": - x = -300 - scaleX = 3*force - case "squeezeDown": - y = -300 - scaleY = 3*force - case "squeezeUp": - y = 300 - scaleY = 3*force - case "fadeIn": - opacity = 0 - case "fadeOut": - animateFrom = false - opacity = 0 - case "fadeOutIn": - let animation = CABasicAnimation() - animation.keyPath = "opacity" - animation.fromValue = 1 - animation.toValue = 0 - animation.timingFunction = getTimingFunction(curve) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.autoreverses = true - layer.addAnimation(animation, forKey: "fade") - case "fadeInLeft": - opacity = 0 - x = 300*force - case "fadeInRight": - x = -300*force - opacity = 0 - case "fadeInDown": - y = -300*force - opacity = 0 - case "fadeInUp": - y = 300*force - opacity = 0 - case "zoomIn": - opacity = 0 - scaleX = 2*force - scaleY = 2*force - case "zoomOut": - animateFrom = false - opacity = 0 - scaleX = 2*force - scaleY = 2*force - case "fall": - animateFrom = false - rotate = 15 * CGFloat(M_PI/180) - y = 600*force - case "shake": - let animation = CAKeyframeAnimation() - animation.keyPath = "position.x" - animation.values = [0, 30*force, -30*force, 30*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.timingFunction = getTimingFunction(curve) - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "shake") - case "pop": - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.scale" - animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.timingFunction = getTimingFunction(curve) - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.repeatCount = repeatCount - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "pop") - case "flipX": - rotate = 0 - scaleX = 1 - scaleY = 1 - var perspective = CATransform3DIdentity - perspective.m34 = -1.0 / layer.frame.size.width/2 - - let animation = CABasicAnimation() - animation.keyPath = "transform" - animation.fromValue = NSValue(CATransform3D: - CATransform3DMakeRotation(0, 0, 0, 0)) - animation.toValue = NSValue(CATransform3D: - CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(M_PI), 0, 1, 0))) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.timingFunction = getTimingFunction(curve) - layer.addAnimation(animation, forKey: "3d") - case "flipY": - var perspective = CATransform3DIdentity - perspective.m34 = -1.0 / layer.frame.size.width/2 - - let animation = CABasicAnimation() - animation.keyPath = "transform" - animation.fromValue = NSValue(CATransform3D: - CATransform3DMakeRotation(0, 0, 0, 0)) - animation.toValue = NSValue(CATransform3D: - CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(M_PI), 1, 0, 0))) - animation.duration = CFTimeInterval(duration) - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - animation.timingFunction = getTimingFunction(curve) - layer.addAnimation(animation, forKey: "3d") - case "morph": - let morphX = CAKeyframeAnimation() - morphX.keyPath = "transform.scale.x" - morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] - morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphX.timingFunction = getTimingFunction(curve) - morphX.duration = CFTimeInterval(duration) - morphX.repeatCount = repeatCount - morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphX, forKey: "morphX") - - let morphY = CAKeyframeAnimation() - morphY.keyPath = "transform.scale.y" - morphY.values = [1, 0.7, 1.3*force, 0.7, 1] - morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphY.timingFunction = getTimingFunction(curve) - morphY.duration = CFTimeInterval(duration) - morphY.repeatCount = repeatCount - morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphY, forKey: "morphY") - case "squeeze": - let morphX = CAKeyframeAnimation() - morphX.keyPath = "transform.scale.x" - morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] - morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphX.timingFunction = getTimingFunction(curve) - morphX.duration = CFTimeInterval(duration) - morphX.repeatCount = repeatCount - morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphX, forKey: "morphX") - - let morphY = CAKeyframeAnimation() - morphY.keyPath = "transform.scale.y" - morphY.values = [1, 0.5, 1, 0.5, 1] - morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - morphY.timingFunction = getTimingFunction(curve) - morphY.duration = CFTimeInterval(duration) - morphY.repeatCount = repeatCount - morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(morphY, forKey: "morphY") - case "flash": - let animation = CABasicAnimation() - animation.keyPath = "opacity" - animation.fromValue = 1 - animation.toValue = 0 - animation.duration = CFTimeInterval(duration) - animation.repeatCount = repeatCount * 2.0 - animation.autoreverses = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "flash") - case "wobble": - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.rotation" - animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "wobble") - - let x = CAKeyframeAnimation() - x.keyPath = "position.x" - x.values = [0, 30*force, -30*force, 30*force, 0] - x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - x.timingFunction = getTimingFunction(curve) - x.duration = CFTimeInterval(duration) - x.additive = true - x.repeatCount = repeatCount - x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(x, forKey: "x") - case "swing": - let animation = CAKeyframeAnimation() - animation.keyPath = "transform.rotation" - animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] - animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] - animation.duration = CFTimeInterval(duration) - animation.additive = true - animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) - layer.addAnimation(animation, forKey: "swing") - default: - x = 300 + alpha = 0.99 + if let animation = AnimationPreset(rawValue: animation) { + switch animation { + case .SlideLeft: + x = 300*force + case .SlideRight: + x = -300*force + case .SlideDown: + y = -300*force + case .SlideUp: + y = 300*force + case .SqueezeLeft: + x = 300 + scaleX = 3*force + case .SqueezeRight: + x = -300 + scaleX = 3*force + case .SqueezeDown: + y = -300 + scaleY = 3*force + case .SqueezeUp: + y = 300 + scaleY = 3*force + case .FadeIn: + opacity = 0 + case .FadeOut: + animateFrom = false + opacity = 0 + case .FadeOutIn: + let animation = CABasicAnimation() + animation.keyPath = "opacity" + animation.fromValue = 1 + animation.toValue = 0 + animation.timingFunction = getTimingFunction(curve: curve) + animation.duration = CFTimeInterval(duration) + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.autoreverses = true + layer.add(animation, forKey: "fade") + case .FadeInLeft: + opacity = 0 + x = 300*force + case .FadeInRight: + x = -300*force + opacity = 0 + case .FadeInDown: + y = -300*force + opacity = 0 + case .FadeInUp: + y = 300*force + opacity = 0 + case .ZoomIn: + opacity = 0 + scaleX = 2*force + scaleY = 2*force + case .ZoomOut: + animateFrom = false + opacity = 0 + scaleX = 2*force + scaleY = 2*force + case .Fall: + animateFrom = false + rotate = 15 * CGFloat(CGFloat.pi/180) + y = 600*force + case .Shake: + let animation = CAKeyframeAnimation() + animation.keyPath = "position.x" + animation.values = [0, 30*force, -30*force, 30*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.timingFunction = getTimingFunction(curve: curve) + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "shake") + case .Pop: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.scale" + animation.values = [0, 0.2*force, -0.2*force, 0.2*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.timingFunction = getTimingFunction(curve: curve) + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "pop") + case .FlipX: + rotate = 0 + scaleX = 1 + scaleY = 1 + var perspective = CATransform3DIdentity + perspective.m34 = -1.0 / layer.frame.size.width/2 + + let animation = CABasicAnimation() + animation.keyPath = "transform" + animation.fromValue = NSValue(caTransform3D: CATransform3DMakeRotation(0, 0, 0, 0)) + animation.toValue = NSValue(caTransform3D: + CATransform3DConcat(perspective, CATransform3DMakeRotation(CGFloat(CGFloat.pi), 0, 1, 0))) + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.timingFunction = getTimingFunction(curve: curve) + layer.add(animation, forKey: "3d") + case .FlipY: + var perspective = CATransform3DIdentity + perspective.m34 = -1.0 / layer.frame.size.width/2 + + let animation = CABasicAnimation() + animation.keyPath = "transform" + animation.fromValue = NSValue(caTransform3D: + CATransform3DMakeRotation(0, 0, 0, 0)) + animation.toValue = NSValue(caTransform3D: + CATransform3DConcat(perspective,CATransform3DMakeRotation(CGFloat(CGFloat.pi), 1, 0, 0))) + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + animation.timingFunction = getTimingFunction(curve: curve) + layer.add(animation, forKey: "3d") + case .Morph: + let morphX = CAKeyframeAnimation() + morphX.keyPath = "transform.scale.x" + morphX.values = [1, 1.3*force, 0.7, 1.3*force, 1] + morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphX.timingFunction = getTimingFunction(curve: curve) + morphX.duration = CFTimeInterval(duration) + morphX.repeatCount = repeatCount + morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphX, forKey: "morphX") + + let morphY = CAKeyframeAnimation() + morphY.keyPath = "transform.scale.y" + morphY.values = [1, 0.7, 1.3*force, 0.7, 1] + morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphY.timingFunction = getTimingFunction(curve: curve) + morphY.duration = CFTimeInterval(duration) + morphY.repeatCount = repeatCount + morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphY, forKey: "morphY") + case .Squeeze: + let morphX = CAKeyframeAnimation() + morphX.keyPath = "transform.scale.x" + morphX.values = [1, 1.5*force, 0.5, 1.5*force, 1] + morphX.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphX.timingFunction = getTimingFunction(curve: curve) + morphX.duration = CFTimeInterval(duration) + morphX.repeatCount = repeatCount + morphX.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphX, forKey: "morphX") + + let morphY = CAKeyframeAnimation() + morphY.keyPath = "transform.scale.y" + morphY.values = [1, 0.5, 1, 0.5, 1] + morphY.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + morphY.timingFunction = getTimingFunction(curve: curve) + morphY.duration = CFTimeInterval(duration) + morphY.repeatCount = repeatCount + morphY.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(morphY, forKey: "morphY") + case .Flash: + let animation = CABasicAnimation() + animation.keyPath = "opacity" + animation.fromValue = 1 + animation.toValue = 0 + animation.duration = CFTimeInterval(duration) + animation.repeatCount = repeatCount * 2.0 + animation.autoreverses = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "flash") + case .Wobble: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.rotation" + animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "wobble") + + let x = CAKeyframeAnimation() + x.keyPath = "position.x" + x.values = [0, 30*force, -30*force, 30*force, 0] + x.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + x.timingFunction = getTimingFunction(curve: curve) + x.duration = CFTimeInterval(duration) + x.isAdditive = true + x.repeatCount = repeatCount + x.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(x, forKey: "x") + case .Swing: + let animation = CAKeyframeAnimation() + animation.keyPath = "transform.rotation" + animation.values = [0, 0.3*force, -0.3*force, 0.3*force, 0] + animation.keyTimes = [0, 0.2, 0.4, 0.6, 0.8, 1] + animation.duration = CFTimeInterval(duration) + animation.isAdditive = true + animation.repeatCount = repeatCount + animation.beginTime = CACurrentMediaTime() + CFTimeInterval(delay) + layer.add(animation, forKey: "swing") + } } } - - + func getTimingFunction(curve: String) -> CAMediaTimingFunction { - switch curve { - case "easeIn": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseIn) - case "easeOut": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut) - case "easeInOut": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) - case "linear": - return CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) - case "spring": - return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) - case "easeInSine": - return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) - case "easeOutSine": - return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) - case "easeInOutSine": - return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) - case "easeInQuad": - return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) - case "easeOutQuad": - return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) - case "easeInOutQuad": - return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) - case "easeInCubic": - return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) - case "easeOutCubic": - return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) - case "easeInOutCubic": - return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) - case "easeInQuart": - return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) - case "easeOutQuart": - return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) - case "easeInOutQuart": - return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) - case "easeInQuint": - return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) - case "easeOutQuint": - return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) - case "easeInOutQuint": - return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) - case "easeInExpo": - return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) - case "easeOutExpo": - return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) - case "easeInOutExpo": - return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) - case "easeInCirc": - return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) - case "easeOutCirc": - return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) - case "easeInOutCirc": - return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) - case "easeInBack": - return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) - case "easeOutBack": - return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) - case "easeInOutBack": - return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) - default: - return CAMediaTimingFunction(name: kCAMediaTimingFunctionDefault) + if let curve = AnimationCurve(rawValue: curve) { + switch curve { + case .EaseIn: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn) + case .EaseOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut) + case .EaseInOut: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut) + case .Linear: return CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear) + case .Spring: return CAMediaTimingFunction(controlPoints: 0.5, 1.1+Float(force/3), 1, 1) + case .EaseInSine: return CAMediaTimingFunction(controlPoints: 0.47, 0, 0.745, 0.715) + case .EaseOutSine: return CAMediaTimingFunction(controlPoints: 0.39, 0.575, 0.565, 1) + case .EaseInOutSine: return CAMediaTimingFunction(controlPoints: 0.445, 0.05, 0.55, 0.95) + case .EaseInQuad: return CAMediaTimingFunction(controlPoints: 0.55, 0.085, 0.68, 0.53) + case .EaseOutQuad: return CAMediaTimingFunction(controlPoints: 0.25, 0.46, 0.45, 0.94) + case .EaseInOutQuad: return CAMediaTimingFunction(controlPoints: 0.455, 0.03, 0.515, 0.955) + case .EaseInCubic: return CAMediaTimingFunction(controlPoints: 0.55, 0.055, 0.675, 0.19) + case .EaseOutCubic: return CAMediaTimingFunction(controlPoints: 0.215, 0.61, 0.355, 1) + case .EaseInOutCubic: return CAMediaTimingFunction(controlPoints: 0.645, 0.045, 0.355, 1) + case .EaseInQuart: return CAMediaTimingFunction(controlPoints: 0.895, 0.03, 0.685, 0.22) + case .EaseOutQuart: return CAMediaTimingFunction(controlPoints: 0.165, 0.84, 0.44, 1) + case .EaseInOutQuart: return CAMediaTimingFunction(controlPoints: 0.77, 0, 0.175, 1) + case .EaseInQuint: return CAMediaTimingFunction(controlPoints: 0.755, 0.05, 0.855, 0.06) + case .EaseOutQuint: return CAMediaTimingFunction(controlPoints: 0.23, 1, 0.32, 1) + case .EaseInOutQuint: return CAMediaTimingFunction(controlPoints: 0.86, 0, 0.07, 1) + case .EaseInExpo: return CAMediaTimingFunction(controlPoints: 0.95, 0.05, 0.795, 0.035) + case .EaseOutExpo: return CAMediaTimingFunction(controlPoints: 0.19, 1, 0.22, 1) + case .EaseInOutExpo: return CAMediaTimingFunction(controlPoints: 1, 0, 0, 1) + case .EaseInCirc: return CAMediaTimingFunction(controlPoints: 0.6, 0.04, 0.98, 0.335) + case .EaseOutCirc: return CAMediaTimingFunction(controlPoints: 0.075, 0.82, 0.165, 1) + case .EaseInOutCirc: return CAMediaTimingFunction(controlPoints: 0.785, 0.135, 0.15, 0.86) + case .EaseInBack: return CAMediaTimingFunction(controlPoints: 0.6, -0.28, 0.735, 0.045) + case .EaseOutBack: return CAMediaTimingFunction(controlPoints: 0.175, 0.885, 0.32, 1.275) + case .EaseInOutBack: return CAMediaTimingFunction(controlPoints: 0.68, -0.55, 0.265, 1.55) + } } + return CAMediaTimingFunction(name: CAMediaTimingFunctionName.default) } - func getAnimationOptions(curve: String) -> UIViewAnimationOptions { - switch curve { - case "easeIn": - return UIViewAnimationOptions.CurveEaseIn - case "easeOut": - return UIViewAnimationOptions.CurveEaseOut - case "easeInOut": - return UIViewAnimationOptions.CurveEaseInOut - case "linear": - return UIViewAnimationOptions.CurveLinear - case "spring": - return UIViewAnimationOptions.CurveLinear - default: - return UIViewAnimationOptions.CurveLinear + + func getAnimationOptions(curve: String) -> UIView.AnimationOptions { + if let curve = AnimationCurve(rawValue: curve) { + switch curve { + case .EaseIn: return UIView.AnimationOptions.curveEaseIn + case .EaseOut: return UIView.AnimationOptions.curveEaseOut + case .EaseInOut: return UIView.AnimationOptions() + default: break + } } + return UIView.AnimationOptions.curveLinear } - + public func animate() { animateFrom = true animatePreset() setView {} } - - public func animateNext(completion: () -> ()) { + + public func animateNext(completion: @escaping () -> ()) { animateFrom = true animatePreset() setView { completion() } } - + public func animateTo() { animateFrom = false animatePreset() setView {} } - - public func animateToNext(completion: () -> ()) { + + public func animateToNext(completion: @escaping () -> ()) { animateFrom = false animatePreset() setView { @@ -421,69 +450,70 @@ public class Spring : NSObject { } } - public func customDidMoveToWindow() { - - if autostart { - - if UIApplication.sharedApplication().applicationState != .Active { - shouldAnimateAfterActive = true - return + public func customLayoutSubviews() { + if shouldAnimateInLayoutSubviews { + shouldAnimateInLayoutSubviews = false + if autostart { + if UIApplication.shared.applicationState != .active { + shouldAnimateAfterActive = true + return + } + alpha = 0 + animate() } - - alpha = 0 - animate() } } - - func setView(completion: () -> ()) { + + func setView(completion: @escaping () -> ()) { if animateFrom { - let translate = CGAffineTransformMakeTranslation(self.x, self.y) - let scale = CGAffineTransformMakeScale(self.scaleX, self.scaleY) - let rotate = CGAffineTransformMakeRotation(self.rotate) - let translateAndScale = CGAffineTransformConcat(translate, scale) - self.transform = CGAffineTransformConcat(rotate, translateAndScale) - + let translate = CGAffineTransform(translationX: self.x, y: self.y) + let scale = CGAffineTransform(scaleX: self.scaleX, y: self.scaleY) + let rotate = CGAffineTransform(rotationAngle: self.rotate) + let translateAndScale = translate.concatenating(scale) + self.transform = rotate.concatenating(translateAndScale) + self.alpha = self.opacity } - - UIView.animateWithDuration( NSTimeInterval(duration), - delay: NSTimeInterval(delay), - usingSpringWithDamping: damping, - initialSpringVelocity: velocity, - options: getAnimationOptions(curve), - animations: { [weak self] in - if let _self = self - { - if _self.animateFrom { - _self.transform = CGAffineTransformIdentity - _self.alpha = 1 - } - else { - let translate = CGAffineTransformMakeTranslation(_self.x, _self.y) - let scale = CGAffineTransformMakeScale(_self.scaleX, _self.scaleY) - let rotate = CGAffineTransformMakeRotation(_self.rotate) - let translateAndScale = CGAffineTransformConcat(translate, scale) - _self.transform = CGAffineTransformConcat(rotate, translateAndScale) - - _self.alpha = _self.opacity - } - - } - - }, { [weak self] finished in + + UIView.animate( withDuration: TimeInterval(duration), + delay: TimeInterval(delay), + usingSpringWithDamping: damping, + initialSpringVelocity: velocity, + options: [getAnimationOptions(curve: curve), UIView.AnimationOptions.allowUserInteraction], + animations: { [weak self] in + if let _self = self + { + if _self.animateFrom { + _self.transform = CGAffineTransform.identity + _self.alpha = 1 + } + else { + let translate = CGAffineTransform(translationX: _self.x, y: _self.y) + let scale = CGAffineTransform(scaleX: _self.scaleX, y: _self.scaleY) + let rotate = CGAffineTransform(rotationAngle: _self.rotate) + let translateAndScale = translate.concatenating(scale) + _self.transform = rotate.concatenating(translateAndScale) + + _self.alpha = _self.opacity + } + + } + + }, completion: { [weak self] finished in completion() self?.resetAll() - + }) + } - + func reset() { x = 0 y = 0 opacity = 1 } - + func resetAll() { x = 0 y = 0 @@ -498,5 +528,5 @@ public class Spring : NSObject { delay = 0 duration = 0.7 } - -} \ No newline at end of file + +} diff --git a/Spring/SpringAnimation.swift b/Spring/SpringAnimation.swift index ff5d787..998882b 100644 --- a/Spring/SpringAnimation.swift +++ b/Spring/SpringAnimation.swift @@ -22,106 +22,91 @@ import UIKit -public func spring(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: nil, - animations: { - - animations() - - }, completion: { finished in - }) -} - -public func springEaseIn(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveEaseIn, - animations: { - - animations() - - }, completion: { finished in - }) -} +@objc public class SpringAnimation: NSObject { + public class func spring(duration: TimeInterval, animations: @escaping () -> Void) { + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, + completion: nil + ) + } -public func springEaseOut(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveEaseOut, - animations: { - - animations() - - }, completion: { finished in - }) -} + public class func springEaseIn(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: .curveEaseIn, + animations: { + animations() + }, + completion: nil + ) + } -public func springEaseInOut(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveEaseInOut, - animations: { - - animations() - - }, completion: { finished in - }) -} + public class func springEaseOut(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: .curveEaseOut, + animations: { + animations() + }, completion: nil + ) + } -public func springLinear(duration: NSTimeInterval, animations: (() -> Void)!) { - - UIView.animateWithDuration( - duration, - delay: 0, - options: UIViewAnimationOptions.CurveLinear, - animations: { - - animations() - - }, completion: { finished in - }) -} + public class func springEaseInOut(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: UIView.AnimationOptions(), + animations: { + animations() + }, completion: nil + ) + } -public func springWithDelay(duration: NSTimeInterval, delay: NSTimeInterval, animations: (() -> Void)!) { - UIView.animateWithDuration( - duration, - delay: delay, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: nil, - animations: { - - animations() - - }, completion: { finished in - }) -} + public class func springLinear(duration: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + options: .curveLinear, + animations: { + animations() + }, completion: nil + ) + } -public func springWithCompletion(duration: NSTimeInterval, animations: (() -> Void)!, completion: ((Bool) -> Void)!) { + public class func springWithDelay(duration: TimeInterval, delay: TimeInterval, animations: (() -> Void)!) { + UIView.animate( + withDuration: duration, + delay: delay, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, completion: nil + ) + } - UIView.animateWithDuration( - duration, - delay: 0, - usingSpringWithDamping: 0.7, - initialSpringVelocity: 0.7, - options: nil, - animations: { - - animations() - - }, completion: { finished in - completion(true) - }) -} \ No newline at end of file + public class func springWithCompletion(duration: TimeInterval, animations: (() -> Void)!, completion: ((Bool) -> Void)!) { + UIView.animate( + withDuration: duration, + delay: 0, + usingSpringWithDamping: 0.7, + initialSpringVelocity: 0.7, + options: [], + animations: { + animations() + }, completion: { finished in + completion(finished) + } + ) + } +} diff --git a/Spring/SpringButton.swift b/Spring/SpringButton.swift index 040f0f8..92124ea 100644 --- a/Spring/SpringButton.swift +++ b/Spring/SpringButton.swift @@ -22,7 +22,7 @@ import UIKit -public class SpringButton: UIButton, Springable { +open class SpringButton: UIButton, Springable { @IBInspectable public var autostart: Bool = false @IBInspectable public var autohide: Bool = false @IBInspectable public var animation: String = "" @@ -43,29 +43,29 @@ public class SpringButton: UIButton, Springable { lazy private var spring : Spring = Spring(self) - override public func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { self.spring.animate() } - public func animateNext(completion: () -> ()) { - self.spring.animateNext(completion) + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) } public func animateTo() { self.spring.animateTo() } - public func animateToNext(completion: () -> ()) { - self.spring.animateToNext(completion) + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) } -} \ No newline at end of file +} diff --git a/Spring/SpringImageView.swift b/Spring/SpringImageView.swift index 6b6481d..85ad61f 100644 --- a/Spring/SpringImageView.swift +++ b/Spring/SpringImageView.swift @@ -22,7 +22,7 @@ import UIKit -public class SpringImageView: UIImageView, Springable { +open class SpringImageView: UIImageView, Springable { @IBInspectable public var autostart: Bool = false @IBInspectable public var autohide: Bool = false @IBInspectable public var animation: String = "" @@ -43,30 +43,30 @@ public class SpringImageView: UIImageView, Springable { lazy private var spring : Spring = Spring(self) - override public func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { self.spring.animate() } - public func animateNext(completion: () -> ()) { - self.spring.animateNext(completion) + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) } public func animateTo() { self.spring.animateTo() } - public func animateToNext(completion: () -> ()) { - self.spring.animateToNext(completion) + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) } -} \ No newline at end of file +} diff --git a/Spring/SpringLabel.swift b/Spring/SpringLabel.swift index 4ce4934..c105a48 100644 --- a/Spring/SpringLabel.swift +++ b/Spring/SpringLabel.swift @@ -22,7 +22,7 @@ import UIKit -public class SpringLabel: UILabel, Springable { +open class SpringLabel: UILabel, Springable { @IBInspectable public var autostart: Bool = false @IBInspectable public var autohide: Bool = false @IBInspectable public var animation: String = "" @@ -43,30 +43,30 @@ public class SpringLabel: UILabel, Springable { lazy private var spring : Spring = Spring(self) - override public func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { self.spring.animate() } - public func animateNext(completion: () -> ()) { - self.spring.animateNext(completion) + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) } public func animateTo() { self.spring.animateTo() } - public func animateToNext(completion: () -> ()) { - self.spring.animateToNext(completion) + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) } -} \ No newline at end of file +} diff --git a/Spring/SpringTextField.swift b/Spring/SpringTextField.swift index b943688..966b6f7 100644 --- a/Spring/SpringTextField.swift +++ b/Spring/SpringTextField.swift @@ -22,7 +22,7 @@ import UIKit -public class SpringTextField: UITextField, Springable { +open class SpringTextField: UITextField, Springable { @IBInspectable public var autostart: Bool = false @IBInspectable public var autohide: Bool = false @IBInspectable public var animation: String = "" @@ -43,29 +43,29 @@ public class SpringTextField: UITextField, Springable { lazy private var spring : Spring = Spring(self) - override public func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { self.spring.animate() } - public func animateNext(completion: () -> ()) { - self.spring.animateNext(completion) + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) } public func animateTo() { self.spring.animateTo() } - public func animateToNext(completion: () -> ()) { - self.spring.animateToNext(completion) + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) } -} \ No newline at end of file +} diff --git a/Spring/SpringTextView.swift b/Spring/SpringTextView.swift index ab7ba15..55d4e4a 100644 --- a/Spring/SpringTextView.swift +++ b/Spring/SpringTextView.swift @@ -22,7 +22,7 @@ import UIKit -public class SpringTextView: UITextView, Springable { +open class SpringTextView: UITextView, Springable { @IBInspectable public var autostart: Bool = false @IBInspectable public var autohide: Bool = false @IBInspectable public var animation: String = "" @@ -43,30 +43,30 @@ public class SpringTextView: UITextView, Springable { lazy private var spring : Spring = Spring(self) - override public func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() self.spring.customAwakeFromNib() } - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { self.spring.animate() } - public func animateNext(completion: () -> ()) { - self.spring.animateNext(completion) + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) } public func animateTo() { self.spring.animateTo() } - public func animateToNext(completion: () -> ()) { - self.spring.animateToNext(completion) + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) } -} \ No newline at end of file +} diff --git a/Spring/SpringView.swift b/Spring/SpringView.swift index 1917924..a00c12a 100644 --- a/Spring/SpringView.swift +++ b/Spring/SpringView.swift @@ -22,7 +22,7 @@ import UIKit -public class SpringView: UIView, Springable { +open class SpringView: UIView, Springable { @IBInspectable public var autostart: Bool = false @IBInspectable public var autohide: Bool = false @IBInspectable public var animation: String = "" @@ -43,29 +43,29 @@ public class SpringView: UIView, Springable { lazy private var spring : Spring = Spring(self) - override public func awakeFromNib() { + override open func awakeFromNib() { super.awakeFromNib() self.spring.customAwakeFromNib() } - - override public func didMoveToWindow() { - super.didMoveToWindow() - self.spring.customDidMoveToWindow() + + open override func layoutSubviews() { + super.layoutSubviews() + spring.customLayoutSubviews() } public func animate() { self.spring.animate() } - public func animateNext(completion: () -> ()) { - self.spring.animateNext(completion) + public func animateNext(completion: @escaping () -> ()) { + self.spring.animateNext(completion: completion) } public func animateTo() { self.spring.animateTo() } - public func animateToNext(completion: () -> ()) { - self.spring.animateToNext(completion) + public func animateToNext(completion: @escaping () -> ()) { + self.spring.animateToNext(completion: completion) } -} \ No newline at end of file +} diff --git a/Spring/TransitionManager.swift b/Spring/TransitionManager.swift index 401e1c3..388edac 100644 --- a/Spring/TransitionManager.swift +++ b/Spring/TransitionManager.swift @@ -27,20 +27,20 @@ public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, var isPresenting = true var duration = 0.3 - public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { - let container = transitionContext.containerView() - let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! - let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! + public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let container = transitionContext.containerView + let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)! + let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)! if isPresenting { toView.frame = container.bounds - toView.transform = CGAffineTransformMakeTranslation(0, container.frame.size.height) + toView.transform = CGAffineTransform(translationX: 0, y: container.frame.size.height) container.addSubview(fromView) container.addSubview(toView) - springEaseInOut(duration) { - fromView.transform = CGAffineTransformMakeScale(0.8, 0.8) + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(scaleX: 0.8, y: 0.8) fromView.alpha = 0.5 - toView.transform = CGAffineTransformIdentity + toView.transform = CGAffineTransform.identity } } else { @@ -51,35 +51,35 @@ public class TransitionManager: NSObject, UIViewControllerTransitioningDelegate, // the same time take consideration of // previous transformation when presenting let transform = toView.transform - toView.transform = CGAffineTransformIdentity + toView.transform = CGAffineTransform.identity toView.frame = container.bounds toView.transform = transform container.addSubview(toView) container.addSubview(fromView) - springEaseInOut(duration) { - fromView.transform = CGAffineTransformMakeTranslation(0, fromView.frame.size.height) - toView.transform = CGAffineTransformIdentity + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(translationX: 0, y: fromView.frame.size.height) + toView.transform = CGAffineTransform.identity toView.alpha = 1 } } - delay(duration, { + delay(delay: duration, closure: { transitionContext.completeTransition(true) }) } - public func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { + public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return duration } - public func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + public func animationController(forPresentedController presented: UIViewController, presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { isPresenting = true return self } - public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { isPresenting = false return self } diff --git a/Spring/TransitionZoom.swift b/Spring/TransitionZoom.swift index da1f4bc..6cf5301 100644 --- a/Spring/TransitionZoom.swift +++ b/Spring/TransitionZoom.swift @@ -27,21 +27,22 @@ public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UI var isPresenting = true var duration = 0.4 - public func animateTransition(transitionContext: UIViewControllerContextTransitioning) { - let container = transitionContext.containerView() - let fromView = transitionContext.viewForKey(UITransitionContextFromViewKey)! - let toView = transitionContext.viewForKey(UITransitionContextToViewKey)! + public func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let container = transitionContext.containerView + let fromView = transitionContext.view(forKey: UITransitionContextViewKey.from)! + let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)! if isPresenting { container.addSubview(fromView) container.addSubview(toView) toView.alpha = 0 - toView.transform = CGAffineTransformMakeScale(2, 2) - springEaseInOut(duration) { - fromView.transform = CGAffineTransformMakeScale(0.5, 0.5) + toView.transform = CGAffineTransform(scaleX: 2, y: 2) + + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5) fromView.alpha = 0 - toView.transform = CGAffineTransformIdentity + toView.transform = CGAffineTransform.identity toView.alpha = 1 } } @@ -49,30 +50,30 @@ public class TransitionZoom: NSObject, UIViewControllerTransitioningDelegate, UI container.addSubview(toView) container.addSubview(fromView) - springEaseInOut(duration) { - fromView.transform = CGAffineTransformMakeScale(2, 2) + SpringAnimation.springEaseInOut(duration: duration) { + fromView.transform = CGAffineTransform(scaleX: 2, y: 2) fromView.alpha = 0 - toView.transform = CGAffineTransformMakeScale(1, 1) + toView.transform = CGAffineTransform(scaleX: 1, y: 1) toView.alpha = 1 } } - delay(duration, { + delay(delay: duration, closure: { transitionContext.completeTransition(true) }) } - public func transitionDuration(transitionContext: UIViewControllerContextTransitioning) -> NSTimeInterval { + public func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { return duration } - public func animationControllerForPresentedController(presented: UIViewController, presentingController presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { + public func animationController(forPresentedController presented: UIViewController, presenting: UIViewController, sourceController source: UIViewController) -> UIViewControllerAnimatedTransitioning? { isPresenting = true return self } - public func animationControllerForDismissedController(dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + public func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { isPresenting = false return self } -} \ No newline at end of file +} diff --git a/Spring/UnwindSegue.swift b/Spring/UnwindSegue.swift index a9aae71..53a71cb 100644 --- a/Spring/UnwindSegue.swift +++ b/Spring/UnwindSegue.swift @@ -23,5 +23,5 @@ import UIKit public extension UIViewController { - @IBAction public func unwindToViewController (sender: UIStoryboardSegue){} -} \ No newline at end of file + @IBAction public func unwindToViewController (_ segue: UIStoryboardSegue){} +} diff --git a/SpringApp.xcodeproj/project.pbxproj b/SpringApp.xcodeproj/project.pbxproj index a16045e..a0e8956 100644 --- a/SpringApp.xcodeproj/project.pbxproj +++ b/SpringApp.xcodeproj/project.pbxproj @@ -407,21 +407,26 @@ 964117331A5BE90A000E3A5A /* Project object */ = { isa = PBXProject; attributes = { - LastUpgradeCheck = 0620; + LastSwiftUpdateCheck = 0700; + LastUpgradeCheck = 0900; ORGANIZATIONNAME = "Meng To"; TargetAttributes = { 1A4FDA321A6E44780099D309 = { CreatedOnToolsVersion = 6.1.1; + LastSwiftMigration = 1020; }; 1A4FDA3C1A6E44780099D309 = { CreatedOnToolsVersion = 6.1.1; + LastSwiftMigration = 1020; TestTargetID = 9641173A1A5BE90A000E3A5A; }; 9641173A1A5BE90A000E3A5A = { CreatedOnToolsVersion = 6.2; + LastSwiftMigration = 1020; }; 9641174F1A5BE90A000E3A5A = { CreatedOnToolsVersion = 6.2; + LastSwiftMigration = 1020; TestTargetID = 9641173A1A5BE90A000E3A5A; }; }; @@ -431,6 +436,7 @@ developmentRegion = English; hasScannedForEncodings = 0; knownRegions = ( + English, en, Base, ); @@ -593,6 +599,7 @@ 1A4FDA4D1A6E44780099D309 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -606,8 +613,10 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -617,6 +626,7 @@ 1A4FDA4E1A6E44780099D309 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { + "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = ""; CURRENT_PROJECT_VERSION = 1; DEFINES_MODULE = YES; DYLIB_COMPATIBILITY_VERSION = 1; @@ -626,8 +636,11 @@ INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; SKIP_INSTALL = YES; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; VERSIONING_SYSTEM = "apple-generic"; VERSION_INFO_PREFIX = ""; @@ -637,10 +650,6 @@ 1A4FDA511A6E44780099D309 /* Debug */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", @@ -648,7 +657,9 @@ INFOPLIST_FILE = SpringTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jamztang.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; }; name = Debug; @@ -656,14 +667,13 @@ 1A4FDA521A6E44780099D309 /* Release */ = { isa = XCBuildConfiguration; buildSettings = { - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); INFOPLIST_FILE = SpringTests/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.1; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.jamztang.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; }; name = Release; @@ -676,20 +686,30 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; COPY_PHASE_STRIP = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; + ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -707,6 +727,7 @@ ONLY_ACTIVE_ARCH = YES; SDKROOT = iphoneos; SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; }; name = Debug; }; @@ -718,13 +739,21 @@ CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -732,6 +761,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -741,6 +771,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.2; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_SWIFT3_OBJC_INFERENCE = Off; VALIDATE_PRODUCT = YES; }; name = Release; @@ -752,7 +783,9 @@ INFOPLIST_FILE = SpringApp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Debug; @@ -764,7 +797,10 @@ INFOPLIST_FILE = SpringApp/Info.plist; IPHONEOS_DEPLOYMENT_TARGET = 8.0; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; TARGETED_DEVICE_FAMILY = "1,2"; }; name = Release; @@ -773,17 +809,15 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", "$(inherited)", ); INFOPLIST_FILE = SpringAppTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; }; name = Debug; @@ -792,13 +826,12 @@ isa = XCBuildConfiguration; buildSettings = { BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); INFOPLIST_FILE = SpringAppTests/Info.plist; LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "designcode.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + SWIFT_VERSION = 5.0; TEST_HOST = "$(BUILT_PRODUCTS_DIR)/SpringApp.app/SpringApp"; }; name = Release; diff --git a/SpringApp.xcodeproj/project.xcworkspace/xcshareddata/SpringApp.xccheckout b/SpringApp.xcodeproj/project.xcworkspace/xcshareddata/SpringApp.xccheckout new file mode 100644 index 0000000..7c00884 --- /dev/null +++ b/SpringApp.xcodeproj/project.xcworkspace/xcshareddata/SpringApp.xccheckout @@ -0,0 +1,41 @@ + + + + + IDESourceControlProjectFavoriteDictionaryKey + + IDESourceControlProjectIdentifier + 90BE4A8A-3AD7-483D-B9EA-ED8463875CE6 + IDESourceControlProjectName + SpringApp + IDESourceControlProjectOriginsDictionary + + 71F5D8D885CFF6BD7151066D7BFF25CC48A5235E + github.com:MengTo/Spring.git + + IDESourceControlProjectPath + SpringApp.xcodeproj + IDESourceControlProjectRelativeInstallPathDictionary + + 71F5D8D885CFF6BD7151066D7BFF25CC48A5235E + ../.. + + IDESourceControlProjectURL + github.com:MengTo/Spring.git + IDESourceControlProjectVersion + 111 + IDESourceControlProjectWCCIdentifier + 71F5D8D885CFF6BD7151066D7BFF25CC48A5235E + IDESourceControlProjectWCConfigurations + + + IDESourceControlRepositoryExtensionIdentifierKey + public.vcs.git + IDESourceControlWCCIdentifierKey + 71F5D8D885CFF6BD7151066D7BFF25CC48A5235E + IDESourceControlWCCName + Spring + + + + diff --git a/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme b/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme index 492fc4d..ecfaae8 100644 --- a/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme +++ b/SpringApp.xcodeproj/xcshareddata/xcschemes/Spring.xcscheme @@ -1,6 +1,6 @@ + shouldUseLaunchSchemeArgsEnv = "YES"> + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/SpringApp/AppDelegate.swift b/SpringApp/AppDelegate.swift index 68f9cca..fd03978 100644 --- a/SpringApp/AppDelegate.swift +++ b/SpringApp/AppDelegate.swift @@ -14,30 +14,29 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func applicationDidFinishLaunching(_ application: UIApplication) { // Override point for customization after application launch. - return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/SpringApp/Base.lproj/LaunchScreen.xib b/SpringApp/Base.lproj/LaunchScreen.xib index 3ace0e1..a13447c 100644 --- a/SpringApp/Base.lproj/LaunchScreen.xib +++ b/SpringApp/Base.lproj/LaunchScreen.xib @@ -1,7 +1,9 @@ - + - + + + @@ -11,15 +13,13 @@ - - + - - + diff --git a/SpringApp/Base.lproj/Main.storyboard b/SpringApp/Base.lproj/Main.storyboard index 1b4a473..6528bfc 100644 --- a/SpringApp/Base.lproj/Main.storyboard +++ b/SpringApp/Base.lproj/Main.storyboard @@ -1,8 +1,16 @@ - - + + - + + + + + + AvenirNext-DemiBold + AvenirNext-Regular + + @@ -13,15 +21,13 @@ - + - - - + @@ -35,32 +41,29 @@ - + @@ -130,67 +132,58 @@ - - - - + - - - + + - - - + + - - + - - + + - + @@ -210,7 +203,7 @@ - + @@ -256,40 +249,35 @@ - + - - - - - + + + - - + - + @@ -309,7 +297,7 @@ - + @@ -339,146 +327,130 @@ - + - - - - - + + - - - + + - - - + + - - - + + - - - + + - - - + + - + @@ -532,7 +504,7 @@ - + diff --git a/SpringApp/CodeViewController.swift b/SpringApp/CodeViewController.swift index 96e4895..9aa8327 100644 --- a/SpringApp/CodeViewController.swift +++ b/SpringApp/CodeViewController.swift @@ -20,7 +20,7 @@ class CodeViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - modalView.transform = CGAffineTransformMakeTranslation(-300, 0) + modalView.transform = CGAffineTransform(translationX: -300, y: 0) if data.animation != "" { codeText += "layer.animation = \"\(data.animation)\"\n" @@ -57,21 +57,23 @@ class CodeViewController: UIViewController { codeTextView.text = codeText } - @IBAction func closeButtonPressed(sender: AnyObject) { - UIApplication.sharedApplication().sendAction("maximizeView:", to: nil, from: self, forEvent: nil) + @IBAction func closeButtonPressed(_ sender: AnyObject) { + UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView(_:)), to: nil, from: self, for: nil) modalView.animation = "slideRight" modalView.animateFrom = false - modalView.animateToNext({ - self.dismissViewControllerAnimated(false, completion: nil) + modalView.animateToNext(completion: { + self.dismiss(animated: false, completion: nil) }) } - override func viewDidAppear(animated: Bool) { + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) modalView.animate() - UIApplication.sharedApplication().sendAction("minimizeView:", to: nil, from: self, forEvent: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.minimizeView(_:)), to: nil, from: self, for: nil) } } + + diff --git a/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json b/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json index 17d5afa..1acc2b0 100644 --- a/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json +++ b/SpringApp/Images.xcassets/AppIcon.appiconset/Contents.json @@ -71,6 +71,12 @@ "idiom" : "ipad", "filename" : "appicon@152.png", "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "appicon@167.png", + "scale" : "2x" } ], "info" : { diff --git a/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@167.png b/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@167.png new file mode 100644 index 0000000..9ae2444 Binary files /dev/null and b/SpringApp/Images.xcassets/AppIcon.appiconset/appicon@167.png differ diff --git a/SpringApp/Info.plist b/SpringApp/Info.plist index f5b3473..01aa7f4 100644 --- a/SpringApp/Info.plist +++ b/SpringApp/Info.plist @@ -2,14 +2,12 @@ - UIViewControllerBasedStatusBarAppearance - CFBundleDevelopmentRegion en CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - designcode.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName @@ -38,5 +36,7 @@ UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight + UIViewControllerBasedStatusBarAppearance + diff --git a/SpringApp/OptionsViewController.swift b/SpringApp/OptionsViewController.swift index 1cba77c..be62011 100644 --- a/SpringApp/OptionsViewController.swift +++ b/SpringApp/OptionsViewController.swift @@ -10,13 +10,13 @@ import UIKit import Spring protocol OptionsViewControllerDelegate: class { - func dampingSliderChanged(sender: AnyObject) - func velocitySliderChanged(sender: AnyObject) - func scaleSliderChanged(sender: AnyObject) - func xSliderChanged(sender: AnyObject) - func ySliderChanged(sender: AnyObject) - func rotateSliderChanged(sender: AnyObject) - func resetButtonPressed(sender: AnyObject) + func dampingSliderChanged(_ sender: AnyObject) + func velocitySliderChanged(_ sender: AnyObject) + func scaleSliderChanged(_ sender: AnyObject) + func xSliderChanged(_ sender: AnyObject) + func ySliderChanged(_ sender: AnyObject) + func rotateSliderChanged(_ sender: AnyObject) + func resetButtonPressed(_ sender: AnyObject) } class OptionsViewController: UIViewController { @@ -50,7 +50,7 @@ class OptionsViewController: UIViewController { override func viewDidLoad() { super.viewDidLoad() - modalView.transform = CGAffineTransformMakeTranslation(0, 300) + modalView.transform = CGAffineTransform(translationX: 0, y: 300) dampingSlider.setValue(Float(data.damping), animated: true) velocitySlider.setValue(Float(data.velocity), animated: true) @@ -67,64 +67,64 @@ class OptionsViewController: UIViewController { rotateLabel.text = getString("Rotate", value: data.rotate) } - @IBAction func dampingSliderChanged(sender: AnyObject) { - selectedDamping = sender.valueForKey("value") as CGFloat + @IBAction func dampingSliderChanged(_ sender: AnyObject) { + selectedDamping = sender.value(forKey: "value") as! CGFloat delegate?.dampingSliderChanged(sender) dampingLabel.text = getString("Damping", value: selectedDamping) } - @IBAction func velocitySliderChanged(sender: AnyObject) { - selectedVelocity = sender.valueForKey("value") as CGFloat + @IBAction func velocitySliderChanged(_ sender: AnyObject) { + selectedVelocity = sender.value(forKey: "value") as! CGFloat delegate?.velocitySliderChanged(sender) velocityLabel.text = getString("Velocity", value: selectedVelocity) } - @IBAction func scaleSliderChanged(sender: AnyObject) { - selectedScale = sender.valueForKey("value") as CGFloat + @IBAction func scaleSliderChanged(_ sender: AnyObject) { + selectedScale = sender.value(forKey: "value") as! CGFloat delegate?.scaleSliderChanged(sender) scaleLabel.text = getString("Scale", value: selectedScale) } - @IBAction func xSliderChanged(sender: AnyObject) { - selectedX = sender.valueForKey("value") as CGFloat + @IBAction func xSliderChanged(_ sender: AnyObject) { + selectedX = sender.value(forKey: "value") as! CGFloat delegate?.xSliderChanged(sender) xLabel.text = getString("X", value: selectedX) } - @IBAction func ySliderChanged(sender: AnyObject) { - selectedY = sender.valueForKey("value") as CGFloat + @IBAction func ySliderChanged(_ sender: AnyObject) { + selectedY = sender.value(forKey: "value") as! CGFloat delegate?.ySliderChanged(sender) yLabel.text = getString("Y", value: selectedY) } - @IBAction func rotateSliderChanged(sender: AnyObject) { - selectedRotate = sender.valueForKey("value") as CGFloat + @IBAction func rotateSliderChanged(_ sender: AnyObject) { + selectedRotate = sender.value(forKey: "value") as! CGFloat delegate?.rotateSliderChanged(sender) rotateLabel.text = getString("Rotate", value: selectedRotate) } - @IBAction func resetButtonPressed(sender: AnyObject) { + @IBAction func resetButtonPressed(_ sender: AnyObject) { delegate?.resetButtonPressed(sender) - dismissViewControllerAnimated(true, completion: nil) + dismiss(animated: true, completion: nil) - UIApplication.sharedApplication().sendAction("maximizeView:", to: nil, from: self, forEvent: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView(_:)), to: nil, from: self, for: nil) } - @IBAction func closeButtonPressed(sender: AnyObject) { - dismissViewControllerAnimated(true, completion: nil) + @IBAction func closeButtonPressed(_ sender: AnyObject) { + dismiss(animated: true, completion: nil) - UIApplication.sharedApplication().sendAction("maximizeView:", to: nil, from: self, forEvent: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.maximizeView(_:)), to: nil, from: self, for: nil) } - override func viewDidAppear(animated: Bool) { + override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(true) - UIApplication.sharedApplication().sendAction("minimizeView:", to: nil, from: self, forEvent: nil) + UIApplication.shared.sendAction(#selector(SpringViewController.minimizeView(_:)), to: nil, from: self, for: nil) modalView.animate() } - func getString(name: String, value: CGFloat) -> String { + func getString(_ name: String, value: CGFloat) -> String { return String(format: "\(name): %.1f", Double(value)) } } diff --git a/SpringApp/SpringViewController.swift b/SpringApp/SpringViewController.swift index e38d8bd..6a4ea1b 100644 --- a/SpringApp/SpringViewController.swift +++ b/SpringApp/SpringViewController.swift @@ -34,49 +34,49 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView var selectedY: CGFloat = 0 var selectedRotate: CGFloat = 0 - @IBAction func forceSliderChanged(sender: AnyObject) { - selectedForce = sender.valueForKey("value") as CGFloat + @IBAction func forceSliderChanged(_ sender: AnyObject) { + selectedForce = sender.value(forKey: "value") as! CGFloat animateView() forceLabel.text = String(format: "Force: %.1f", Double(selectedForce)) } - @IBAction func durationSliderChanged(sender: AnyObject) { - selectedDuration = sender.valueForKey("value") as CGFloat + @IBAction func durationSliderChanged(_ sender: AnyObject) { + selectedDuration = sender.value(forKey: "value") as! CGFloat animateView() durationLabel.text = String(format: "Duration: %.1f", Double(selectedDuration)) } - @IBAction func delaySliderChanged(sender: AnyObject) { - selectedDelay = sender.valueForKey("value") as CGFloat + @IBAction func delaySliderChanged(_ sender: AnyObject) { + selectedDelay = sender.value(forKey: "value") as! CGFloat animateView() delayLabel.text = String(format: "Delay: %.1f", Double(selectedDelay)) } - func dampingSliderChanged(sender: AnyObject) { - selectedDamping = sender.valueForKey("value") as CGFloat + func dampingSliderChanged(_ sender: AnyObject) { + selectedDamping = sender.value(forKey: "value") as! CGFloat animateView() } - func velocitySliderChanged(sender: AnyObject) { - selectedVelocity = sender.valueForKey("value") as CGFloat + func velocitySliderChanged(_ sender: AnyObject) { + selectedVelocity = sender.value(forKey: "value") as! CGFloat animateView() } - func scaleSliderChanged(sender: AnyObject) { - selectedScale = sender.valueForKey("value") as CGFloat + func scaleSliderChanged(_ sender: AnyObject) { + selectedScale = sender.value(forKey: "value") as! CGFloat animateView() } - func xSliderChanged(sender: AnyObject) { - selectedX = sender.valueForKey("value") as CGFloat + func xSliderChanged(_ sender: AnyObject) { + selectedX = sender.value(forKey: "value") as! CGFloat animateView() } - func ySliderChanged(sender: AnyObject) { - selectedY = sender.valueForKey("value") as CGFloat + func ySliderChanged(_ sender: AnyObject) { + selectedY = sender.value(forKey: "value") as! CGFloat animateView() } - func rotateSliderChanged(sender: AnyObject) { - selectedRotate = sender.valueForKey("value") as CGFloat + func rotateSliderChanged(_ sender: AnyObject) { + selectedRotate = sender.value(forKey: "value") as! CGFloat animateView() } @@ -98,52 +98,84 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView ballView.y = selectedY ballView.rotate = selectedRotate - ballView.animation = data[0][selectedRow] - ballView.curve = data[1][selectedEasing] + ballView.animation = animations[selectedRow].rawValue + ballView.curve = animationCurves[selectedEasing].rawValue } - func minimizeView(sender: AnyObject) { - spring(0.7, { - self.view.transform = CGAffineTransformMakeScale(0.935, 0.935) + @objc func minimizeView(_ sender: AnyObject) { + SpringAnimation.spring(duration: 0.7, animations: { + self.view.transform = CGAffineTransform(scaleX: 0.935, y: 0.935) }) - UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.LightContent, animated: true) + UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.lightContent, animated: true) } - func maximizeView(sender: AnyObject) { - spring(0.7, { - self.view.transform = CGAffineTransformMakeScale(1, 1) + @objc func maximizeView(_ sender: AnyObject) { + SpringAnimation.spring(duration: 0.7, animations: { + self.view.transform = CGAffineTransform(scaleX: 1, y: 1) }) - UIApplication.sharedApplication().setStatusBarStyle(UIStatusBarStyle.Default, animated: true) - } - - var data = [[ - "shake", - "pop", - "morph", - "squeeze", - "wobble", - "swing", - "flipX", - "flipY", - "fall", - "squeezeLeft", - "squeezeRight", - "squeezeDown", - "squeezeUp", - "slideLeft", - "slideRight", - "slideDown", - "slideUp", - "fadeIn", - "fadeOut", - "fadeInLeft", - "fadeInRight", - "fadeInDown", - "fadeInUp", - "zoomIn", - "zoomOut", - "flash", - ], ["spring", "linear", "easeIn", "easeOut", "easeInOut","easeInSine","easeOutSine","easeInOutSine","easeInQuad","easeOutQuad","easeInOutQuad","easeInCubic","easeOutCubic","easeInOutCubic","easeInQuart","easeOutQuart","easeInOutQuart","easeInQuint","easeOutQuint","easeInOutQuint","easeInExpo","easeOutExpo","easeInOutExpo","easeInCirc","easeOutCirc","easeInOutCirc","easeInBack","easeOutBack","easeInOutBack"]] + UIApplication.shared.setStatusBarStyle(UIStatusBarStyle.default, animated: true) + } + + let animations: [Spring.AnimationPreset] = [ + .Shake, + .Pop, + .Morph, + .Squeeze, + .Wobble, + .Swing, + .FlipX, + .FlipY, + .Fall, + .SqueezeLeft, + .SqueezeRight, + .SqueezeDown, + .SqueezeUp, + .SlideLeft, + .SlideRight, + .SlideDown, + .SlideUp, + .FadeIn, + .FadeOut, + .FadeInLeft, + .FadeInRight, + .FadeInDown, + .FadeInUp, + .ZoomIn, + .ZoomOut, + .Flash + ] + + var animationCurves: [Spring.AnimationCurve] = [ + .EaseIn, + .EaseOut, + .EaseInOut, + .Linear, + .Spring, + .EaseInSine, + .EaseOutSine, + .EaseInOutSine, + .EaseInQuad, + .EaseOutQuad, + .EaseInOutQuad, + .EaseInCubic, + .EaseOutCubic, + .EaseInOutCubic, + .EaseInQuart, + .EaseOutQuart, + .EaseInOutQuart, + .EaseInQuint, + .EaseOutQuint, + .EaseInOutQuint, + .EaseInExpo, + .EaseOutExpo, + .EaseInOutExpo, + .EaseInCirc, + .EaseOutCirc, + .EaseInOutCirc, + .EaseInBack, + .EaseOutBack, + .EaseInOutBack + ] override func viewDidLoad() { super.viewDidLoad() @@ -153,12 +185,12 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView animationPicker.showsSelectionIndicator = true } - @IBAction func ballButtonPressed(sender: AnyObject) { + @IBAction func ballButtonPressed(_ sender: AnyObject) { - UIView.animateWithDuration(0.1, animations: { + UIView.animate(withDuration: 0.1, animations: { self.ballView.backgroundColor = UIColor(hex: "69DBFF") }, completion: { finished in - UIView.animateWithDuration(0.5, animations: { + UIView.animate(withDuration: 0.5, animations: { self.ballView.backgroundColor = UIColor(hex: "#279CEB") }) }) @@ -177,14 +209,14 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView animation.toValue = cornerRadius animation.duration = 0.2 ballView.layer.cornerRadius = cornerRadius - ballView.layer.addAnimation(animation, forKey: "radius") + ballView.layer.add(animation, forKey: "radius") } - @IBAction func shapeButtonPressed(sender: AnyObject) { + @IBAction func shapeButtonPressed(_ sender: AnyObject) { changeBall() } - func resetButtonPressed(sender: AnyObject) { + func resetButtonPressed(_ sender: AnyObject) { selectedForce = 1 selectedDuration = 1 selectedDelay = 0 @@ -205,19 +237,19 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView delayLabel.text = String(format: "Delay: %.1f", Double(selectedDelay)) } - func numberOfComponentsInPickerView(pickerView: UIPickerView) -> Int { + func numberOfComponents(in pickerView: UIPickerView) -> Int { return 2 } - func pickerView(pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { - return data[component].count + func pickerView(_ pickerView: UIPickerView, numberOfRowsInComponent component: Int) -> Int { + return component == 0 ? animations.count : animationCurves.count } - func pickerView(pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String! { - return data[component][row] + func pickerView(_ pickerView: UIPickerView, titleForRow row: Int, forComponent component: Int) -> String? { + return component == 0 ? animations[row].rawValue : animationCurves[row].rawValue } - func pickerView(pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { + func pickerView(_ pickerView: UIPickerView, didSelectRow row: Int, inComponent component: Int) { switch component { case 0: selectedRow = row @@ -228,15 +260,15 @@ class SpringViewController: UIViewController, UIPickerViewDelegate, UIPickerView } } - override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) { - if let optionsViewController = segue.destinationViewController as? OptionsViewController { + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if let optionsViewController = segue.destination as? OptionsViewController { optionsViewController.delegate = self setOptions() optionsViewController.data = ballView } - else if let codeViewController = segue.destinationViewController as? CodeViewController { + else if let codeViewController = segue.destination as? CodeViewController { setOptions() codeViewController.data = ballView } } -} \ No newline at end of file +} diff --git a/SpringAppTests/Info.plist b/SpringAppTests/Info.plist index b1fb88b..ba72822 100644 --- a/SpringAppTests/Info.plist +++ b/SpringAppTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - designcode.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/SpringAppTests/SpringAppTests.swift b/SpringAppTests/SpringAppTests.swift index 2f0113b..ac2484b 100644 --- a/SpringAppTests/SpringAppTests.swift +++ b/SpringAppTests/SpringAppTests.swift @@ -28,7 +28,7 @@ class SpringAppTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock() { + self.measure() { // Put the code you want to measure the time of here. } } diff --git a/SpringTests/Info.plist b/SpringTests/Info.plist index 609467f..ba72822 100644 --- a/SpringTests/Info.plist +++ b/SpringTests/Info.plist @@ -7,7 +7,7 @@ CFBundleExecutable $(EXECUTABLE_NAME) CFBundleIdentifier - com.jamztang.$(PRODUCT_NAME:rfc1034identifier) + $(PRODUCT_BUNDLE_IDENTIFIER) CFBundleInfoDictionaryVersion 6.0 CFBundleName diff --git a/SpringTests/SpringTests.swift b/SpringTests/SpringTests.swift index 105bf23..938737d 100644 --- a/SpringTests/SpringTests.swift +++ b/SpringTests/SpringTests.swift @@ -28,7 +28,7 @@ class SpringTests: XCTestCase { func testPerformanceExample() { // This is an example of a performance test case. - self.measureBlock() { + self.measure() { // Put the code you want to measure the time of here. } }