diff --git a/Example/ViewController.swift b/Example/ViewController.swift index b8a85e4..d07d231 100644 --- a/Example/ViewController.swift +++ b/Example/ViewController.swift @@ -64,3 +64,15 @@ class ViewController: UIViewController { } } +class AnimatableDoneView2: UIView, HasAnimatablePath { + let animatableLayer = CAShapeLayer() + var animatablePath: UIBezierPath { + let length = frame.width + let path = UIBezierPath() + path.move(to: CGPoint(x: length * 0.196, y: length * 0.527)) + path.addLine(to: CGPoint(x: length * 0.47, y: length * 0.777)) + path.addLine(to: CGPoint(x: length * 0.99, y: length * 0.25)) + return path + } +} + diff --git a/NativePopup.xcodeproj/project.pbxproj b/NativePopup.xcodeproj/project.pbxproj index b2752e9..9dae418 100644 --- a/NativePopup.xcodeproj/project.pbxproj +++ b/NativePopup.xcodeproj/project.pbxproj @@ -8,14 +8,13 @@ /* Begin PBXBuildFile section */ FE4CECF61ED1171400D5DB31 /* AnimatableCrossView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4CECF51ED1171400D5DB31 /* AnimatableCrossView.swift */; }; - FE4CECF81ED119F800D5DB31 /* HasAnimatablePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = FE4CECF71ED119F800D5DB31 /* HasAnimatablePath.swift */; }; FE8533901EAC7C92004BB756 /* NativePopup.h in Headers */ = {isa = PBXBuildFile; fileRef = FE85338E1EAC7C92004BB756 /* NativePopup.h */; settings = {ATTRIBUTES = (Public, ); }; }; FEB0316D1ECFF6770039A1C6 /* Preset.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB0316C1ECFF6770039A1C6 /* Preset.swift */; }; FEB031711ECFF6A30039A1C6 /* Bundle.extension.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB031701ECFF6A30039A1C6 /* Bundle.extension.swift */; }; FEB031731ECFF6E00039A1C6 /* InitialEffectType.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB031721ECFF6E00039A1C6 /* InitialEffectType.swift */; }; FEB031751ECFFB6C0039A1C6 /* Animatable.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB031741ECFFB6C0039A1C6 /* Animatable.swift */; }; FEB031771ECFFE120039A1C6 /* AnimatableDoneView.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB031761ECFFE120039A1C6 /* AnimatableDoneView.swift */; }; - FEB031791ED014D70039A1C6 /* HasAnimatableLayer.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB031781ED014D70039A1C6 /* HasAnimatableLayer.swift */; }; + FEB031791ED014D70039A1C6 /* HasAnimatablePath.swift in Sources */ = {isa = PBXBuildFile; fileRef = FEB031781ED014D70039A1C6 /* HasAnimatablePath.swift */; }; FECA87BA1EAC7CCF00D07CB1 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = FECA87B91EAC7CCF00D07CB1 /* AppDelegate.swift */; }; FECA87BC1EAC7CCF00D07CB1 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = FECA87BB1EAC7CCF00D07CB1 /* ViewController.swift */; }; FECA87BF1EAC7CCF00D07CB1 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = FECA87BD1EAC7CCF00D07CB1 /* Main.storyboard */; }; @@ -57,7 +56,6 @@ /* Begin PBXFileReference section */ FE4CECF51ED1171400D5DB31 /* AnimatableCrossView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatableCrossView.swift; sourceTree = ""; }; - FE4CECF71ED119F800D5DB31 /* HasAnimatablePath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HasAnimatablePath.swift; sourceTree = ""; }; FE85338B1EAC7C92004BB756 /* NativePopup.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = NativePopup.framework; sourceTree = BUILT_PRODUCTS_DIR; }; FE85338E1EAC7C92004BB756 /* NativePopup.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = NativePopup.h; sourceTree = ""; }; FE85338F1EAC7C92004BB756 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; @@ -66,7 +64,7 @@ FEB031721ECFF6E00039A1C6 /* InitialEffectType.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = InitialEffectType.swift; sourceTree = ""; }; FEB031741ECFFB6C0039A1C6 /* Animatable.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animatable.swift; sourceTree = ""; }; FEB031761ECFFE120039A1C6 /* AnimatableDoneView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimatableDoneView.swift; sourceTree = ""; }; - FEB031781ED014D70039A1C6 /* HasAnimatableLayer.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HasAnimatableLayer.swift; sourceTree = ""; }; + FEB031781ED014D70039A1C6 /* HasAnimatablePath.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = HasAnimatablePath.swift; sourceTree = ""; }; FECA87B71EAC7CCF00D07CB1 /* Example.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = Example.app; sourceTree = BUILT_PRODUCTS_DIR; }; FECA87B91EAC7CCF00D07CB1 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; FECA87BB1EAC7CCF00D07CB1 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; @@ -105,8 +103,7 @@ isa = PBXGroup; children = ( FEB031741ECFFB6C0039A1C6 /* Animatable.swift */, - FEB031781ED014D70039A1C6 /* HasAnimatableLayer.swift */, - FE4CECF71ED119F800D5DB31 /* HasAnimatablePath.swift */, + FEB031781ED014D70039A1C6 /* HasAnimatablePath.swift */, FE4CECF51ED1171400D5DB31 /* AnimatableCrossView.swift */, FEB031761ECFFE120039A1C6 /* AnimatableDoneView.swift */, ); @@ -293,10 +290,9 @@ FEB031711ECFF6A30039A1C6 /* Bundle.extension.swift in Sources */, FEB031731ECFF6E00039A1C6 /* InitialEffectType.swift in Sources */, FEB031771ECFFE120039A1C6 /* AnimatableDoneView.swift in Sources */, - FEB031791ED014D70039A1C6 /* HasAnimatableLayer.swift in Sources */, + FEB031791ED014D70039A1C6 /* HasAnimatablePath.swift in Sources */, FEB031751ECFFB6C0039A1C6 /* Animatable.swift in Sources */, FECA87E31EACC7F000D07CB1 /* UIImageConvertible.swift in Sources */, - FE4CECF81ED119F800D5DB31 /* HasAnimatablePath.swift in Sources */, FECA87F21EADBA3C00D07CB1 /* Extension.swift in Sources */, FECA87D81EAC7D9E00D07CB1 /* NativePopup.swift in Sources */, FEB0316D1ECFF6770039A1C6 /* Preset.swift in Sources */, diff --git a/NativePopup/Animatable/Animatable.swift b/NativePopup/Animatable/Animatable.swift index 0c8b781..a7b3629 100644 --- a/NativePopup/Animatable/Animatable.swift +++ b/NativePopup/Animatable/Animatable.swift @@ -8,11 +8,10 @@ import Foundation -protocol Animatable { +public protocol Animatable { func animate() - var duration: TimeInterval { get } } -extension Animatable { +public extension Animatable { var duration: TimeInterval { return 0.3 } } diff --git a/NativePopup/Animatable/AnimatableCrossView.swift b/NativePopup/Animatable/AnimatableCrossView.swift index dc8585d..15ee8d7 100644 --- a/NativePopup/Animatable/AnimatableCrossView.swift +++ b/NativePopup/Animatable/AnimatableCrossView.swift @@ -8,9 +8,10 @@ import Foundation -class AnimatableCrossView: AnimatablePathView { +class AnimatableCrossView: UIView, HasAnimatablePath { + let animatableLayer = CAShapeLayer() var duration: TimeInterval { return 0.4 } - override var animatablePath: UIBezierPath { + var animatablePath: UIBezierPath { let length = frame.width let path = UIBezierPath() path.move(to: CGPoint(x: length * 0.1, y: length * 0.1)) diff --git a/NativePopup/Animatable/AnimatableDoneView.swift b/NativePopup/Animatable/AnimatableDoneView.swift index 1f5ee32..5428aee 100644 --- a/NativePopup/Animatable/AnimatableDoneView.swift +++ b/NativePopup/Animatable/AnimatableDoneView.swift @@ -8,8 +8,9 @@ import Foundation -class AnimatableDoneView: AnimatablePathView { - override var animatablePath: UIBezierPath { +class AnimatableDoneView: UIView, HasAnimatablePath { + let animatableLayer = CAShapeLayer() + var animatablePath: UIBezierPath { let length = frame.width let path = UIBezierPath() path.move(to: CGPoint(x: length * 0.196, y: length * 0.527)) diff --git a/NativePopup/Animatable/HasAnimatableLayer.swift b/NativePopup/Animatable/HasAnimatableLayer.swift deleted file mode 100644 index a676dbe..0000000 --- a/NativePopup/Animatable/HasAnimatableLayer.swift +++ /dev/null @@ -1,25 +0,0 @@ -// -// HasAnimatableLayer.swift -// NativePopup -// -// Created by mono on 2017/05/20. -// Copyright © 2017 mono. All rights reserved. -// - -import Foundation - -protocol HasAnimatableLayer: Animatable { - var animatableLayer: CAShapeLayer { get } -} - -extension HasAnimatableLayer { - func animate() { - let animation = CABasicAnimation(keyPath: "strokeEnd") - animation.duration = duration - animation.fromValue = 0 - animation.toValue = 1 - animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) - animatableLayer.strokeEnd = 1 - animatableLayer.add(animation, forKey: "animation") - } -} diff --git a/NativePopup/Animatable/HasAnimatablePath.swift b/NativePopup/Animatable/HasAnimatablePath.swift index 36e2440..8b67fdb 100644 --- a/NativePopup/Animatable/HasAnimatablePath.swift +++ b/NativePopup/Animatable/HasAnimatablePath.swift @@ -1,24 +1,38 @@ // -// HasAnimatablePath.swift +// HasAnimatableLayer.swift // NativePopup // -// Created by mono on 2017/05/21. +// Created by mono on 2017/05/20. // Copyright © 2017 mono. All rights reserved. // import Foundation -open class AnimatablePathView: UIView, HasAnimatableLayer { - let animatableLayer = CAShapeLayer() - open var animatablePath: UIBezierPath { fatalError("Should be overridden.") } - func setupLayer() { +public protocol HasAnimatablePath: Animatable { + var layer: CALayer { get } + var tintColor: UIColor! { get } + /** Should return same instance */ + var animatableLayer: CAShapeLayer { get } + var animatablePath: UIBezierPath { get } +} + +public extension HasAnimatablePath { + public func animate() { + let animation = CABasicAnimation(keyPath: "strokeEnd") + animation.duration = duration + animation.fromValue = 0 + animation.toValue = 1 + animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) + animatableLayer.strokeEnd = 1 + animatableLayer.add(animation, forKey: "animation") + } + public func configureAnimatableLayer() { animatableLayer.path = animatablePath.cgPath animatableLayer.fillColor = UIColor.clear.cgColor - animatableLayer.strokeColor = tintColor.cgColor + animatableLayer.strokeColor = tintColor?.cgColor animatableLayer.lineWidth = 9 animatableLayer.lineCap = kCALineCapRound animatableLayer.lineJoin = kCALineCapRound animatableLayer.strokeEnd = 0 - layer.addSublayer(animatableLayer) } } diff --git a/NativePopup/NativePopup.swift b/NativePopup/NativePopup.swift index 1a3ad92..ff491d8 100644 --- a/NativePopup/NativePopup.swift +++ b/NativePopup/NativePopup.swift @@ -110,9 +110,10 @@ public class NativePopup: UIView { [self, effectView, imageView, titleLabel, messageLabel].forEach { $0.translatesAutoresizingMaskIntoConstraints = false } - if let animatable = imageView as? AnimatablePathView { + if let animatable = imageView as? HasAnimatablePath { imageView.layoutIfNeeded() - animatable.setupLayer() + animatable.configureAnimatableLayer() + animatable.layer.addSublayer(animatable.animatableLayer) } }