diff --git a/Source/SpinerAnimationType.swift b/Source/SpinerAnimationType.swift new file mode 100644 index 0000000..861b0aa --- /dev/null +++ b/Source/SpinerAnimationType.swift @@ -0,0 +1,155 @@ +// +// SpinerAnimationType.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +// swiftlint:disable:next class_delegate_protocol +protocol TransitionButtonAnimationDelegate { + + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) +} + +/** +Enum of animation types used for spiner animation. + +- DefaultSpinner: LineSpinFadeLoader animation. +- BallRotate: BallRotate animation. +- BallPulse: BallPulse animation. +- AudioEqualizer: AudioEqualizer animation. +- BallClipRotate: BallClipRotate animation. +- BallScale: BallScale animation. +*/ +public enum SpinerAnimationType: Int, CaseIterable { + + /** + DefaultSpinner. + + - returns: Instance of DefaultSpinner. + */ + case defaultSpinner = 0 + /** + BallRotate. + + - returns: Instance of SpinerBallRotate. + */ + case ballRotate = 1 + /** + BallPulse. + + - returns: Instance of SpinerBallPulse. + */ + case ballPulse = 2 + /** + AudioEqualizer. + + - returns: Instance of SpinerAudioEqualizer. + */ + case audioEqualizer = 3 + /** + BallClipRotate. + + - returns: Instance of SpinerBallClipRotate. + */ + case ballClipRotate = 4 + /** + BallScale. + + - returns: Instance of SpinerBallScale. + */ + case ballScale = 5 + + + // swiftlint:disable:next cyclomatic_complexity function_body_length + func animation() -> TransitionButtonAnimationDelegate { + switch self { + case .defaultSpinner: + return DefaultSpinner() + case .ballRotate: + return SpinerBallRotate() + case .ballPulse: + return SpinerBallPulse() + case .audioEqualizer: + return SpinerAudioEqualizer() + case .ballClipRotate: + return SpinerBallClipRotate() + case .ballScale: + return SpinerBallScale() + } + } +} + +enum TransitionButtonAnimationShape { + case circle + case ringTwoHalfVertical + case ringTwoHalfHorizontal + case line + + // swiftlint:disable:next cyclomatic_complexity function_body_length + func layerWith(size: CGSize, color: UIColor) -> CALayer { + let layer: CAShapeLayer = CAShapeLayer() + var path: UIBezierPath = UIBezierPath() + let lineWidth: CGFloat = 2 + + switch self { + case .circle: + path.addArc(withCenter: CGPoint(x: size.width / 2, y: size.height / 2), + radius: size.width / 2, + startAngle: 0, + endAngle: CGFloat(2 * Double.pi), + clockwise: false) + layer.fillColor = color.cgColor + case .ringTwoHalfVertical: + path.addArc(withCenter: CGPoint(x: size.width / 2, y: size.height / 2), + radius: size.width / 2, + startAngle: CGFloat(-3 * Double.pi / 4), + endAngle: CGFloat(-Double.pi / 4), + clockwise: true) + path.move( + to: CGPoint(x: size.width / 2 - size.width / 2 * cos(CGFloat(Double.pi / 4)), + y: size.height / 2 + size.height / 2 * sin(CGFloat(Double.pi / 4))) + ) + path.addArc(withCenter: CGPoint(x: size.width / 2, y: size.height / 2), + radius: size.width / 2, + startAngle: CGFloat(-5 * Double.pi / 4), + endAngle: CGFloat(-7 * Double.pi / 4), + clockwise: false) + layer.fillColor = nil + layer.strokeColor = color.cgColor + layer.lineWidth = lineWidth + case .ringTwoHalfHorizontal: + path.addArc(withCenter: CGPoint(x: size.width / 2, y: size.height / 2), + radius: size.width / 2, + startAngle: CGFloat(3 * Double.pi / 4), + endAngle: CGFloat(5 * Double.pi / 4), + clockwise: true) + path.move( + to: CGPoint(x: size.width / 2 + size.width / 2 * cos(CGFloat(Double.pi / 4)), + y: size.height / 2 - size.height / 2 * sin(CGFloat(Double.pi / 4))) + ) + path.addArc(withCenter: CGPoint(x: size.width / 2, y: size.height / 2), + radius: size.width / 2, + startAngle: CGFloat(-Double.pi / 4), + endAngle: CGFloat(Double.pi / 4), + clockwise: true) + layer.fillColor = nil + layer.strokeColor = color.cgColor + layer.lineWidth = lineWidth + case .line: + path = UIBezierPath(roundedRect: CGRect(x: 0, y: 0, width: size.width, height: size.height), + cornerRadius: size.width / 2) + layer.fillColor = color.cgColor + } + + layer.backgroundColor = nil + layer.path = path.cgPath + layer.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) + + return layer + } +} diff --git a/Source/SpinerLayer.swift b/Source/SpinerLayer.swift index b804b3e..5d586e4 100755 --- a/Source/SpinerLayer.swift +++ b/Source/SpinerLayer.swift @@ -11,6 +11,9 @@ import UIKit class SpinerLayer: CAShapeLayer { + /// Animation type. + public var type: SpinerAnimationType = .defaultSpinner + var spinnerColor = UIColor.white { didSet { strokeColor = spinnerColor.cgColor @@ -38,34 +41,29 @@ class SpinerLayer: CAShapeLayer { super.init(layer: layer) } - + func animation() { self.isHidden = false - let rotate = CABasicAnimation(keyPath: "transform.rotation.z") - rotate.fromValue = 0 - rotate.toValue = Double.pi * 2 - rotate.duration = 0.4 - rotate.timingFunction = CAMediaTimingFunction(name: .linear) - - rotate.repeatCount = HUGE - rotate.fillMode = .forwards - rotate.isRemovedOnCompletion = false - self.add(rotate, forKey: rotate.keyPath) - + let animation: TransitionButtonAnimationDelegate = type.animation() + animation.setupSpinnerAnimation(in: self, frame: frame, color: spinnerColor, spinnerSize: nil) } func setToFrame(_ frame: CGRect) { - let radius:CGFloat = (frame.height / 2) * 0.5 self.frame = CGRect(x: 0, y: 0, width: frame.height, height: frame.height) - let center = CGPoint(x: frame.height / 2, y: bounds.center.y) - let startAngle = 0 - Double.pi/2 - let endAngle = Double.pi * 2 - Double.pi/2 - let clockwise: Bool = true - self.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: clockwise).cgPath } func stopAnimation() { self.isHidden = true self.removeAllAnimations() + removeAnimationLayer() + } + + private func removeAnimationLayer() { + if self.sublayers != nil { + for item in self.sublayers! { + item.removeAllAnimations() + item.removeFromSuperlayer() + } + } } } diff --git a/Source/Spiners/DefaultSpinner.swift b/Source/Spiners/DefaultSpinner.swift new file mode 100644 index 0000000..bdf7495 --- /dev/null +++ b/Source/Spiners/DefaultSpinner.swift @@ -0,0 +1,46 @@ +// +// DefaultSpinner.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +class DefaultSpinner: TransitionButtonAnimationDelegate { + + /// setup spinner layer + /// + /// - Parameters: + /// - layer: layer Parent layer (Button layer) + /// - frame: frame of parant layer + /// - color: color of spinner + /// - spinnerSize: size of spinner layer + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) { + + self.setToFrame(frame, layer: layer) + + let rotate = CABasicAnimation(keyPath: "transform.rotation.z") + rotate.fromValue = 0 + rotate.toValue = Double.pi * 2 + rotate.duration = 0.4 + rotate.timingFunction = CAMediaTimingFunction(name: .linear) + + rotate.repeatCount = HUGE + rotate.fillMode = .forwards + rotate.isRemovedOnCompletion = false + layer.add(rotate, forKey: rotate.keyPath) + } + + func setToFrame(_ frame: CGRect, layer: CAShapeLayer) { + let radius:CGFloat = (frame.height / 2) * 0.5 + layer.frame = CGRect(x: 0, y: 0, width: frame.height, height: frame.height) + let center = CGPoint(x: frame.height / 2, y: layer.bounds.center.y) + let startAngle = 0 - Double.pi/2 + let endAngle = Double.pi * 2 - Double.pi/2 + let clockwise: Bool = true + layer.path = UIBezierPath(arcCenter: center, radius: radius, startAngle: CGFloat(startAngle), endAngle: CGFloat(endAngle), clockwise: clockwise).cgPath + } +} diff --git a/Source/Spiners/SpinerAudioEqualizer.swift b/Source/Spiners/SpinerAudioEqualizer.swift new file mode 100644 index 0000000..0628424 --- /dev/null +++ b/Source/Spiners/SpinerAudioEqualizer.swift @@ -0,0 +1,52 @@ +// +// SpinerAudioEqualizer.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +class SpinerAudioEqualizer: TransitionButtonAnimationDelegate { + + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) { + let lineSize = frame.width / 12 + let x = (layer.bounds.width - lineSize * 7) / 2 + let y = (layer.bounds.height - frame.height) / 2 + let duration: [CFTimeInterval] = [4.3, 2.5, 1.7, 3.1] + let values = [0, 0.7, 0.4, 0.05, 0.95, 0.3, 0.9, 0.4, 0.15, 0.18, 0.75, 0.01] + + // Draw lines + for i in 0 ..< 4 { + let animation = CAKeyframeAnimation() + + animation.keyPath = "path" + animation.isAdditive = true + animation.values = [] + + for j in 0 ..< values.count { + let heightFactor = values[j] + let height = frame.height * CGFloat(heightFactor) + let point = CGPoint(x: 0, y: frame.height - height) + let path = UIBezierPath(rect: CGRect(origin: point, size: CGSize(width: lineSize, height: height - 20))) + + animation.values?.append(path.cgPath) + } + animation.duration = duration[i] + animation.repeatCount = HUGE + animation.isRemovedOnCompletion = false + + let line = TransitionButtonAnimationShape.line.layerWith(size: CGSize(width: lineSize, height: frame.height), color: color) + let frame = CGRect(x: x + lineSize * 2 * CGFloat(i), + y: y, + width: lineSize, + height: frame.height) + + line.frame = frame + line.add(animation, forKey: "animation") + layer.addSublayer(line) + } + } +} diff --git a/Source/Spiners/SpinerBallClipRotate.swift b/Source/Spiners/SpinerBallClipRotate.swift new file mode 100644 index 0000000..1ee67fe --- /dev/null +++ b/Source/Spiners/SpinerBallClipRotate.swift @@ -0,0 +1,83 @@ +// +// SpinerBallClipRotate.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +class SpinerBallClipRotate: TransitionButtonAnimationDelegate { + + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) { + let bigCircleSize: CGFloat = frame.width / 1.4 + let smallCircleSize: CGFloat = frame.width / 2.5 + let longDuration: CFTimeInterval = 1 + #if swift(>=4.2) + let timingFunction = CAMediaTimingFunction(name: .easeInEaseOut) + #else + let timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut) + #endif + + circleOf(shape: .ringTwoHalfHorizontal, + duration: longDuration, + timingFunction: timingFunction, + layer: layer, + size: bigCircleSize, + color: color, reverse: false) + circleOf(shape: .ringTwoHalfVertical, + duration: longDuration, + timingFunction: timingFunction, + layer: layer, + size: smallCircleSize, + color: color, reverse: true) + } + + func createAnimationIn(duration: CFTimeInterval, timingFunction: CAMediaTimingFunction, reverse: Bool) -> CAAnimation { + // Scale animation + let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale") + + scaleAnimation.keyTimes = [0, 0.5, 1] + scaleAnimation.timingFunctions = [timingFunction, timingFunction] + scaleAnimation.values = [1, 0.6, 1] + scaleAnimation.duration = duration + + // Rotate animation + let rotateAnimation = CAKeyframeAnimation(keyPath: "transform.rotation.z") + + rotateAnimation.keyTimes = scaleAnimation.keyTimes + rotateAnimation.timingFunctions = [timingFunction, timingFunction] + if !reverse { + rotateAnimation.values = [0, Double.pi, 2 * Double.pi] + } else { + rotateAnimation.values = [0, -Double.pi, -2 * Double.pi] + } + rotateAnimation.duration = duration + + // Animation + let animation = CAAnimationGroup() + + animation.animations = [scaleAnimation, rotateAnimation] + animation.duration = duration + animation.repeatCount = HUGE + animation.isRemovedOnCompletion = false + + return animation + } + + // swiftlint:disable:next function_parameter_count + func circleOf(shape: TransitionButtonAnimationShape, duration: CFTimeInterval, timingFunction: CAMediaTimingFunction, layer: CALayer, size: CGFloat, color: UIColor, reverse: Bool) { + let circle = shape.layerWith(size: CGSize(width: size, height: size), color: color) + let frame = CGRect(x: (layer.bounds.size.width - size) / 2, + y: (layer.bounds.size.height - size) / 2, + width: size, + height: size) + let animation = createAnimationIn(duration: duration, timingFunction: timingFunction, reverse: reverse) + + circle.frame = frame + circle.add(animation, forKey: "animation") + layer.addSublayer(circle) + } +} diff --git a/Source/Spiners/SpinerBallPulse.swift b/Source/Spiners/SpinerBallPulse.swift new file mode 100644 index 0000000..6f0628d --- /dev/null +++ b/Source/Spiners/SpinerBallPulse.swift @@ -0,0 +1,47 @@ +// +// SpinerBallPulse.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +class SpinerBallPulse: TransitionButtonAnimationDelegate { + + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) { + let circleSpacing: CGFloat = 2 + let circleSize: CGFloat = (frame.width - 2 * circleSpacing) / 5 + let x: CGFloat = (frame.width / 2) - (circleSize * 1.7) + let y: CGFloat = (layer.bounds.height - circleSize) / 2 + let duration: CFTimeInterval = 0.75 + let beginTime = CACurrentMediaTime() + let beginTimes: [CFTimeInterval] = [0.12, 0.24, 0.36] + let timingFunction = CAMediaTimingFunction(controlPoints: 0.2, 0.68, 0.18, 1.08) + let animation = CAKeyframeAnimation(keyPath: "transform.scale") + + // Animation + animation.keyTimes = [0, 0.3, 1] + animation.timingFunctions = [timingFunction, timingFunction] + animation.values = [1, 0.3, 1] + animation.duration = duration + animation.repeatCount = HUGE + animation.isRemovedOnCompletion = false + + // Draw circles + for i in 0 ..< 3 { + let circle = TransitionButtonAnimationShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) + let frame = CGRect(x: x + circleSize * CGFloat(i) + circleSpacing * CGFloat(i), + y: y, + width: circleSize, + height: circleSize) + + animation.beginTime = beginTime + beginTimes[i] + circle.frame = frame + circle.add(animation, forKey: "animation") + layer.addSublayer(circle) + } + } +} diff --git a/Source/Spiners/SpinerBallRotate.swift b/Source/Spiners/SpinerBallRotate.swift new file mode 100644 index 0000000..79dc463 --- /dev/null +++ b/Source/Spiners/SpinerBallRotate.swift @@ -0,0 +1,83 @@ +// +// SpinerBallRotate.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +class SpinerBallRotate: TransitionButtonAnimationDelegate { + + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) { + + var defaultPadding: CGFloat = 10.0 + var sizeofSpinner: CGFloat? + if spinnerSize != nil { + defaultPadding = 0.0 + sizeofSpinner = max(CGFloat(spinnerSize!) - defaultPadding, 1.0) + } + var size = max(min(frame.width, frame.height) - defaultPadding, 1.0) + if sizeofSpinner != nil && sizeofSpinner! > (size - defaultPadding) { + defaultPadding = 10.0 + size = max(min(frame.width, frame.height) - defaultPadding, 1.0) + sizeofSpinner = size + } + + let center = CGPoint(x: (size/2) + (defaultPadding / 2), y: (size / 2) + (defaultPadding / 2)) + let circleSize = sizeofSpinner != nil ? max(min(sizeofSpinner! / 6, size / 6), 1.0) : size / 6 + + for i in 0 ..< 5 { + let factor = Float(i) * 1 / 5 + let circle = TransitionButtonAnimationShape.circle.layerWith(size: CGSize(width: circleSize, height: circleSize), color: color) + let animation = rotateAnimation(factor, x: center.x, y: center.y, size: CGSize(width: (sizeofSpinner != nil ? sizeofSpinner! : size) - circleSize, height: (sizeofSpinner != nil ? sizeofSpinner! : size) - circleSize)) + + circle.frame = CGRect(x: 0, y: 0, width: circleSize, height: circleSize) + circle.add(animation, forKey: "animation") + layer.addSublayer(circle) + } + + } + + + /// Rotate animation + /// + /// - Parameters: + /// - rate: rate of rotation + /// - x: X value of center + /// - y: Y value of center + /// - size: size of spinner + /// - Returns: Rotate Animation group + func rotateAnimation(_ rate: Float, x: CGFloat, y: CGFloat, size: CGSize) -> CAAnimationGroup { + let duration: CFTimeInterval = 1.5 + let fromScale = 1 - rate + let toScale = 0.2 + rate + let timeFunc = CAMediaTimingFunction(controlPoints: 0.5, 0.15 + rate, 0.25, 1) + + // Scale animation + let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") + scaleAnimation.duration = duration + scaleAnimation.repeatCount = HUGE + scaleAnimation.fromValue = fromScale + scaleAnimation.toValue = toScale + + // Position animation + let positionAnimation = CAKeyframeAnimation(keyPath: "position") + positionAnimation.duration = duration + positionAnimation.repeatCount = HUGE + positionAnimation.path = UIBezierPath(arcCenter: CGPoint(x: x, y: y), radius: size.width / 2, startAngle: CGFloat(3 * Double.pi * 0.5), endAngle: CGFloat(3 * Double.pi * 0.5 + 2 * Double.pi), clockwise: true).cgPath + + // Aniamtion + let animation = CAAnimationGroup() + animation.animations = [scaleAnimation, positionAnimation] + animation.timingFunction = timeFunc + animation.duration = duration + animation.repeatCount = HUGE + animation.isRemovedOnCompletion = false + + return animation + } + +} diff --git a/Source/Spiners/SpinerBallScale.swift b/Source/Spiners/SpinerBallScale.swift new file mode 100644 index 0000000..17f7f95 --- /dev/null +++ b/Source/Spiners/SpinerBallScale.swift @@ -0,0 +1,62 @@ +// +// SpinerBallScale.swift +// TransitionButton +// +// Created by Rahul Mayani on 11/09/20. +// Copyright © 2020 ITechnoDev. All rights reserved. +// + +import Foundation +import UIKit + +class SpinerBallScale: TransitionButtonAnimationDelegate { + + func setupSpinnerAnimation(in layer: CAShapeLayer, frame: CGRect, color: UIColor, spinnerSize: UInt?) { + let duration: CFTimeInterval = 1 + let beginTime = CACurrentMediaTime() + let beginTimes = [0, 0.2, 0.4] + + // Scale animation + let scaleAnimation = CABasicAnimation(keyPath: "transform.scale") + + scaleAnimation.duration = duration + scaleAnimation.fromValue = 0 + scaleAnimation.toValue = 0.8 + + // Opacity animation + let opacityAnimation = CAKeyframeAnimation(keyPath: "opacity") + + opacityAnimation.duration = duration + opacityAnimation.keyTimes = [0, 0.05, 1] + opacityAnimation.values = [0, 1, 0] + + // Animation + let animation = CAAnimationGroup() + + animation.animations = [scaleAnimation, opacityAnimation] + #if swift(>=4.2) + animation.timingFunction = CAMediaTimingFunction(name: .linear) + #else + animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear) + #endif + animation.duration = duration + animation.repeatCount = HUGE + animation.isRemovedOnCompletion = false + + // Draw balls + for i in 0 ..< 3 { + + let circle = TransitionButtonAnimationShape.circle.layerWith(size: CGSize(width: frame.width, height: frame.height), color: color) + let frame = CGRect(x: (layer.bounds.width - frame.width) / 2, + y: (layer.bounds.height - frame.height) / 2, + width: frame.width, + height: frame.height) + + animation.beginTime = beginTime + beginTimes[i] + circle.frame = frame + circle.opacity = 0 + circle.add(animation, forKey: "animation") + layer.addSublayer(circle) + } + } +} diff --git a/Source/TransitionButton.swift b/Source/TransitionButton.swift index bd5e171..f49856e 100755 --- a/Source/TransitionButton.swift +++ b/Source/TransitionButton.swift @@ -36,6 +36,13 @@ public enum StopAnimationStyle { } } + /// the type of the spinner while animating the button + @IBInspectable open var spinnerType: Int = 0 { + didSet { + spiner.type = SpinerAnimationType(rawValue: spinnerType) ?? .defaultSpinner + } + } + /// the background of the button in disabled state @IBInspectable open var disabledBackgroundColor: UIColor = UIColor.lightGray { didSet { diff --git a/TransitionButton.xcodeproj/project.pbxproj b/TransitionButton.xcodeproj/project.pbxproj index 710998f..8c701ca 100755 --- a/TransitionButton.xcodeproj/project.pbxproj +++ b/TransitionButton.xcodeproj/project.pbxproj @@ -14,6 +14,13 @@ 7AF5064C1F2D086E00631DA4 /* TransitionButton.swift in Sources */ = {isa = PBXBuildFile; fileRef = 7AF506461F2D086E00631DA4 /* TransitionButton.swift */; }; D93F1CA21EAEDB6E009A7474 /* TransitionButton.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = D93F1C981EAEDB6E009A7474 /* TransitionButton.framework */; }; D93F1CA71EAEDB6E009A7474 /* TransitionButtonTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = D93F1CA61EAEDB6E009A7474 /* TransitionButtonTests.swift */; }; + EEA70A0B250B3E0B0095D11A /* SpinerBallRotate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A0A250B3E0B0095D11A /* SpinerBallRotate.swift */; }; + EEA70A0D250B42110095D11A /* SpinerAnimationType.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A0C250B42110095D11A /* SpinerAnimationType.swift */; }; + EEA70A0F250B503D0095D11A /* DefaultSpinner.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A0E250B503D0095D11A /* DefaultSpinner.swift */; }; + EEA70A11250B53FA0095D11A /* SpinerBallPulse.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A10250B53FA0095D11A /* SpinerBallPulse.swift */; }; + EEA70A13250B5B3A0095D11A /* SpinerAudioEqualizer.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A12250B5B3A0095D11A /* SpinerAudioEqualizer.swift */; }; + EEA70A15250B6A1E0095D11A /* SpinerBallClipRotate.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A14250B6A1E0095D11A /* SpinerBallClipRotate.swift */; }; + EEA70A17250B6B5F0095D11A /* SpinerBallScale.swift in Sources */ = {isa = PBXBuildFile; fileRef = EEA70A16250B6B5F0095D11A /* SpinerBallScale.swift */; }; /* End PBXBuildFile section */ /* Begin PBXContainerItemProxy section */ @@ -37,6 +44,13 @@ D93F1CA11EAEDB6E009A7474 /* TransitionButtonTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = TransitionButtonTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; D93F1CA61EAEDB6E009A7474 /* TransitionButtonTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TransitionButtonTests.swift; sourceTree = ""; }; D93F1CA81EAEDB6E009A7474 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + EEA70A0A250B3E0B0095D11A /* SpinerBallRotate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinerBallRotate.swift; sourceTree = ""; }; + EEA70A0C250B42110095D11A /* SpinerAnimationType.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinerAnimationType.swift; sourceTree = ""; }; + EEA70A0E250B503D0095D11A /* DefaultSpinner.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = DefaultSpinner.swift; sourceTree = ""; }; + EEA70A10250B53FA0095D11A /* SpinerBallPulse.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinerBallPulse.swift; sourceTree = ""; }; + EEA70A12250B5B3A0095D11A /* SpinerAudioEqualizer.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinerAudioEqualizer.swift; sourceTree = ""; }; + EEA70A14250B6A1E0095D11A /* SpinerBallClipRotate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinerBallClipRotate.swift; sourceTree = ""; }; + EEA70A16250B6B5F0095D11A /* SpinerBallScale.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SpinerBallScale.swift; sourceTree = ""; }; /* End PBXFileReference section */ /* Begin PBXFrameworksBuildPhase section */ @@ -80,10 +94,12 @@ D93F1C9A1EAEDB6E009A7474 /* Source */ = { isa = PBXGroup; children = ( + EEA70A09250B3DEB0095D11A /* Spiners */, 7AF506411F2D086E00631DA4 /* CGRectExtension.swift */, 7AF506421F2D086E00631DA4 /* CustomTransitionViewController.swift */, 7AF506431F2D086E00631DA4 /* FadeTransition.swift */, 7AF506451F2D086E00631DA4 /* SpinerLayer.swift */, + EEA70A0C250B42110095D11A /* SpinerAnimationType.swift */, 7AF506461F2D086E00631DA4 /* TransitionButton.swift */, D93F1C9C1EAEDB6E009A7474 /* Info.plist */, ); @@ -106,6 +122,19 @@ name = Resources; sourceTree = ""; }; + EEA70A09250B3DEB0095D11A /* Spiners */ = { + isa = PBXGroup; + children = ( + EEA70A0E250B503D0095D11A /* DefaultSpinner.swift */, + EEA70A0A250B3E0B0095D11A /* SpinerBallRotate.swift */, + EEA70A10250B53FA0095D11A /* SpinerBallPulse.swift */, + EEA70A12250B5B3A0095D11A /* SpinerAudioEqualizer.swift */, + EEA70A14250B6A1E0095D11A /* SpinerBallClipRotate.swift */, + EEA70A16250B6B5F0095D11A /* SpinerBallScale.swift */, + ); + path = Spiners; + sourceTree = ""; + }; /* End PBXGroup section */ /* Begin PBXHeadersBuildPhase section */ @@ -218,10 +247,17 @@ isa = PBXSourcesBuildPhase; buildActionMask = 2147483647; files = ( + EEA70A13250B5B3A0095D11A /* SpinerAudioEqualizer.swift in Sources */, 7AF5064C1F2D086E00631DA4 /* TransitionButton.swift in Sources */, 7AF506481F2D086E00631DA4 /* CustomTransitionViewController.swift in Sources */, + EEA70A11250B53FA0095D11A /* SpinerBallPulse.swift in Sources */, + EEA70A17250B6B5F0095D11A /* SpinerBallScale.swift in Sources */, 7AF506491F2D086E00631DA4 /* FadeTransition.swift in Sources */, + EEA70A0F250B503D0095D11A /* DefaultSpinner.swift in Sources */, 7AF5064B1F2D086E00631DA4 /* SpinerLayer.swift in Sources */, + EEA70A15250B6A1E0095D11A /* SpinerBallClipRotate.swift in Sources */, + EEA70A0B250B3E0B0095D11A /* SpinerBallRotate.swift in Sources */, + EEA70A0D250B42110095D11A /* SpinerAnimationType.swift in Sources */, 7AF506471F2D086E00631DA4 /* CGRectExtension.swift in Sources */, ); runOnlyForDeploymentPostprocessing = 0; diff --git a/iOS Example/Source/Main.storyboard b/iOS Example/Source/Main.storyboard index 9070e18..365f06c 100644 --- a/iOS Example/Source/Main.storyboard +++ b/iOS Example/Source/Main.storyboard @@ -1,11 +1,9 @@ - - - - + + - + @@ -45,6 +43,9 @@ + + +