diff --git a/Example2/StarWars/Circular/AnimationDelegate.swift b/Example2/StarWars/Circular/AnimationDelegate.swift new file mode 100755 index 0000000..edbfeca --- /dev/null +++ b/Example2/StarWars/Circular/AnimationDelegate.swift @@ -0,0 +1,19 @@ +// +// Copyright © 2014 Yalantis +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// + +import UIKit + +open class AnimationDelegate: NSObject, CAAnimationDelegate { + + fileprivate let completion: () -> Void + + public init(completion: @escaping () -> Void) { + self.completion = completion + } + + public func animationDidStop(_: CAAnimation, finished: Bool) { + completion() + } +} diff --git a/Example2/StarWars/Circular/CircularRevealAnimator.swift b/Example2/StarWars/Circular/CircularRevealAnimator.swift new file mode 100755 index 0000000..17c0bce --- /dev/null +++ b/Example2/StarWars/Circular/CircularRevealAnimator.swift @@ -0,0 +1,68 @@ +// +// Copyright © 2014 Yalantis +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// + +import QuartzCore + +private func SquareAroundCircle(_ center: CGPoint, radius: CGFloat) -> CGRect { + assert(0 <= radius, "radius must be a positive value") + return CGRect(origin: center, size: CGSize.zero).insetBy(dx: -radius, dy: -radius) +} + +open class CircularRevealAnimator { + + public var completion: (() -> Void)? + + fileprivate let layer: CALayer + fileprivate let mask: CAShapeLayer + fileprivate let animation: CABasicAnimation + + public var duration: CFTimeInterval { + get { return animation.duration } + set(value) { animation.duration = value } + } + + public var timingFunction: CAMediaTimingFunction! { + get { return animation.timingFunction } + set(value) { animation.timingFunction = value } + } + + public init(layer: CALayer, center: CGPoint, startRadius: CGFloat, endRadius: CGFloat, invert: Bool = false) { + let startCirclePath = CGPath(ellipseIn: SquareAroundCircle(center, radius: startRadius), transform: nil) + let endCirclePath = CGPath(ellipseIn: SquareAroundCircle(center, radius: endRadius), transform: nil) + + var startPath = startCirclePath, endPath = endCirclePath + if invert { + var path = CGMutablePath() + path.addRect(layer.bounds) + path.addPath(startCirclePath) + startPath = path + path = CGMutablePath() + path.addRect(layer.bounds) + path.addPath(endCirclePath) + endPath = path + } + + self.layer = layer + + mask = CAShapeLayer() + mask.path = endPath + mask.fillRule = kCAFillRuleEvenOdd + + animation = CABasicAnimation(keyPath: "path") + animation.fromValue = startPath + animation.toValue = endPath + animation.delegate = AnimationDelegate { + layer.mask = nil + self.completion?() + self.animation.delegate = nil + } + } + + public func start() { + layer.mask = mask + mask.frame = layer.bounds + mask.add(animation, forKey: "reveal") + } +} diff --git a/Example2/StarWars/Circular/UIView+CircularAnimation.swift b/Example2/StarWars/Circular/UIView+CircularAnimation.swift new file mode 100755 index 0000000..15d7590 --- /dev/null +++ b/Example2/StarWars/Circular/UIView+CircularAnimation.swift @@ -0,0 +1,38 @@ +// +// UIView+CircularAnimation.swift +// StarWarsAnimations +// +// Created by Artem Sidorenko on 10/5/15. +// Copyright © 2015 Yalantis. All rights reserved. +// + +import UIKit + +extension UIView { + + open func animateCircular(withDuration duration: TimeInterval, center: CGPoint, revert: Bool = false, animations: () -> Void, completion: ((Bool) -> Void)? = nil) { + let snapshot = snapshotView(afterScreenUpdates: false)! + snapshot.frame = bounds + self.addSubview(snapshot) + + let center = convert(center, to: snapshot) + let radius: CGFloat = { + let x = frame.width + let y = frame.height + return sqrt(x * x + y * y) + }() + var animation : CircularRevealAnimator + if !revert { + animation = CircularRevealAnimator(layer: snapshot.layer, center: center, startRadius: 0, endRadius: radius, invert: true) + } else { + animation = CircularRevealAnimator(layer: snapshot.layer, center: center, startRadius: radius, endRadius: 0, invert: false) + } + animation.duration = duration + animation.completion = { + snapshot.removeFromSuperview() + completion?(true) + } + animation.start() + animations() + } +} diff --git a/Example2/StarWars/Info.plist b/Example2/StarWars/Info.plist new file mode 100644 index 0000000..fbe1e6b --- /dev/null +++ b/Example2/StarWars/Info.plist @@ -0,0 +1,24 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + FMWK + CFBundleShortVersionString + 1.0 + CFBundleVersion + $(CURRENT_PROJECT_VERSION) + NSPrincipalClass + + + diff --git a/Example2/StarWars/StarWars.h b/Example2/StarWars/StarWars.h new file mode 100644 index 0000000..0fbc650 --- /dev/null +++ b/Example2/StarWars/StarWars.h @@ -0,0 +1,19 @@ +// +// StarWars.h +// StarWars +// +// Created by Isabel Lee on 02/05/2017. +// Copyright © 2017 isabeljlee. All rights reserved. +// + +#import + +//! Project version number for StarWars. +FOUNDATION_EXPORT double StarWarsVersionNumber; + +//! Project version string for StarWars. +FOUNDATION_EXPORT const unsigned char StarWarsVersionString[]; + +// In this header, you should import all the public headers of your framework using statements like #import + + diff --git a/Example2/StarWars/StarWarsGLAnimator/Sprite.swift b/Example2/StarWars/StarWarsGLAnimator/Sprite.swift new file mode 100755 index 0000000..cc42d4b --- /dev/null +++ b/Example2/StarWars/StarWarsGLAnimator/Sprite.swift @@ -0,0 +1,60 @@ +// +// Created by Artem Sidorenko on 10/8/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import GLKit + +struct TexturedVertex { + var geometryVertex = Vector2() + var textureVertex = Vector2() +} + +struct TexturedQuad { + var bl = TexturedVertex() + var br = TexturedVertex() { didSet { _br = br } } + var tl = TexturedVertex() { didSet { _tl = tl } } + var tr = TexturedVertex() + + // openGL optimization. it uses triangles to draw. + // so we duplicate 2 vertex, so it have 6 vertex to draw two triangles + fileprivate var _br = TexturedVertex() + fileprivate var _tl = TexturedVertex() +} + +struct Sprite { + var quad = TexturedQuad() + var moveVelocity = Vector2() + + mutating func slice(_ rect: CGRect, textureSize: CGSize) { + quad.bl.geometryVertex = Vector2(x: 0, y: 0) + quad.br.geometryVertex = Vector2(x: rect.size.width, y: 0) + quad.tl.geometryVertex = Vector2(x: 0, y: rect.size.height) + quad.tr.geometryVertex = Vector2(x: rect.size.width, y: rect.size.height) + + quad.bl.textureVertex = Vector2(x: rect.origin.x / textureSize.width, y: rect.origin.y / textureSize.height) + quad.br.textureVertex = Vector2(x: (rect.origin.x + rect.size.width) / textureSize.width, y: rect.origin.y / textureSize.height) + quad.tl.textureVertex = Vector2(x: rect.origin.x / textureSize.width, y: (rect.origin.y + rect.size.height) / textureSize.height) + quad.tr.textureVertex = Vector2(x: (rect.origin.x + rect.size.width) / textureSize.width, y: (rect.origin.y + rect.size.height) / textureSize.height) + + position += Vector2(rect.origin) + } + + var position = Vector2() { + didSet { + let diff = position - oldValue + quad.bl.geometryVertex += diff + quad.br.geometryVertex += diff + quad.tl.geometryVertex += diff + quad.tr.geometryVertex += diff + } + } + + mutating func update(_ tick: TimeInterval) { + position += moveVelocity * Float32(tick) + } + +} diff --git a/Example2/StarWars/StarWarsGLAnimator/SpriteRender.swift b/Example2/StarWars/StarWarsGLAnimator/SpriteRender.swift new file mode 100755 index 0000000..9dc5fc1 --- /dev/null +++ b/Example2/StarWars/StarWarsGLAnimator/SpriteRender.swift @@ -0,0 +1,41 @@ +// +// Created by Artem Sidorenko on 10/8/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import GLKit + +class SpriteRender { + + fileprivate let texture: ViewTexture + fileprivate let effect: GLKBaseEffect + + init(texture: ViewTexture, effect: GLKBaseEffect) { + self.texture = texture + self.effect = effect + } + + func render(_ sprites: [Sprite]) { + effect.texture2d0.name = self.texture.name + effect.texture2d0.enabled = 1 + + effect.prepareToDraw() + + var vertex = sprites.map { $0.quad } + + glEnableVertexAttribArray(GLuint(GLKVertexAttrib.position.rawValue)) + glEnableVertexAttribArray(GLuint(GLKVertexAttrib.texCoord0.rawValue)) + + withUnsafePointer(to: &vertex[0].bl.geometryVertex) { offset in + glVertexAttribPointer(GLuint(GLKVertexAttrib.position.rawValue), 2, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(MemoryLayout.size), offset) + } + withUnsafePointer(to: &vertex[0].bl.textureVertex) { offset in + glVertexAttribPointer(GLuint(GLKVertexAttrib.texCoord0.rawValue), 2, GLenum(GL_FLOAT), GLboolean(UInt8(GL_FALSE)), GLsizei(MemoryLayout.size), offset) + } + + glDrawArrays(GLenum(GL_TRIANGLES), 0, GLsizei(vertex.count * 6)) + } +} diff --git a/Example2/StarWars/StarWarsGLAnimator/StarWarsGLAnimator.swift b/Example2/StarWars/StarWarsGLAnimator/StarWarsGLAnimator.swift new file mode 100755 index 0000000..9229b6a --- /dev/null +++ b/Example2/StarWars/StarWarsGLAnimator/StarWarsGLAnimator.swift @@ -0,0 +1,121 @@ +// +// Created by Artem Sidorenko on 9/14/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import UIKit +import GLKit + +open class StarWarsGLAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + open var duration: TimeInterval = 2 + open var spriteWidth: CGFloat = 8 + + fileprivate var sprites: [Sprite] = [] + fileprivate var glContext: EAGLContext! + fileprivate var effect: GLKBaseEffect! + fileprivate var glView: GLKView! + fileprivate var displayLink: CADisplayLink! + fileprivate var lastUpdateTime: TimeInterval? + fileprivate var startTransitionTime: TimeInterval! + fileprivate var transitionContext: UIViewControllerContextTransitioning! + fileprivate var render: SpriteRender! + + open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return duration + } + + open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let containerView = transitionContext.containerView + let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view + let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view + + containerView.addSubview(toView!) + containerView.sendSubview(toBack: toView!) + + func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> Float { + let diff = bigNumber - smallNumber + return Float((CGFloat(arc4random()) / 100.0).truncatingRemainder(dividingBy: diff) + smallNumber) + } + + self.glContext = EAGLContext(api: .openGLES2) + EAGLContext.setCurrent(glContext) + + glView = GLKView(frame: (fromView?.frame)!, context: glContext) + glView.enableSetNeedsDisplay = true + glView.delegate = self + glView.isOpaque = false + containerView.addSubview(glView) + + let texture = ViewTexture() + texture.setupOpenGL() + texture.render(view: fromView!) + + effect = GLKBaseEffect() + let projectionMatrix = GLKMatrix4MakeOrtho(0, Float(texture.width), 0, Float(texture.height), -1, 1) + effect.transform.projectionMatrix = projectionMatrix + + render = SpriteRender(texture: texture, effect: effect) + + let size = CGSize(width: CGFloat(texture.width), height: CGFloat(texture.height)) + + let scale = UIScreen.main.scale + let width = spriteWidth * scale + let height = width + + for x in stride(from: CGFloat(0), through: size.width, by: width) { + for y in stride(from: CGFloat(0), through: size.height, by: height) { + let region = CGRect(x: x, y: y, width: width, height: height) + var sprite = Sprite() + sprite.slice(region, textureSize: size) + sprite.moveVelocity = Vector2(x: randomFloatBetween(-100, and: 100), y: randomFloatBetween(-CGFloat(texture.height)*1.3/CGFloat(duration), and: -CGFloat(texture.height)/CGFloat(duration))) + + sprites.append(sprite) + } + } + fromView?.removeFromSuperview() + self.transitionContext = transitionContext + + displayLink = CADisplayLink(target: self, selector: #selector(StarWarsGLAnimator.displayLinkTick(_:))) + displayLink.isPaused = false + displayLink.add(to: RunLoop.main, forMode: RunLoopMode.commonModes) + + self.startTransitionTime = Date.timeIntervalSinceReferenceDate + } + + open func animationEnded(_ transitionCompleted: Bool) { + displayLink.invalidate() + displayLink = nil + } + + func displayLinkTick(_ displayLink: CADisplayLink) { + if let lastUpdateTime = lastUpdateTime { + let timeSinceLastUpdate = Date.timeIntervalSinceReferenceDate - lastUpdateTime + self.lastUpdateTime = Date.timeIntervalSinceReferenceDate + for index in 0.. duration { + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } + } +} + +extension StarWarsGLAnimator: GLKViewDelegate { + + public func glkView(_ view: GLKView, drawIn rect: CGRect) { + glClearColor(0, 0, 0, 0) + glClear(UInt32(GL_COLOR_BUFFER_BIT)) + glBlendFunc(GLenum(GL_SRC_ALPHA), GLenum(GL_ONE_MINUS_SRC_ALPHA)) + glEnable(GLenum(GL_BLEND)) + + render.render(self.sprites) + } +} diff --git a/Example2/StarWars/StarWarsGLAnimator/Vector2.swift b/Example2/StarWars/StarWarsGLAnimator/Vector2.swift new file mode 100755 index 0000000..8d6627c --- /dev/null +++ b/Example2/StarWars/StarWarsGLAnimator/Vector2.swift @@ -0,0 +1,168 @@ +// +// Created by Artem Sidorenko on 10/9/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import UIKit + +struct Vector2 { + + var x : Float32 = 0.0 + var y : Float32 = 0.0 + + init() { + + x = 0.0 + y = 0.0 + } + + init(value: Float32) { + + x = value + y = value + } + + init(x: Float32 ,y: Float32) { + + self.x = x + self.y = y + } + + init(x: CGFloat, y: CGFloat) { + self.init(x: Float32(x), y: Float32(y)) + } + + init(x: Int, y: Int) { + self.init(x: Float32(x), y: Float32(y)) + } + + init(other: Vector2) { + + x = other.x + y = other.y + } + + init(_ other: CGPoint) { + x = Float32(other.x) + y = Float32(other.y) + } +} + +extension Vector2: CustomStringConvertible { + + var description: String { return "[\(x),\(y)]" } +} + +extension Vector2 : Equatable { + + func isFinite() -> Bool { + + return x.isFinite && y.isFinite + } + + func distance(_ other: Vector2) -> Float32 { + + let result = self - other; + return sqrt( result.dot(result) ) + } + + mutating func normalize() { + + let m = magnitude() + + if m > 0 { + + let il:Float32 = 1.0 / m + + x *= il + y *= il + } + } + + func magnitude() -> Float32 { + + return sqrtf( x*x + y*y ) + } + + func dot( _ v: Vector2 ) -> Float32 { + + return x * v.x + y * v.y + } + + mutating func lerp( _ a: Vector2, b: Vector2, coef : Float32) { + + let result = a + ( b - a) * coef + + x = result.x + y = result.y + } +} + +func ==(lhs: Vector2, rhs: Vector2) -> Bool { + + return (lhs.x == rhs.x) && (lhs.y == rhs.y) +} + +func * (left: Vector2, right : Float32) -> Vector2 { + + return Vector2(x:left.x * right, y:left.y * right) +} + +func * (left: Vector2, right : Vector2) -> Vector2 { + + return Vector2(x:left.x * right.x, y:left.y * right.y) +} + +func / (left: Vector2, right : Float32) -> Vector2 { + + return Vector2(x:left.x / right, y:left.y / right) +} + +func / (left: Vector2, right : Vector2) -> Vector2 { + + return Vector2(x:left.x / right.x, y:left.y / right.y) +} + +func + (left: Vector2, right: Vector2) -> Vector2 { + + return Vector2(x:left.x + right.x, y:left.y + right.y) +} + +func - (left: Vector2, right: Vector2) -> Vector2 { + + return Vector2(x:left.x - right.x, y:left.y - right.y) +} + +func + (left: Vector2, right: Float32) -> Vector2 { + + return Vector2(x:left.x + right, y:left.y + right) +} + +func - (left: Vector2, right: Float32) -> Vector2 { + + return Vector2(x:left.x - right, y:left.y - right) +} + +func += (left: inout Vector2, right: Vector2) { + + left = left + right +} + +func -= (left: inout Vector2, right: Vector2) { + + left = left - right +} + +func *= (left: inout Vector2, right: Vector2) { + + left = left * right +} + +func /= (left: inout Vector2, right: Vector2) { + + left = left / right +} + diff --git a/Example2/StarWars/StarWarsGLAnimator/ViewTexture.swift b/Example2/StarWars/StarWarsGLAnimator/ViewTexture.swift new file mode 100755 index 0000000..934615b --- /dev/null +++ b/Example2/StarWars/StarWarsGLAnimator/ViewTexture.swift @@ -0,0 +1,58 @@ +// +// Created by Artem Sidorenko on 10/9/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import UIKit + +class ViewTexture { + var name: GLuint = 0 + var width: GLsizei = 0 + var height: GLsizei = 0 + + func setupOpenGL() { + glGenTextures(1, &name) + glBindTexture(GLenum(GL_TEXTURE_2D), name) + + glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MIN_FILTER), GLint(GL_LINEAR)) + glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_MAG_FILTER), GLint(GL_LINEAR)) + + glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_S), GLint(GL_CLAMP_TO_EDGE)) + glTexParameteri(GLenum(GL_TEXTURE_2D), GLenum(GL_TEXTURE_WRAP_T), GLint(GL_CLAMP_TO_EDGE)) + glBindTexture(GLenum(GL_TEXTURE_2D), 0); + } + + deinit { + if name != 0 { + glDeleteTextures(1, &name) + } + } + + func render(view: UIView) { + let scale = UIScreen.main.scale + width = GLsizei(view.layer.bounds.size.width * scale) + height = GLsizei(view.layer.bounds.size.height * scale) + + var texturePixelBuffer = [GLubyte](repeating: 0, count: Int(height * width * 4)) + let colorSpace = CGColorSpaceCreateDeviceRGB() + + withUnsafeMutablePointer(to: &texturePixelBuffer[0]) { texturePixelBuffer in + let context = CGContext(data: texturePixelBuffer, + width: Int(width), height: Int(height), bitsPerComponent: 8, bytesPerRow: Int(width * 4), space: colorSpace, + bitmapInfo: CGImageAlphaInfo.premultipliedLast.rawValue | CGBitmapInfo.byteOrder32Big.rawValue)! + context.scaleBy(x: scale, y: scale) + + UIGraphicsPushContext(context) + view.drawHierarchy(in: view.layer.bounds, afterScreenUpdates: false) + UIGraphicsPopContext() + + glBindTexture(GLenum(GL_TEXTURE_2D), name); + + glTexImage2D(GLenum(GL_TEXTURE_2D), 0, GLint(GL_RGBA), width, height, 0, GLenum(GL_RGBA), GLenum(GL_UNSIGNED_BYTE), texturePixelBuffer) + glBindTexture(GLenum(GL_TEXTURE_2D), 0); + } + } +} diff --git a/Example2/StarWars/StarWarsUIDynamicAnimator/StarWarsUIDynamicAnimator.swift b/Example2/StarWars/StarWarsUIDynamicAnimator/StarWarsUIDynamicAnimator.swift new file mode 100755 index 0000000..3b1586d --- /dev/null +++ b/Example2/StarWars/StarWarsUIDynamicAnimator/StarWarsUIDynamicAnimator.swift @@ -0,0 +1,78 @@ +// +// Created by Artem Sidorenko on 9/11/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import UIKit + +open class StarWarsUIDynamicAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + open var duration: TimeInterval = 2 + open var spriteWidth: CGFloat = 20 + + var transitionContext: UIViewControllerContextTransitioning! + + open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return duration + } + + var animator: UIDynamicAnimator! + + open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let containerView = transitionContext.containerView + let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view + let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view + + containerView.addSubview(toView!) + containerView.sendSubview(toBack: toView!) + + let size = fromView!.frame.size + + func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> CGFloat { + let diff = bigNumber - smallNumber + return (CGFloat(arc4random()) / 100.0).truncatingRemainder(dividingBy: diff) + smallNumber + } + + // snapshot the from view, this makes subsequent snaphots more performant + let fromViewSnapshot = fromView?.snapshotView(afterScreenUpdates: false) + + let width = spriteWidth + let height = width + + animator = UIDynamicAnimator(referenceView: containerView) + + var snapshots: [UIView] = [] + for x in stride(from: CGFloat(0), through: size.width, by: width) { + for y in stride(from: CGFloat(0), through: size.height, by: height) { + let snapshotRegion = CGRect(x: x, y: y, width: width, height: height) + + let snapshot = fromViewSnapshot!.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: false, withCapInsets: .zero)! + + containerView.addSubview(snapshot) + snapshot.frame = snapshotRegion + snapshots.append(snapshot) + + let push = UIPushBehavior(items: [snapshot], mode: .instantaneous) + push.pushDirection = CGVector(dx: randomFloatBetween(-0.15 , and: 0.15), dy: randomFloatBetween(-0.15 , and: 0)) + push.active = true + animator.addBehavior(push) + } + } + let gravity = UIGravityBehavior(items: snapshots) + animator.addBehavior(gravity) + + print(snapshots.count) + + fromView?.removeFromSuperview() + + Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(StarWarsUIDynamicAnimator.completeTransition), userInfo: nil, repeats: false) + self.transitionContext = transitionContext + } + + func completeTransition() { + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } +} diff --git a/Example2/StarWars/StarWarsUIViewAnimator/StarWarsUIViewAnimator.swift b/Example2/StarWars/StarWarsUIViewAnimator/StarWarsUIViewAnimator.swift new file mode 100755 index 0000000..0bd3e1e --- /dev/null +++ b/Example2/StarWars/StarWarsUIViewAnimator/StarWarsUIViewAnimator.swift @@ -0,0 +1,77 @@ +// +// Created by Artem Sidorenko on 9/11/15. +// Copyright © 2015 Yalantis. All rights reserved. +// +// Licensed under the MIT license: http://opensource.org/licenses/MIT +// Latest version can be found at https://github.com/Yalantis/StarWars.iOS +// + +import UIKit + +open class StarWarsUIViewAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + open var duration: TimeInterval = 2 + open var spriteWidth: CGFloat = 10 + + open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return duration + } + + open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let containerView = transitionContext.containerView + let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view + let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view + + containerView.addSubview(toView!) + containerView.sendSubview(toBack: toView!) + + var snapshots:[UIView] = [] + let size = fromView?.frame.size + + func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> CGFloat { + let diff = bigNumber - smallNumber + return (CGFloat(arc4random()) / 100.0).truncatingRemainder(dividingBy: diff) + smallNumber + } + + // snapshot the from view, this makes subsequent snaphots more performant + let fromViewSnapshot = fromView?.snapshotView(afterScreenUpdates: false) + + let width = spriteWidth + let height = width + + for x in stride(from: CGFloat(0), through: (size?.width)!, by: width) { + for y in stride(from: CGFloat(0), through: (size?.height)!, by: height) { + + let snapshotRegion = CGRect(x: x, y: y, width: width, height: height) + + let snapshot = fromViewSnapshot!.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: false, withCapInsets: UIEdgeInsets.zero) + + containerView.addSubview(snapshot!) + snapshot!.frame = snapshotRegion + snapshots.append(snapshot!) + } + } + + containerView.sendSubview(toBack: fromView!) + + UIView.animate( + withDuration: + duration, + delay: 0, + options: UIViewAnimationOptions.curveLinear, + animations: { + for view in snapshots { + let xOffset = randomFloatBetween(-200 , and: 200) + let yOffset = randomFloatBetween(fromView!.frame.height, and: fromView!.frame.height * 1.3) + view.frame = view.frame.offsetBy(dx: xOffset, dy: yOffset) + } + }, + completion: { _ in + for view in snapshots { + view.removeFromSuperview() + } + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } + ) + } +} diff --git a/Example2/StarWars/StarWarsWindAnimator.swift b/Example2/StarWars/StarWarsWindAnimator.swift new file mode 100644 index 0000000..28bd703 --- /dev/null +++ b/Example2/StarWars/StarWarsWindAnimator.swift @@ -0,0 +1,85 @@ +// +// StarWarsWindAnimator.swift +// case_Studies +// +// Created by Isabel Lee on 03/05/2017. +// Copyright © 2017 isabeljlee. All rights reserved. +// + +import UIKit + +open class StarWarsWindAnimator: NSObject, UIViewControllerAnimatedTransitioning { + + open var duration: TimeInterval = 2 + open var spriteWidth: CGFloat = 20 + open var wind: CGFloat = 3 + open var float: CGFloat = 0.1 + var transitionContext: UIViewControllerContextTransitioning! + + open func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval { + return duration + } + + var animator: UIDynamicAnimator! + + open func animateTransition(using transitionContext: UIViewControllerContextTransitioning) { + let containerView = transitionContext.containerView + let fromView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.from)!.view + let toView = transitionContext.viewController(forKey: UITransitionContextViewControllerKey.to)!.view + + containerView.addSubview(toView!) + containerView.sendSubview(toBack: toView!) + + let size = fromView!.frame.size + + func randomFloatBetween(_ smallNumber: CGFloat, and bigNumber: CGFloat) -> CGFloat { + let diff = bigNumber - smallNumber + return (CGFloat(arc4random()) / 100.0).truncatingRemainder(dividingBy: diff) + smallNumber + } + + // snapshot the from view, this makes subsequent snaphots more performant + let fromViewSnapshot = fromView?.snapshotView(afterScreenUpdates: false) + + let width = spriteWidth + let height = width + + animator = UIDynamicAnimator(referenceView: containerView) + + var snapshots: [UIView] = [] + for x in stride(from: CGFloat(0), through: size.width, by: width) { + for y in stride(from: CGFloat(0), through: size.height, by: height) { + let snapshotRegion = CGRect(x: x, y: y, width: width, height: height) + + let snapshot = fromViewSnapshot!.resizableSnapshotView(from: snapshotRegion, afterScreenUpdates: false, withCapInsets: .zero)! + + containerView.addSubview(snapshot) + snapshot.frame = snapshotRegion + snapshots.append(snapshot) + + let push = UIPushBehavior(items: [snapshot], mode: .instantaneous) + push.pushDirection = CGVector(dx: randomFloatBetween(-0.15 , and: 0.15), dy: randomFloatBetween(-0.15 , and: 0)) + push.active = true + animator.addBehavior(push) + } + } + + let windPush = UIPushBehavior(items: snapshots, mode: .instantaneous) + windPush.pushDirection = CGVector(dx: wind, dy: -float) + windPush.active = true + self.animator.addBehavior(windPush) + + let gravity = UIGravityBehavior(items: snapshots) + animator.addBehavior(gravity) + + print(snapshots.count) + + fromView?.removeFromSuperview() + + Timer.scheduledTimer(timeInterval: duration, target: self, selector: #selector(StarWarsUIDynamicAnimator.completeTransition), userInfo: nil, repeats: false) + self.transitionContext = transitionContext + } + + func completeTransition() { + transitionContext.completeTransition(!transitionContext.transitionWasCancelled) + } +} diff --git a/Example2/case_Studies.xcodeproj/project.pbxproj b/Example2/case_Studies.xcodeproj/project.pbxproj new file mode 100644 index 0000000..d20b576 --- /dev/null +++ b/Example2/case_Studies.xcodeproj/project.pbxproj @@ -0,0 +1,559 @@ +// !$*UTF8*$! +{ + archiveVersion = 1; + classes = { + }; + objectVersion = 46; + objects = { + +/* Begin PBXBuildFile section */ + 0E76171D1EB946A300E1C37C /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E76171C1EB946A300E1C37C /* AppDelegate.swift */; }; + 0E76171F1EB946A300E1C37C /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E76171E1EB946A300E1C37C /* ViewController.swift */; }; + 0E7617221EB946A300E1C37C /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E7617201EB946A300E1C37C /* Main.storyboard */; }; + 0E7617241EB946A300E1C37C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0E7617231EB946A300E1C37C /* Assets.xcassets */; }; + 0E7617271EB946A300E1C37C /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0E7617251EB946A300E1C37C /* LaunchScreen.storyboard */; }; + 0E7617491EB947AE00E1C37C /* StarWars.h in Headers */ = {isa = PBXBuildFile; fileRef = 0E7617471EB947AE00E1C37C /* StarWars.h */; settings = {ATTRIBUTES = (Public, ); }; }; + 0E76174C1EB947AE00E1C37C /* StarWars.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7617451EB947AE00E1C37C /* StarWars.framework */; }; + 0E76174D1EB947AE00E1C37C /* StarWars.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 0E7617451EB947AE00E1C37C /* StarWars.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; }; + 0E7617581EB947D600E1C37C /* Sprite.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617531EB947D600E1C37C /* Sprite.swift */; }; + 0E7617591EB947D600E1C37C /* SpriteRender.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617541EB947D600E1C37C /* SpriteRender.swift */; }; + 0E76175A1EB947D600E1C37C /* StarWarsGLAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617551EB947D600E1C37C /* StarWarsGLAnimator.swift */; }; + 0E76175B1EB947D600E1C37C /* Vector2.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617561EB947D600E1C37C /* Vector2.swift */; }; + 0E76175C1EB947D600E1C37C /* ViewTexture.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617571EB947D600E1C37C /* ViewTexture.swift */; }; + 0E76175F1EB947E100E1C37C /* StarWarsUIDynamicAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E76175E1EB947E100E1C37C /* StarWarsUIDynamicAnimator.swift */; }; + 0E7617621EB947EB00E1C37C /* StarWarsUIViewAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617611EB947EB00E1C37C /* StarWarsUIViewAnimator.swift */; }; + 0E7617641EB948E700E1C37C /* AnimationViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617631EB948E700E1C37C /* AnimationViewController.swift */; }; + 0E7617961EB98EE300E1C37C /* AnimationDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617941EB98EE300E1C37C /* AnimationDelegate.swift */; }; + 0E7617971EB98EE300E1C37C /* CircularRevealAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7617951EB98EE300E1C37C /* CircularRevealAnimator.swift */; }; + 0E7F44231EC2257600108434 /* TheEndViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E7F44221EC2257600108434 /* TheEndViewController.swift */; }; + 0E9364E61EBA6FC80070F773 /* StarWarsWindAnimator.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9364E51EBA6FC80070F773 /* StarWarsWindAnimator.swift */; }; + 0E9364E81EBB71B70070F773 /* UIView+CircularAnimation.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0E9364E71EBB71B70070F773 /* UIView+CircularAnimation.swift */; }; +/* End PBXBuildFile section */ + +/* Begin PBXContainerItemProxy section */ + 0E76174A1EB947AE00E1C37C /* PBXContainerItemProxy */ = { + isa = PBXContainerItemProxy; + containerPortal = 0E7617111EB946A300E1C37C /* Project object */; + proxyType = 1; + remoteGlobalIDString = 0E7617441EB947AE00E1C37C; + remoteInfo = StarWars; + }; +/* End PBXContainerItemProxy section */ + +/* Begin PBXCopyFilesBuildPhase section */ + 0E7617511EB947AE00E1C37C /* Embed Frameworks */ = { + isa = PBXCopyFilesBuildPhase; + buildActionMask = 2147483647; + dstPath = ""; + dstSubfolderSpec = 10; + files = ( + 0E76174D1EB947AE00E1C37C /* StarWars.framework in Embed Frameworks */, + ); + name = "Embed Frameworks"; + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXCopyFilesBuildPhase section */ + +/* Begin PBXFileReference section */ + 0E7617191EB946A300E1C37C /* case_Studies.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = case_Studies.app; sourceTree = BUILT_PRODUCTS_DIR; }; + 0E76171C1EB946A300E1C37C /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; + 0E76171E1EB946A300E1C37C /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; + 0E7617211EB946A300E1C37C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; + 0E7617231EB946A300E1C37C /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; + 0E7617261EB946A300E1C37C /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; + 0E7617281EB946A300E1C37C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0E7617451EB947AE00E1C37C /* StarWars.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = StarWars.framework; sourceTree = BUILT_PRODUCTS_DIR; }; + 0E7617471EB947AE00E1C37C /* StarWars.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = StarWars.h; sourceTree = ""; }; + 0E7617481EB947AE00E1C37C /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; + 0E7617531EB947D600E1C37C /* Sprite.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Sprite.swift; sourceTree = ""; }; + 0E7617541EB947D600E1C37C /* SpriteRender.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SpriteRender.swift; sourceTree = ""; }; + 0E7617551EB947D600E1C37C /* StarWarsGLAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsGLAnimator.swift; sourceTree = ""; }; + 0E7617561EB947D600E1C37C /* Vector2.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Vector2.swift; sourceTree = ""; }; + 0E7617571EB947D600E1C37C /* ViewTexture.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewTexture.swift; sourceTree = ""; }; + 0E76175E1EB947E100E1C37C /* StarWarsUIDynamicAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsUIDynamicAnimator.swift; sourceTree = ""; }; + 0E7617611EB947EB00E1C37C /* StarWarsUIViewAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsUIViewAnimator.swift; sourceTree = ""; }; + 0E7617631EB948E700E1C37C /* AnimationViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationViewController.swift; sourceTree = ""; }; + 0E7617941EB98EE300E1C37C /* AnimationDelegate.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationDelegate.swift; sourceTree = ""; }; + 0E7617951EB98EE300E1C37C /* CircularRevealAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = CircularRevealAnimator.swift; sourceTree = ""; }; + 0E7F44221EC2257600108434 /* TheEndViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = TheEndViewController.swift; sourceTree = ""; }; + 0E9364E51EBA6FC80070F773 /* StarWarsWindAnimator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = StarWarsWindAnimator.swift; sourceTree = ""; }; + 0E9364E71EBB71B70070F773 /* UIView+CircularAnimation.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+CircularAnimation.swift"; sourceTree = ""; }; +/* End PBXFileReference section */ + +/* Begin PBXFrameworksBuildPhase section */ + 0E7617161EB946A300E1C37C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E76174C1EB947AE00E1C37C /* StarWars.framework in Frameworks */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0E7617411EB947AE00E1C37C /* Frameworks */ = { + isa = PBXFrameworksBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXFrameworksBuildPhase section */ + +/* Begin PBXGroup section */ + 0E7617101EB946A300E1C37C = { + isa = PBXGroup; + children = ( + 0E76171B1EB946A300E1C37C /* case_Studies */, + 0E7617461EB947AE00E1C37C /* StarWars */, + 0E76171A1EB946A300E1C37C /* Products */, + ); + sourceTree = ""; + }; + 0E76171A1EB946A300E1C37C /* Products */ = { + isa = PBXGroup; + children = ( + 0E7617191EB946A300E1C37C /* case_Studies.app */, + 0E7617451EB947AE00E1C37C /* StarWars.framework */, + ); + name = Products; + sourceTree = ""; + }; + 0E76171B1EB946A300E1C37C /* case_Studies */ = { + isa = PBXGroup; + children = ( + 0E76171C1EB946A300E1C37C /* AppDelegate.swift */, + 0E76171E1EB946A300E1C37C /* ViewController.swift */, + 0E7617201EB946A300E1C37C /* Main.storyboard */, + 0E7617231EB946A300E1C37C /* Assets.xcassets */, + 0E7617251EB946A300E1C37C /* LaunchScreen.storyboard */, + 0E7617281EB946A300E1C37C /* Info.plist */, + 0E7617631EB948E700E1C37C /* AnimationViewController.swift */, + 0E7F44221EC2257600108434 /* TheEndViewController.swift */, + ); + path = case_Studies; + sourceTree = ""; + }; + 0E7617461EB947AE00E1C37C /* StarWars */ = { + isa = PBXGroup; + children = ( + 0E7617931EB98EE300E1C37C /* Circular */, + 0E7617601EB947EB00E1C37C /* StarWarsUIViewAnimator */, + 0E76175D1EB947E100E1C37C /* StarWarsUIDynamicAnimator */, + 0E7617521EB947D600E1C37C /* StarWarsGLAnimator */, + 0E7617471EB947AE00E1C37C /* StarWars.h */, + 0E7617481EB947AE00E1C37C /* Info.plist */, + 0E9364E51EBA6FC80070F773 /* StarWarsWindAnimator.swift */, + ); + path = StarWars; + sourceTree = ""; + }; + 0E7617521EB947D600E1C37C /* StarWarsGLAnimator */ = { + isa = PBXGroup; + children = ( + 0E7617531EB947D600E1C37C /* Sprite.swift */, + 0E7617541EB947D600E1C37C /* SpriteRender.swift */, + 0E7617551EB947D600E1C37C /* StarWarsGLAnimator.swift */, + 0E7617561EB947D600E1C37C /* Vector2.swift */, + 0E7617571EB947D600E1C37C /* ViewTexture.swift */, + ); + path = StarWarsGLAnimator; + sourceTree = ""; + }; + 0E76175D1EB947E100E1C37C /* StarWarsUIDynamicAnimator */ = { + isa = PBXGroup; + children = ( + 0E76175E1EB947E100E1C37C /* StarWarsUIDynamicAnimator.swift */, + ); + path = StarWarsUIDynamicAnimator; + sourceTree = ""; + }; + 0E7617601EB947EB00E1C37C /* StarWarsUIViewAnimator */ = { + isa = PBXGroup; + children = ( + 0E7617611EB947EB00E1C37C /* StarWarsUIViewAnimator.swift */, + ); + path = StarWarsUIViewAnimator; + sourceTree = ""; + }; + 0E7617931EB98EE300E1C37C /* Circular */ = { + isa = PBXGroup; + children = ( + 0E9364E71EBB71B70070F773 /* UIView+CircularAnimation.swift */, + 0E7617941EB98EE300E1C37C /* AnimationDelegate.swift */, + 0E7617951EB98EE300E1C37C /* CircularRevealAnimator.swift */, + ); + path = Circular; + sourceTree = ""; + }; +/* End PBXGroup section */ + +/* Begin PBXHeadersBuildPhase section */ + 0E7617421EB947AE00E1C37C /* Headers */ = { + isa = PBXHeadersBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E7617491EB947AE00E1C37C /* StarWars.h in Headers */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXHeadersBuildPhase section */ + +/* Begin PBXNativeTarget section */ + 0E7617181EB946A300E1C37C /* case_Studies */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0E76172B1EB946A300E1C37C /* Build configuration list for PBXNativeTarget "case_Studies" */; + buildPhases = ( + 0E7617151EB946A300E1C37C /* Sources */, + 0E7617161EB946A300E1C37C /* Frameworks */, + 0E7617171EB946A300E1C37C /* Resources */, + 0E7617511EB947AE00E1C37C /* Embed Frameworks */, + ); + buildRules = ( + ); + dependencies = ( + 0E76174B1EB947AE00E1C37C /* PBXTargetDependency */, + ); + name = case_Studies; + productName = case_Studies; + productReference = 0E7617191EB946A300E1C37C /* case_Studies.app */; + productType = "com.apple.product-type.application"; + }; + 0E7617441EB947AE00E1C37C /* StarWars */ = { + isa = PBXNativeTarget; + buildConfigurationList = 0E76174E1EB947AE00E1C37C /* Build configuration list for PBXNativeTarget "StarWars" */; + buildPhases = ( + 0E7617401EB947AE00E1C37C /* Sources */, + 0E7617411EB947AE00E1C37C /* Frameworks */, + 0E7617421EB947AE00E1C37C /* Headers */, + 0E7617431EB947AE00E1C37C /* Resources */, + ); + buildRules = ( + ); + dependencies = ( + ); + name = StarWars; + productName = StarWars; + productReference = 0E7617451EB947AE00E1C37C /* StarWars.framework */; + productType = "com.apple.product-type.framework"; + }; +/* End PBXNativeTarget section */ + +/* Begin PBXProject section */ + 0E7617111EB946A300E1C37C /* Project object */ = { + isa = PBXProject; + attributes = { + LastSwiftUpdateCheck = 0830; + LastUpgradeCheck = 0830; + ORGANIZATIONNAME = isabeljlee; + TargetAttributes = { + 0E7617181EB946A300E1C37C = { + CreatedOnToolsVersion = 8.3; + DevelopmentTeam = K39564QAF6; + ProvisioningStyle = Automatic; + }; + 0E7617441EB947AE00E1C37C = { + CreatedOnToolsVersion = 8.3; + DevelopmentTeam = K39564QAF6; + ProvisioningStyle = Automatic; + }; + }; + }; + buildConfigurationList = 0E7617141EB946A300E1C37C /* Build configuration list for PBXProject "case_Studies" */; + compatibilityVersion = "Xcode 3.2"; + developmentRegion = English; + hasScannedForEncodings = 0; + knownRegions = ( + en, + Base, + ); + mainGroup = 0E7617101EB946A300E1C37C; + productRefGroup = 0E76171A1EB946A300E1C37C /* Products */; + projectDirPath = ""; + projectRoot = ""; + targets = ( + 0E7617181EB946A300E1C37C /* case_Studies */, + 0E7617441EB947AE00E1C37C /* StarWars */, + ); + }; +/* End PBXProject section */ + +/* Begin PBXResourcesBuildPhase section */ + 0E7617171EB946A300E1C37C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E7617271EB946A300E1C37C /* LaunchScreen.storyboard in Resources */, + 0E7617241EB946A300E1C37C /* Assets.xcassets in Resources */, + 0E7617221EB946A300E1C37C /* Main.storyboard in Resources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0E7617431EB947AE00E1C37C /* Resources */ = { + isa = PBXResourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXResourcesBuildPhase section */ + +/* Begin PBXSourcesBuildPhase section */ + 0E7617151EB946A300E1C37C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E7F44231EC2257600108434 /* TheEndViewController.swift in Sources */, + 0E7617641EB948E700E1C37C /* AnimationViewController.swift in Sources */, + 0E76171F1EB946A300E1C37C /* ViewController.swift in Sources */, + 0E76171D1EB946A300E1C37C /* AppDelegate.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; + 0E7617401EB947AE00E1C37C /* Sources */ = { + isa = PBXSourcesBuildPhase; + buildActionMask = 2147483647; + files = ( + 0E7617591EB947D600E1C37C /* SpriteRender.swift in Sources */, + 0E76175B1EB947D600E1C37C /* Vector2.swift in Sources */, + 0E76175A1EB947D600E1C37C /* StarWarsGLAnimator.swift in Sources */, + 0E76175F1EB947E100E1C37C /* StarWarsUIDynamicAnimator.swift in Sources */, + 0E7617971EB98EE300E1C37C /* CircularRevealAnimator.swift in Sources */, + 0E7617621EB947EB00E1C37C /* StarWarsUIViewAnimator.swift in Sources */, + 0E7617961EB98EE300E1C37C /* AnimationDelegate.swift in Sources */, + 0E76175C1EB947D600E1C37C /* ViewTexture.swift in Sources */, + 0E7617581EB947D600E1C37C /* Sprite.swift in Sources */, + 0E9364E81EBB71B70070F773 /* UIView+CircularAnimation.swift in Sources */, + 0E9364E61EBA6FC80070F773 /* StarWarsWindAnimator.swift in Sources */, + ); + runOnlyForDeploymentPostprocessing = 0; + }; +/* End PBXSourcesBuildPhase section */ + +/* Begin PBXTargetDependency section */ + 0E76174B1EB947AE00E1C37C /* PBXTargetDependency */ = { + isa = PBXTargetDependency; + target = 0E7617441EB947AE00E1C37C /* StarWars */; + targetProxy = 0E76174A1EB947AE00E1C37C /* PBXContainerItemProxy */; + }; +/* End PBXTargetDependency section */ + +/* Begin PBXVariantGroup section */ + 0E7617201EB946A300E1C37C /* Main.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0E7617211EB946A300E1C37C /* Base */, + ); + name = Main.storyboard; + sourceTree = ""; + }; + 0E7617251EB946A300E1C37C /* LaunchScreen.storyboard */ = { + isa = PBXVariantGroup; + children = ( + 0E7617261EB946A300E1C37C /* Base */, + ); + name = LaunchScreen.storyboard; + sourceTree = ""; + }; +/* End PBXVariantGroup section */ + +/* Begin XCBuildConfiguration section */ + 0E7617291EB946A300E1C37C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + 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; + DEBUG_INFORMATION_FORMAT = dwarf; + 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", + "$(inherited)", + ); + GCC_WARN_64_TO_32_BIT_CONVERSION = YES; + GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; + GCC_WARN_UNDECLARED_SELECTOR = YES; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = YES; + ONLY_ACTIVE_ARCH = YES; + SDKROOT = iphoneos; + SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; + SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + TARGETED_DEVICE_FAMILY = "1,2"; + }; + name = Debug; + }; + 0E76172A1EB946A300E1C37C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_NONNULL = YES; + CLANG_ANALYZER_NUMBER_OBJECT_CONVERSION = YES_AGGRESSIVE; + CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; + CLANG_CXX_LIBRARY = "libc++"; + CLANG_ENABLE_MODULES = YES; + CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; + CLANG_WARN_DOCUMENTATION_COMMENTS = YES; + CLANG_WARN_EMPTY_BODY = YES; + CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; + CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + 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; + DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; + 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; + GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; + GCC_WARN_UNUSED_FUNCTION = YES; + GCC_WARN_UNUSED_VARIABLE = YES; + IPHONEOS_DEPLOYMENT_TARGET = 10.3; + MTL_ENABLE_DEBUG_INFO = NO; + SDKROOT = iphoneos; + SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; + TARGETED_DEVICE_FAMILY = "1,2"; + VALIDATE_PRODUCT = YES; + }; + name = Release; + }; + 0E76172C1EB946A300E1C37C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = K39564QAF6; + INFOPLIST_FILE = case_Studies/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.isabeljlee.case-Studies"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Debug; + }; + 0E76172D1EB946A300E1C37C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES; + ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; + DEVELOPMENT_TEAM = K39564QAF6; + INFOPLIST_FILE = case_Studies/Info.plist; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = "com.isabeljlee.case-Studies"; + PRODUCT_NAME = "$(TARGET_NAME)"; + SWIFT_VERSION = 3.0; + }; + name = Release; + }; + 0E76174F1EB947AE00E1C37C /* Debug */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = K39564QAF6; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = StarWars/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.isabeljlee.StarWars; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Debug; + }; + 0E7617501EB947AE00E1C37C /* Release */ = { + isa = XCBuildConfiguration; + buildSettings = { + CODE_SIGN_IDENTITY = ""; + CURRENT_PROJECT_VERSION = 1; + DEFINES_MODULE = YES; + DEVELOPMENT_TEAM = K39564QAF6; + DYLIB_COMPATIBILITY_VERSION = 1; + DYLIB_CURRENT_VERSION = 1; + DYLIB_INSTALL_NAME_BASE = "@rpath"; + INFOPLIST_FILE = StarWars/Info.plist; + INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks"; + LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; + PRODUCT_BUNDLE_IDENTIFIER = com.isabeljlee.StarWars; + PRODUCT_NAME = "$(TARGET_NAME)"; + SKIP_INSTALL = YES; + SWIFT_VERSION = 3.0; + VERSIONING_SYSTEM = "apple-generic"; + VERSION_INFO_PREFIX = ""; + }; + name = Release; + }; +/* End XCBuildConfiguration section */ + +/* Begin XCConfigurationList section */ + 0E7617141EB946A300E1C37C /* Build configuration list for PBXProject "case_Studies" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E7617291EB946A300E1C37C /* Debug */, + 0E76172A1EB946A300E1C37C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0E76172B1EB946A300E1C37C /* Build configuration list for PBXNativeTarget "case_Studies" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E76172C1EB946A300E1C37C /* Debug */, + 0E76172D1EB946A300E1C37C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; + 0E76174E1EB947AE00E1C37C /* Build configuration list for PBXNativeTarget "StarWars" */ = { + isa = XCConfigurationList; + buildConfigurations = ( + 0E76174F1EB947AE00E1C37C /* Debug */, + 0E7617501EB947AE00E1C37C /* Release */, + ); + defaultConfigurationIsVisible = 0; + defaultConfigurationName = Release; + }; +/* End XCConfigurationList section */ + }; + rootObject = 0E7617111EB946A300E1C37C /* Project object */; +} diff --git a/Example2/case_Studies.xcodeproj/project.xcworkspace/contents.xcworkspacedata b/Example2/case_Studies.xcodeproj/project.xcworkspace/contents.xcworkspacedata new file mode 100644 index 0000000..19038e6 --- /dev/null +++ b/Example2/case_Studies.xcodeproj/project.xcworkspace/contents.xcworkspacedata @@ -0,0 +1,7 @@ + + + + + diff --git a/Example2/case_Studies/AnimationViewController.swift b/Example2/case_Studies/AnimationViewController.swift new file mode 100644 index 0000000..119ba92 --- /dev/null +++ b/Example2/case_Studies/AnimationViewController.swift @@ -0,0 +1,133 @@ +// +// AnimationViewController.swift +// case_Studies +// +// Created by Isabel Lee on 02/05/2017. +// Copyright © 2017 isabeljlee. All rights reserved. +// + +import UIKit +import StarWars + +class AnimationViewController: UIViewController { + + @IBOutlet weak var circularRevealButton: UIButton! + @IBOutlet weak var circularReverseButton: UIButton! + @IBOutlet weak var colorChangeButton: UIButton! + @IBOutlet weak var viewRevealButton: UIButton! + @IBOutlet weak var viewRevertButton: UIButton! + @IBOutlet weak var theEndButton: UIButton! + + @IBAction func circularReveal(_ sender: UIButton) { + sender.layer.masksToBounds = true + + let fillLayer = CALayer() + fillLayer.backgroundColor = UIColor.white.cgColor + fillLayer.frame = sender.layer.bounds + sender.layer.insertSublayer(fillLayer, at: 0) + + let center = CGPoint(x: fillLayer.bounds.midX, y: fillLayer.bounds.midY) + let radius: CGFloat = max(sender.frame.width / 2 , sender.frame.height / 2) + + let circularAnimation = CircularRevealAnimator(layer: fillLayer, center: center, startRadius: 0, endRadius: radius) + circularAnimation.duration = 0.2 + circularAnimation.completion = { + fillLayer.opacity = 0 + let opacityAnimation = CABasicAnimation(keyPath: "opacity") + opacityAnimation.fromValue = 1 + opacityAnimation.toValue = 0 + opacityAnimation.duration = 0.2 + opacityAnimation.delegate = AnimationDelegate { + fillLayer.removeFromSuperlayer() + } + fillLayer.add(opacityAnimation, forKey: "opacity") + } + circularAnimation.start() + } + + @IBAction func CircularRevert(_ sender: UIButton) { + sender.layer.masksToBounds = true + + let fillLayer = CALayer() + fillLayer.backgroundColor = UIColor.white.cgColor + fillLayer.frame = sender.layer.bounds + sender.layer.insertSublayer(fillLayer, at: 0) + + let center = CGPoint(x: fillLayer.bounds.midX, y: fillLayer.bounds.midY) + let radius: CGFloat = max(sender.frame.width / 2 , sender.frame.height / 2) + + let circularAnimation = CircularRevealAnimator(layer: fillLayer, center: center, startRadius: radius, endRadius: 0) + circularAnimation.duration = 0.2 + circularAnimation.completion = { + fillLayer.opacity = 0 + let opacityAnimation = CABasicAnimation(keyPath: "opacity") + opacityAnimation.fromValue = 1 + opacityAnimation.toValue = 0 + opacityAnimation.duration = 0.2 + opacityAnimation.delegate = AnimationDelegate { + fillLayer.removeFromSuperlayer() + } + fillLayer.add(opacityAnimation, forKey: "opacity") + } + circularAnimation.start() + } + + @IBAction func colorChange(_ sender: UIButton) { + sender.layer.masksToBounds = true + + let fillLayer = CALayer() + fillLayer.backgroundColor = UIColor.white.cgColor + fillLayer.frame = sender.layer.bounds + sender.layer.insertSublayer(fillLayer, at: 0) + + let center = CGPoint(x: fillLayer.bounds.midX, y: fillLayer.bounds.midY) + let radius: CGFloat = max(sender.frame.width / 2 , sender.frame.height / 2) + + let circularAnimation = CircularRevealAnimator(layer: fillLayer, center: center, startRadius: 0, endRadius: radius) + circularAnimation.duration = 0.2 + circularAnimation.completion = { + fillLayer.removeFromSuperlayer() + sender.backgroundColor = UIColor.white + } + circularAnimation.start() + } + + @IBAction func viewReveal(_ sender: UIButton) { + self.view.animateCircular(withDuration: 0.5, center: sender.center, revert: false, animations: { + self.backgroundImageView.image = UIImage(named: "background") + self.circularRevealButton.backgroundColor = UIColor.white + self.circularReverseButton.backgroundColor = UIColor.black + self.colorChangeButton.backgroundColor = UIColor.white + self.viewRevealButton.backgroundColor = UIColor.black + self.viewRevertButton.backgroundColor = UIColor.white + self.theEndButton.backgroundColor = UIColor.black + }) + } + + @IBAction func viewRevert(_ sender: UIButton) { + self.view.animateCircular(withDuration: 0.5, center: sender.center, revert: true, animations: { + self.backgroundImageView.image = UIImage(named: "background2") + self.circularRevealButton.backgroundColor = UIColor.black + self.circularReverseButton.backgroundColor = UIColor.white + self.colorChangeButton.backgroundColor = UIColor.black + self.viewRevealButton.backgroundColor = UIColor.white + self.viewRevertButton.backgroundColor = UIColor.black + self.theEndButton.backgroundColor = UIColor.white + }) + } + + @IBOutlet weak var backgroundImageView: UIImageView! + + + override func viewDidLoad() { + super.viewDidLoad() + + // Do any additional setup after loading the view. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + +} diff --git a/Example2/case_Studies/AppDelegate.swift b/Example2/case_Studies/AppDelegate.swift new file mode 100644 index 0000000..c98c1c3 --- /dev/null +++ b/Example2/case_Studies/AppDelegate.swift @@ -0,0 +1,46 @@ +// +// AppDelegate.swift +// case_Studies +// +// Created by Isabel Lee on 02/05/2017. +// Copyright © 2017 isabeljlee. All rights reserved. +// + +import UIKit + +@UIApplicationMain +class AppDelegate: UIResponder, UIApplicationDelegate { + + var window: UIWindow? + + + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { + // Override point for customization after application launch. + return true + } + + 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 invalidate graphics rendering callbacks. Games should use this method to pause the game. + } + + 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) { + // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. + } + + 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) { + // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. + } + + +} + diff --git a/Example2/case_Studies/Assets.xcassets/AppIcon.appiconset/Contents.json b/Example2/case_Studies/Assets.xcassets/AppIcon.appiconset/Contents.json new file mode 100644 index 0000000..6d54bf1 --- /dev/null +++ b/Example2/case_Studies/Assets.xcassets/AppIcon.appiconset/Contents.json @@ -0,0 +1,176 @@ +{ + "images" : [ + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "20x20", + "idiom" : "iphone", + "filename" : "Icon-App-20x20@3x.png", + "scale" : "3x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "iphone", + "filename" : "Icon-App-29x29@3x.png", + "scale" : "3x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@3x.png", + "scale" : "3x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@1x.png", + "scale" : "1x" + }, + { + "size" : "57x57", + "idiom" : "iphone", + "filename" : "Icon-App-57x57@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@2x.png", + "scale" : "2x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@3x.png", + "scale" : "3x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@1x.png", + "scale" : "1x" + }, + { + "size" : "20x20", + "idiom" : "ipad", + "filename" : "Icon-App-20x20@2x.png", + "scale" : "2x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@1x.png", + "scale" : "1x" + }, + { + "size" : "29x29", + "idiom" : "ipad", + "filename" : "Icon-App-29x29@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "40x40", + "idiom" : "ipad", + "filename" : "Icon-App-40x40@2x.png", + "scale" : "2x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@1x.png", + "scale" : "1x" + }, + { + "size" : "50x50", + "idiom" : "ipad", + "filename" : "Icon-Small-50x50@2x.png", + "scale" : "2x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@1x.png", + "scale" : "1x" + }, + { + "size" : "72x72", + "idiom" : "ipad", + "filename" : "Icon-App-72x72@2x.png", + "scale" : "2x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@2x.png", + "scale" : "2x" + }, + { + "size" : "83.5x83.5", + "idiom" : "ipad", + "filename" : "Icon-App-83.5x83.5@2x.png", + "scale" : "2x" + }, + { + "size" : "40x40", + "idiom" : "iphone", + "filename" : "Icon-App-40x40@1x.png", + "scale" : "1x" + }, + { + "size" : "60x60", + "idiom" : "iphone", + "filename" : "Icon-App-60x60@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "iphone", + "filename" : "Icon-App-76x76@1x.png", + "scale" : "1x" + }, + { + "size" : "76x76", + "idiom" : "ipad", + "filename" : "Icon-App-76x76@3x.png", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example2/case_Studies/Assets.xcassets/Contents.json b/Example2/case_Studies/Assets.xcassets/Contents.json new file mode 100644 index 0000000..da4a164 --- /dev/null +++ b/Example2/case_Studies/Assets.xcassets/Contents.json @@ -0,0 +1,6 @@ +{ + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example2/case_Studies/Assets.xcassets/background.imageset/Contents.json b/Example2/case_Studies/Assets.xcassets/background.imageset/Contents.json new file mode 100644 index 0000000..e97bcdb --- /dev/null +++ b/Example2/case_Studies/Assets.xcassets/background.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "background.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example2/case_Studies/Assets.xcassets/background.imageset/background.jpg b/Example2/case_Studies/Assets.xcassets/background.imageset/background.jpg new file mode 100644 index 0000000..fca65a4 Binary files /dev/null and b/Example2/case_Studies/Assets.xcassets/background.imageset/background.jpg differ diff --git a/Example2/case_Studies/Assets.xcassets/background2.imageset/Contents.json b/Example2/case_Studies/Assets.xcassets/background2.imageset/Contents.json new file mode 100644 index 0000000..c151c31 --- /dev/null +++ b/Example2/case_Studies/Assets.xcassets/background2.imageset/Contents.json @@ -0,0 +1,21 @@ +{ + "images" : [ + { + "idiom" : "universal", + "filename" : "backgroud2.jpg", + "scale" : "1x" + }, + { + "idiom" : "universal", + "scale" : "2x" + }, + { + "idiom" : "universal", + "scale" : "3x" + } + ], + "info" : { + "version" : 1, + "author" : "xcode" + } +} \ No newline at end of file diff --git a/Example2/case_Studies/Assets.xcassets/background2.imageset/backgroud2.jpg b/Example2/case_Studies/Assets.xcassets/background2.imageset/backgroud2.jpg new file mode 100644 index 0000000..afd0984 Binary files /dev/null and b/Example2/case_Studies/Assets.xcassets/background2.imageset/backgroud2.jpg differ diff --git a/Example2/case_Studies/Base.lproj/LaunchScreen.storyboard b/Example2/case_Studies/Base.lproj/LaunchScreen.storyboard new file mode 100644 index 0000000..fdf3f97 --- /dev/null +++ b/Example2/case_Studies/Base.lproj/LaunchScreen.storyboard @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example2/case_Studies/Base.lproj/Main.storyboard b/Example2/case_Studies/Base.lproj/Main.storyboard new file mode 100644 index 0000000..b0b41eb --- /dev/null +++ b/Example2/case_Studies/Base.lproj/Main.storyboard @@ -0,0 +1,507 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/Example2/case_Studies/Info.plist b/Example2/case_Studies/Info.plist new file mode 100644 index 0000000..d052473 --- /dev/null +++ b/Example2/case_Studies/Info.plist @@ -0,0 +1,45 @@ + + + + + CFBundleDevelopmentRegion + en + CFBundleExecutable + $(EXECUTABLE_NAME) + CFBundleIdentifier + $(PRODUCT_BUNDLE_IDENTIFIER) + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + $(PRODUCT_NAME) + CFBundlePackageType + APPL + CFBundleShortVersionString + 1.0 + CFBundleVersion + 1 + LSRequiresIPhoneOS + + UILaunchStoryboardName + LaunchScreen + UIMainStoryboardFile + Main + UIRequiredDeviceCapabilities + + armv7 + + UISupportedInterfaceOrientations + + UIInterfaceOrientationPortrait + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + UISupportedInterfaceOrientations~ipad + + UIInterfaceOrientationPortrait + UIInterfaceOrientationPortraitUpsideDown + UIInterfaceOrientationLandscapeLeft + UIInterfaceOrientationLandscapeRight + + + diff --git a/Example2/case_Studies/TheEndViewController.swift b/Example2/case_Studies/TheEndViewController.swift new file mode 100644 index 0000000..94a59f7 --- /dev/null +++ b/Example2/case_Studies/TheEndViewController.swift @@ -0,0 +1,27 @@ +// +// TheEndViewController.swift +// case_Studies +// +// Created by Isabel Lee on 09/05/2017. +// Copyright © 2017 isabeljlee. All rights reserved. +// + +import UIKit +import StarWars + +class TheEndViewController: UIViewController { + @IBOutlet weak var blackView: UIView! + @IBOutlet weak var theEndButton: UIButton! + @IBOutlet weak var theEnd: UILabel! + + @IBAction func theEndTapped(_ sender: UIButton) { + self.view.animateCircular(withDuration: 1, center: self.view.center, revert: true, animations: { + self.blackView.alpha = 1 + self.theEnd.text = "Thanks" + }) + } + + override func viewDidLoad() { + super.viewDidLoad() + } +} diff --git a/Example2/case_Studies/ViewController.swift b/Example2/case_Studies/ViewController.swift new file mode 100644 index 0000000..72069c5 --- /dev/null +++ b/Example2/case_Studies/ViewController.swift @@ -0,0 +1,146 @@ +// +// ViewController.swift +// case_Studies +// +// Created by Isabel Lee on 02/05/2017. +// Copyright © 2017 isabeljlee. All rights reserved. +// + +import UIKit +import StarWars + +class ViewController: UIViewController, UIViewControllerTransitioningDelegate { + + var speed = 3.0 + var size = 20.0 + var wind = 0.0 + var float = 0.25 + + @IBOutlet weak var sizeLabel: UILabel! + @IBOutlet weak var speedLabel: UILabel! + @IBOutlet weak var windLabel: UILabel! + @IBOutlet weak var floatLabel: UILabel! + + @IBOutlet weak var sizeStack: UIStackView! + @IBOutlet weak var speedStack: UIStackView! + @IBOutlet weak var windStack: UIStackView! + @IBOutlet weak var floatStack: UIStackView! + + @IBOutlet weak var segmentedControl: UISegmentedControl! + + @IBOutlet weak var backgroundImageView: UIImageView! + let uiViewAnimator = StarWarsUIViewAnimator() + let uiDynamicAnimator = StarWarsUIDynamicAnimator() + let glaAnimator = StarWarsGLAnimator() + let windAnimator = StarWarsWindAnimator() + + var currentAnimator: UIViewControllerAnimatedTransitioning! + + @IBAction func sizeSliderMoved(_ sender: UISlider) { + let currentValue = Double(lroundf(sender.value)) + print("Size: \(currentValue)") + sizeLabel.text = "\(currentValue)" + size = currentValue + uiViewAnimator.spriteWidth = CGFloat(size) + uiDynamicAnimator.spriteWidth = CGFloat(size) + windAnimator.spriteWidth = CGFloat(size) + } + + @IBAction func speedSliderMoved(_ sender: UISlider) { + let currentValue = round(sender.value * 10)/10 + print("Speed: \(currentValue)") + speedLabel.text = String(format: "%.1f", currentValue) + speed = Double(currentValue) + uiViewAnimator.duration = speed + } + + @IBAction func windSliderMoved(_ sender: UISlider) { + let currentValue = sender.value + windLabel.text = String(format: "%.1f", currentValue) + wind = Double(currentValue) + windAnimator.wind = CGFloat(wind) + } + + + @IBAction func floatSliderMoved(_ sender: UISlider) { + let currentValue = sender.value + floatLabel.text = String(format: "%.1f", currentValue) + float = Double(currentValue) + windAnimator.float = CGFloat(float) + } + + @IBAction func changeAnimationSegmentedControl(_ sender: UISegmentedControl) { + switch sender.selectedSegmentIndex { + case 0: + self.speedStack.isHidden = false + self.windStack.isHidden = true + self.floatStack.isHidden = true + currentAnimator = uiViewAnimator + + return + case 1: + self.speedStack.isHidden = true + self.windStack.isHidden = true + self.floatStack.isHidden = true + currentAnimator = uiDynamicAnimator + return + case 2: + self.speedStack.isHidden = false + self.windStack.isHidden = true + self.floatStack.isHidden = true + return + case 3: + self.speedStack.isHidden = true + self.windStack.isHidden = false + self.floatStack.isHidden = false + currentAnimator = windAnimator + return + default: + return + } + } + + override func viewDidLoad() { + super.viewDidLoad() + currentAnimator = uiViewAnimator + // Do any additional setup after loading the view, typically from a nib. + } + + override func didReceiveMemoryWarning() { + super.didReceiveMemoryWarning() + // Dispose of any resources that can be recreated. + } + + @IBAction func unwindToRoot(sender: UIStoryboardSegue) { + + } + + override func prepare(for segue: UIStoryboardSegue, sender: Any?) { + if segue.identifier == "viewTransitionSegue" { + let destination = segue.destination + destination.transitioningDelegate = self + } + } + + func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? { + + switch segmentedControl.selectedSegmentIndex { + case 0: + return uiViewAnimator + case 1: + return uiDynamicAnimator + case 2: + let animator = StarWarsGLAnimator() + animator.duration = speed + animator.spriteWidth = CGFloat(size) + + return animator + case 3: + return windAnimator + default: + return uiViewAnimator + } + } +} + +