├── .swift-version
├── chain-example-loop.gif
├── ChainedAnimation.xcodeproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
├── xcshareddata
│ └── xcschemes
│ │ └── ChainedAnimation.xcscheme
└── project.pbxproj
├── .travis.yml
├── ChainedAnimation
├── Types.swift
├── ChainedAnimation.h
├── Animator.swift
├── Info.plist
├── AnimationProvider.swift
├── AnimationConfiguration.swift
└── AnimationChain.swift
├── ChainedAnimationTests
├── Info.plist
├── ChainedAnimationTestCase.swift
├── MockAnimationProvider.swift
├── ChainedAnimationTests.swift
└── AnimationConfigurationTests.swift
├── ChainedAnimation.podspec
├── ChainedAnimationExample
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── UIView+Helper.swift
├── Info.plist
├── Base.lproj
│ ├── Main.storyboard
│ └── LaunchScreen.storyboard
├── AppDelegate.swift
└── ViewController.swift
├── .gitignore
├── LICENSE
└── README.md
/.swift-version:
--------------------------------------------------------------------------------
1 | 3.0
2 |
--------------------------------------------------------------------------------
/chain-example-loop.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/daehn/ChainedAnimation/HEAD/chain-example-loop.gif
--------------------------------------------------------------------------------
/ChainedAnimation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/.travis.yml:
--------------------------------------------------------------------------------
1 | language: objective-c
2 | osx_image: xcode10
3 |
4 | script:
5 | - set -o pipefail && xcodebuild clean build test -scheme ChainedAnimation -destination "OS=12.0,name=iPhone XS" | xcpretty
6 | after_script:
7 | - bash <(curl -s https://codecov.io/bash)
8 |
--------------------------------------------------------------------------------
/ChainedAnimation/Types.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Types.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 | public typealias Animation = () -> Void
10 | public typealias Completion = (Bool) -> Void
11 |
--------------------------------------------------------------------------------
/ChainedAnimation/ChainedAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // ChainedAnimation.h
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | //! Project version number for ChainedAnimation.
12 | FOUNDATION_EXPORT double ChainedAnimationVersionNumber;
13 |
14 | //! Project version string for ChainedAnimation.
15 | FOUNDATION_EXPORT const unsigned char ChainedAnimationVersionString[];
16 |
17 | // In this header, you should import all the public headers of your framework using statements like #import
18 |
19 |
20 |
--------------------------------------------------------------------------------
/ChainedAnimation/Animator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // Animator.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | struct Animator {
11 |
12 | static var animationProvider: AnimationProvider = UIViewAnimationProvider()
13 |
14 | static func perform(configuration: AnimationConfiguration) {
15 | animationProvider.animate(
16 | withDuration: configuration.duration,
17 | delay: configuration.delay,
18 | options: configuration.options,
19 | animations: configuration.animation,
20 | completion: configuration.completion
21 | )
22 | }
23 |
24 | }
25 |
--------------------------------------------------------------------------------
/ChainedAnimationTests/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | BNDL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ChainedAnimation.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 | s.name = "ChainedAnimation"
4 | s.version = "3.0.1"
5 | s.summary = "ChainedAnimation is a small Swift library to chain multiple animations with different delays."
6 | s.homepage = "https://github.com/daehn/ChainedAnimation"
7 | s.license = 'MIT'
8 | s.author = { "Silvan Dähn" => "silvandaehn@me.com" }
9 | s.source = { :git => "https://github.com/daehn/ChainedAnimation.git", :tag => s.version.to_s }
10 | s.social_media_url = 'https://twitter.com/silvandaehn'
11 |
12 | s.platform = :ios, '8.0'
13 | s.requires_arc = true
14 | s.pod_target_xcconfig = { 'SWIFT_VERSION' => '4' }
15 |
16 | s.source_files = "ChainedAnimation", "ChainedAnimation/**/*.{h,m,swift}"
17 | end
18 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | }
33 | ],
34 | "info" : {
35 | "version" : 1,
36 | "author" : "xcode"
37 | }
38 | }
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | # OS X
2 | .DS_Store
3 |
4 | # Xcode
5 | #
6 | build/
7 | *.pbxuser
8 | !default.pbxuser
9 | *.mode1v3
10 | !default.mode1v3
11 | *.mode2v3
12 | !default.mode2v3
13 | *.perspectivev3
14 | !default.perspectivev3
15 | xcuserdata
16 | *.xccheckout
17 | profile
18 | *.moved-aside
19 | DerivedData
20 | *.hmap
21 | *.ipa
22 | *.xcuserstate
23 |
24 | # CocoaPods
25 | #
26 | # We recommend against adding the Pods directory to your .gitignore. However
27 | # you should judge for yourself, the pros and cons are mentioned at:
28 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control
29 | #
30 | # Pods/
31 |
32 | # Carthage
33 | #
34 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
35 | # Carthage/Checkouts
36 |
37 | Carthage/Build
38 |
--------------------------------------------------------------------------------
/ChainedAnimation/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | FMWK
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | $(CURRENT_PROJECT_VERSION)
21 | NSPrincipalClass
22 |
23 |
24 |
25 |
--------------------------------------------------------------------------------
/ChainedAnimation/AnimationProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationProvider.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | public protocol AnimationProvider {
11 |
12 | func animate(withDuration duration: TimeInterval, delay: TimeInterval, options: UIView.AnimationOptions, animations: @escaping Animation, completion: Completion?)
13 |
14 | }
15 |
16 |
17 | struct UIViewAnimationProvider: AnimationProvider {
18 |
19 | func animate(withDuration duration: TimeInterval, delay: TimeInterval, options: UIView.AnimationOptions, animations: @escaping Animation, completion: Completion?) {
20 | UIView.animate(
21 | withDuration: duration,
22 | delay: delay,
23 | options: options,
24 | animations: animations,
25 | completion: completion
26 | )
27 | }
28 |
29 | }
30 |
--------------------------------------------------------------------------------
/ChainedAnimationTests/ChainedAnimationTestCase.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChainedAnimationBaseTest.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | import XCTest
11 | @testable import ChainedAnimation
12 |
13 |
14 | class ChainedAnimationTestCase: XCTestCase {
15 |
16 | var animationProvider: MockAnimationProvider!
17 |
18 | override func setUp() {
19 | super.setUp()
20 | animationProvider = MockAnimationProvider()
21 | Animator.animationProvider = animationProvider
22 | }
23 |
24 | // MARK: - Helper
25 |
26 | func testConfiguration(_ animation: @escaping Animation, completion: Completion? = nil) -> AnimationConfiguration {
27 | return AnimationConfiguration(
28 | animation,
29 | duration: 0.5,
30 | delay: 0.6,
31 | options: .curveEaseIn,
32 | completion: completion
33 | )
34 | }
35 |
36 | }
37 |
--------------------------------------------------------------------------------
/ChainedAnimation/AnimationConfiguration.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationConfiguration.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | struct AnimationConfiguration {
11 |
12 | let animation: Animation
13 | let duration: TimeInterval
14 | let delay: TimeInterval
15 | let options: UIView.AnimationOptions
16 | var completion : Completion?
17 |
18 | init(_ animation: @escaping Animation, duration: TimeInterval, delay: TimeInterval, options: UIView.AnimationOptions = [], completion: Completion? = nil) {
19 | self.animation = animation
20 | self.duration = duration
21 | self.delay = delay
22 | self.options = options
23 | self.completion = completion
24 | }
25 |
26 | mutating func add(completion: @escaping Completion) {
27 | let currentCompletion = self.completion
28 | self.completion = {
29 | currentCompletion?($0)
30 | completion($0)
31 | }
32 | }
33 | }
34 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | The MIT License (MIT)
2 |
3 | Copyright (c) 2015 Silvan Daehn
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/UIView+Helper.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Helper.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | import UIKit
11 |
12 |
13 | extension UIView {
14 |
15 | func outline(_ color: UIColor = .black, borderWidth: CGFloat = 1, cornerRadius: CGFloat = 0) {
16 | backgroundColor = .clear
17 | layer.borderColor = color.cgColor
18 | layer.borderWidth = borderWidth
19 | layer.cornerRadius = cornerRadius
20 | }
21 |
22 | }
23 |
24 |
25 | extension UIView {
26 |
27 | var y: CGFloat {
28 | get { return frame.origin.y }
29 | set(value) { frame.origin.y = value }
30 | }
31 |
32 | var x: CGFloat {
33 | get { return frame.origin.x }
34 | set(value) { frame.origin.x = value }
35 | }
36 |
37 | var width: CGFloat {
38 | get { return frame.width }
39 | set(value) { frame.size.width = value }
40 | }
41 |
42 | var height: CGFloat {
43 | get { return frame.height }
44 | set(value) { frame.size.height = value }
45 | }
46 |
47 | }
48 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | $(EXECUTABLE_NAME)
9 | CFBundleIdentifier
10 | $(PRODUCT_BUNDLE_IDENTIFIER)
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundleName
14 | $(PRODUCT_NAME)
15 | CFBundlePackageType
16 | APPL
17 | CFBundleShortVersionString
18 | 1.0
19 | CFBundleVersion
20 | 1
21 | LSRequiresIPhoneOS
22 |
23 | UILaunchStoryboardName
24 | LaunchScreen
25 | UIMainStoryboardFile
26 | Main
27 | UIRequiredDeviceCapabilities
28 |
29 | armv7
30 |
31 | UISupportedInterfaceOrientations
32 |
33 | UIInterfaceOrientationPortrait
34 | UIInterfaceOrientationLandscapeLeft
35 | UIInterfaceOrientationLandscapeRight
36 |
37 |
38 |
39 |
--------------------------------------------------------------------------------
/ChainedAnimationTests/MockAnimationProvider.swift:
--------------------------------------------------------------------------------
1 | //
2 | // MockAnimationProvider.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 | import Foundation
10 | import ChainedAnimation
11 |
12 | typealias AnimationParameters = (
13 | duration: TimeInterval,
14 | delay: TimeInterval,
15 | options: UIView.AnimationOptions,
16 | animations: Animation,
17 | completion: Completion?
18 | )
19 |
20 | class TestAnimation {
21 |
22 | var callCount = 0
23 | var closure: Animation! = nil
24 |
25 | init() {
26 | closure = { self.callCount += 1 }
27 | }
28 |
29 | }
30 |
31 | class TestCompletion {
32 |
33 | var callCount = 0
34 | var closure: Completion! = nil
35 |
36 | init() {
37 | closure = { _ in self.callCount += 1 }
38 | }
39 |
40 | }
41 |
42 | class MockAnimationProvider: AnimationProvider {
43 |
44 | var callClosure: ((AnimationParameters) -> Void)?
45 | var callParameters: AnimationParameters?
46 | var callCount = 0
47 |
48 | var callPassedInClosures = false
49 |
50 | public func animate(withDuration duration: TimeInterval, delay: TimeInterval, options: UIView.AnimationOptions, animations: @escaping Animation, completion: Completion?) {
51 | callCount += 1
52 | let parameters = (duration: duration, delay: delay, options: options, animations: animations, completion: completion)
53 | callParameters = parameters
54 | callClosure?(parameters)
55 |
56 | guard callPassedInClosures else { return }
57 | animations()
58 | completion?(true)
59 | }
60 |
61 | }
62 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/Base.lproj/LaunchScreen.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/ChainedAnimationTests/ChainedAnimationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChainedAnimationTests.swift
3 | // ChainedAnimationTests
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | @testable import ChainedAnimation
11 |
12 |
13 | class ChainedAnimationTests: ChainedAnimationTestCase {
14 |
15 | func testAnimationChain() {
16 | let animationClosure: Animation = {}
17 | let firstBoxedAnimation = testConfiguration(animationClosure)
18 | let firstChain = AnimationChain(options: [.curveEaseIn, .autoreverse], animations: [[firstBoxedAnimation]])
19 | let secondChain = firstChain.thenAfterStart(1.0, animation: animationClosure)
20 |
21 | XCTAssert(firstChain.currentOffset == 0)
22 | XCTAssert(firstChain.animations.joined().count == 1)
23 | XCTAssert(secondChain.currentOffset == 1.0)
24 | XCTAssert(secondChain.animations.joined().count == 2)
25 | XCTAssert(secondChain.options == firstChain.options)
26 |
27 | let completionChain = secondChain.chainAfterCompletion(0.5, delay: 0, options: .curveEaseInOut, animations: animationClosure)
28 | XCTAssert(completionChain.animations.joined().count == 3)
29 | XCTAssert(completionChain.animations.count == 2)
30 | XCTAssert(completionChain.currentOffset == 0)
31 | XCTAssert(completionChain.options == .curveEaseInOut)
32 | }
33 |
34 | func testAnimationCalled() {
35 | UIView.beginAnimationChain(0) {
36 | XCTAssert(true)
37 | }.animate()
38 | }
39 |
40 | func testCompletionCalled() {
41 | UIView.beginAnimationChain(2, delay: 0, options: UIView.AnimationOptions.curveEaseInOut) {
42 | }.completion { success in
43 | XCTAssert(success)
44 | }.animate()
45 | }
46 |
47 | func testThenAfterCalled() {
48 | UIView.beginAnimationChain(0.2, delay: 0) {
49 | }.thenAfterStart(0.2) {
50 | XCTAssert(true)
51 | }.animate()
52 | }
53 |
54 | }
55 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/AppDelegate.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.swift
3 | // ChainedAnimationExample
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 | import UIKit
10 |
11 | @UIApplicationMain
12 | class AppDelegate: UIResponder, UIApplicationDelegate {
13 |
14 | var window: UIWindow?
15 |
16 |
17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool {
18 | // Override point for customization after application launch.
19 | return true
20 | }
21 |
22 | func applicationWillResignActive(_ application: UIApplication) {
23 | // 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.
24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
25 | }
26 |
27 | func applicationDidEnterBackground(_ application: UIApplication) {
28 | // 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.
29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
30 | }
31 |
32 | func applicationWillEnterForeground(_ application: UIApplication) {
33 | // 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.
34 | }
35 |
36 | func applicationDidBecomeActive(_ application: UIApplication) {
37 | // 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.
38 | }
39 |
40 | func applicationWillTerminate(_ application: UIApplication) {
41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
42 | }
43 |
44 |
45 | }
46 |
47 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ChainedAnimation
2 |
3 | [](https://travis-ci.org/daehn/ChainedAnimation)  [](https://codecov.io/gh/daehn/ChainedAnimation) [](https://github.com/Carthage/Carthage) [](https://cocoapods.org/pods/ChainedAnimation)
4 |
5 | ## Usage
6 |
7 | To run the example project, clone the repo, and run the Example application target.
8 |
9 | Chain multiple animations with different delays. Chained animations will be started with a delay after the last one started executing.
10 |
11 |
12 |
13 | You can create a chained animation with the `-beginAnimationChain` function on the UIView class.
14 |
15 | ```swift
16 | UIView.beginAnimationChain(0.5) {
17 | view.frame.origin.y = 170
18 | }.animate()
19 | ```
20 |
21 | You can provide an optional delay an `UIViewAnimationOptions`.
22 |
23 | ```swift
24 | UIView.beginAnimationChain(0.5, delay: 0.2, options: .CurveEaseInOut) {
25 | view.frame.origin.y = 170
26 | }.animate()
27 | ```
28 | To add an offset animation, use the `-thenAfterStart:` function and append an
29 | animation closure that will be executed as soon as the last animation started, delayed by the provided offset. Add a completion
30 | closure to the animation chain and it will be executed when the previous animation in the chain completed.
31 |
32 | ```swift
33 | UIView.beginAnimationChain(0.5, options: .CurveEaseInOut) {
34 | view.frame.origin.y = 170
35 | }.thenAfterStart(0.1) {
36 | // This animation will be started 0.1 seconds
37 | // after the previous one started
38 | otherView.tranform = awesomeTransform
39 | }.thenAfterStart(0.15) {
40 | // More shiny animations
41 | }.completion { bool in
42 | // Do something nice on completion. Or don't.
43 | }.animate()
44 | ```
45 |
46 | It is also possible to add a new chain after a previous one completed.
47 | To add a new chain call `-chainAfterCompletion:` and start adding animation blocks with their offset.
48 |
49 | ```swift
50 | UIView.beginAnimationChain(0.33, options: .CurveEaseInOut) {
51 | view.frame.origin.y = 170
52 | }.thenAfterStart(0.15) {
53 | // Start animations with a delayed start
54 | }.completion { bool in
55 | // Do something nice on the completion of the first chain.
56 | }.chainAfterCompletion(1.2, options: .CurveEaseIn) {
57 | // This animation will be started after the last
58 | // animation in the first chain completed
59 | }.thenAfterStart(0.1) {
60 | // This animation will be started 0.1 seconds after
61 | // the first animation in the second chain started
62 | }.completion { _ in
63 | // Do something nice on the completion of the second chain.
64 | }.animate()
65 | ```
66 |
67 | ## Author
68 |
69 | Silvan Dähn, @silvandaehn
70 |
71 | ## License
72 |
73 | Chain is available under the MIT license. See the LICENSE file for more info.
74 |
--------------------------------------------------------------------------------
/ChainedAnimationTests/AnimationConfigurationTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationConfigurationTests.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | import XCTest
11 | @testable import ChainedAnimation
12 |
13 |
14 | class AnimationConfigurationTests: ChainedAnimationTestCase {
15 |
16 | func testThatItCallsTheAnimationProviderWithTheGivenParametersWhenPerformIsCalled() {
17 | // Given
18 | let sut = AnimationConfiguration(
19 | {},
20 | duration: 1.2,
21 | delay: 0.5,
22 | options: .curveEaseIn,
23 | completion: nil
24 | )
25 |
26 | // when
27 | Animator.perform(configuration: sut)
28 |
29 | // then
30 | let params = animationProvider.callParameters
31 | XCTAssertEqual(params?.duration, 1.2)
32 | XCTAssertEqual(params?.delay, 0.5)
33 | XCTAssertEqual(params?.options, .curveEaseIn)
34 | }
35 |
36 | func testThatItCallsTheProviderWithTheAnimationAndCompletionClosure() {
37 | // Given
38 | animationProvider.callPassedInClosures = true
39 | let completionExpectation = expectation(description: "Completion should be called")
40 | var animationCalled = false
41 | let animation: Animation = { animationCalled = true }
42 | let completion: Completion = { _ in completionExpectation.fulfill() }
43 | let sut = testConfiguration(animation, completion: completion)
44 |
45 | // When
46 | Animator.perform(configuration: sut)
47 |
48 | // Then
49 | XCTAssertNotNil(animationProvider.callParameters)
50 | XCTAssert(animationCalled)
51 | waitForExpectations(timeout: 1, handler: nil)
52 | }
53 |
54 | func testThatAnAdditionalCompletionCanBeAddedToAnAnimationConfiguration() {
55 | // Given
56 | animationProvider.callPassedInClosures = true
57 | let animation = TestAnimation()
58 | let completion = TestCompletion()
59 | var sut = testConfiguration(animation.closure, completion: completion.closure)
60 |
61 | // When
62 | let secondCompletion = TestCompletion()
63 | sut.add(completion: secondCompletion.closure)
64 |
65 | Animator.perform(configuration: sut)
66 |
67 | // Then
68 | XCTAssertEqual(animation.callCount, 1)
69 | XCTAssertEqual(completion.callCount, 1)
70 | XCTAssertEqual(secondCompletion.callCount, 1)
71 | }
72 |
73 | func testThatAdditionalCompletionsCanBeAddedToAnAnimationConfiguration() {
74 | // Given
75 | animationProvider.callPassedInClosures = true
76 | let animation = TestAnimation()
77 | let completion = TestCompletion()
78 | var sut = testConfiguration(animation.closure, completion: completion.closure)
79 |
80 | // When
81 | let secondCompletion = TestCompletion()
82 | let thirdCompletion = TestCompletion()
83 | sut.add(completion: secondCompletion.closure)
84 | sut.add(completion: thirdCompletion.closure)
85 |
86 | Animator.perform(configuration: sut)
87 |
88 | // Then
89 | XCTAssertEqual(animation.callCount, 1)
90 | XCTAssertEqual(completion.callCount, 1)
91 | XCTAssertEqual(secondCompletion.callCount, 1)
92 | XCTAssertEqual(thirdCompletion.callCount, 1)
93 | }
94 |
95 | }
96 |
--------------------------------------------------------------------------------
/ChainedAnimation.xcodeproj/xcshareddata/xcschemes/ChainedAnimation.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
31 |
32 |
34 |
40 |
41 |
42 |
43 |
44 |
50 |
51 |
52 |
53 |
54 |
55 |
65 |
66 |
72 |
73 |
74 |
75 |
76 |
77 |
83 |
84 |
90 |
91 |
92 |
93 |
95 |
96 |
99 |
100 |
101 |
--------------------------------------------------------------------------------
/ChainedAnimationExample/ViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 06/21/2015.
6 | // Copyright (c) 06/21/2015 Silvan Dähn. All rights reserved.
7 | //
8 |
9 |
10 | import UIKit
11 | import ChainedAnimation
12 |
13 |
14 | class ViewController: UIViewController {
15 |
16 | var displayImageView = UIImageView()
17 | var phone = UIView()
18 | var subheader = UILabel()
19 | var headline = UILabel()
20 | var firstSection = UIView()
21 | var secondSection = UIView()
22 | var thirdSection = UIView()
23 | var fourthSection = UIView()
24 | let sectionOffset: CGFloat = 40
25 |
26 | override func viewDidAppear(_ animated: Bool) {
27 | super.viewDidAppear(animated)
28 | let delay = DispatchTime.now() + Double(Int64(1 * Double(NSEC_PER_SEC))) / Double(NSEC_PER_SEC)
29 | DispatchQueue.main.asyncAfter(deadline: delay) {
30 | self.startAnimation()
31 | }
32 | }
33 |
34 | // MARK: - Layout
35 |
36 | override func viewDidLayoutSubviews() {
37 | layoutPhoneAndDisplay()
38 | layoutSections()
39 | layoutSubheader()
40 | layoutHeadline()
41 | super.viewDidLayoutSubviews()
42 | }
43 |
44 | func layoutPhoneAndDisplay() {
45 | phone.frame = view.bounds.insetBy(dx: 60, dy: 60)
46 | phone.outline(cornerRadius: 40)
47 | phone.y = view.height
48 |
49 | displayImageView.frame = phone.bounds.insetBy(dx: 10, dy: 60)
50 | displayImageView.outline()
51 | displayImageView.backgroundColor = .groupTableViewBackground
52 | phone.addSubview(displayImageView)
53 | view.addSubview(phone)
54 | }
55 |
56 | func layoutSections() {
57 | let sectionPadding: CGFloat = 15.0
58 | let sectionHeight = (displayImageView.height - sectionPadding * 5) / 4.0
59 | let sectionFrame = displayImageView.bounds.insetBy(dx: sectionPadding, dy: displayImageView.height / 2.5)
60 | var currentY = sectionPadding
61 |
62 | for view in [firstSection, secondSection, thirdSection, fourthSection] {
63 | view.frame = sectionFrame
64 | view.y = currentY + sectionOffset
65 | view.backgroundColor = .white
66 | currentY += sectionHeight + sectionPadding
67 | view.alpha = 0
68 | displayImageView.addSubview(view)
69 | }
70 | }
71 |
72 | func layoutSubheader() {
73 | subheader.text = "This is an example application."
74 | subheader.font = UIFont(name: "Avenir Next", size: 18)
75 | subheader.textColor = .black
76 | subheader.sizeToFit()
77 | subheader.center = view.center
78 | subheader.y = 0
79 | subheader.alpha = 0
80 | view.addSubview(subheader)
81 | }
82 |
83 | func layoutHeadline() {
84 | headline.text = "Welcome!"
85 | headline.font = UIFont(name: "AvenirNext-UltraLight", size: 42)
86 | headline.textColor = .black
87 | headline.sizeToFit()
88 | headline.center = view.center
89 | headline.y = 0
90 | headline.alpha = 0
91 | view.addSubview(headline)
92 | }
93 |
94 | // MARK: - Animation
95 |
96 | func startAnimation() {
97 | let moveAndFadeIn: (UIView) -> Void = { section in
98 | section.alpha = 1
99 | section.y -= self.sectionOffset
100 | }
101 |
102 | let moveAndFadeOut: (UIView) -> Void = { view in
103 | view.alpha = 0
104 | view.transform = CGAffineTransform(scaleX: 0.98, y: 0.98)
105 | }
106 |
107 | UIView.beginAnimationChain(0.8, options: .curveEaseInOut) {
108 | self.phone.y = 170
109 | }.thenAfterStart(0.1) {
110 | self.subheader.y = 105
111 | moveAndFadeIn(self.firstSection)
112 | }.thenAfterStart(0.15) {
113 | moveAndFadeIn(self.secondSection)
114 | self.subheader.alpha = 1
115 | self.headline.y = 45
116 | }.thenAfterStart(0.1) {
117 | moveAndFadeIn(self.thirdSection)
118 | self.headline.alpha = 1
119 | }.thenAfterStart(0.1) {
120 | moveAndFadeIn(self.fourthSection)
121 | }.completion { _ in
122 | print("First completion")
123 | }.chainAfterCompletion(1.2, delay: 0.5, options: .curveEaseIn) {
124 | moveAndFadeOut(self.displayImageView)
125 | moveAndFadeOut(self.phone)
126 | }.thenAfterStart(0.2) {
127 | moveAndFadeOut(self.headline)
128 | }.thenAfterStart(0.1) {
129 | moveAndFadeOut(self.subheader)
130 | }.completion { _ in
131 | print("Second completion")
132 | }.animate()
133 | }
134 | }
135 |
--------------------------------------------------------------------------------
/ChainedAnimation/AnimationChain.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ChainedAnimation.swift
3 | // ChainedAnimation
4 | //
5 | // Created by Silvan Dähn on 10/09/2016.
6 | // Copyright © 2016 Silvan Dähn. All rights reserved.
7 | //
8 |
9 | public struct AnimationChain {
10 |
11 | let options: UIView.AnimationOptions
12 | var animations: [[AnimationConfiguration]]
13 | var currentOffset: TimeInterval
14 |
15 | init(options: UIView.AnimationOptions, animations: [[AnimationConfiguration]], currentOffset : TimeInterval = 0) {
16 | self.options = options
17 | self.animations = animations
18 | self.currentOffset = currentOffset
19 | }
20 |
21 | /**
22 | Appends a new animation closure to the current chain with the given offset and
23 | returns a new `AnimationChain` constiting of all `BoxedAnimations`.
24 |
25 | - parameter offset The offset of execution in seconds after the previous animation.
26 | - parameter animation The animation that should be added with the given ofset.
27 |
28 | - returns A new `AnimationChain` including the added animation.
29 | */
30 | public func thenAfterStart(_ offset: TimeInterval, animation: @escaping Animation) -> AnimationChain {
31 |
32 | var previousAnimations = animations
33 | let previousChain = previousAnimations.removeLast()
34 | let previousDuration = previousChain.last?.duration ?? 0
35 | let previousDelay = previousChain.last?.delay ?? 0
36 | let boxedFunction = AnimationConfiguration(
37 | animation,
38 | duration: previousDuration,
39 | delay: self.currentOffset + offset + previousDelay,
40 | options: options
41 | )
42 | previousAnimations.append(previousChain + [boxedFunction])
43 | return AnimationChain(options: options, animations: previousAnimations, currentOffset: currentOffset + offset)
44 | }
45 |
46 | /**
47 | Appends a completion closure to the current chain and returns the
48 | new chain. The completion closure will be executed after the animation in the
49 | closure before was executed.
50 |
51 | - parameter completion The closure that will be executed after the animation before completed.
52 |
53 | - return A new `AnimationChain` with the added completion closure.
54 | **/
55 | public func completion(_ completion: @escaping Completion) -> AnimationChain {
56 |
57 | var previousAnimations = animations
58 | var lastChain = previousAnimations.removeLast()
59 | let lastAnimation = lastChain.removeLast()
60 | let boxedFunction = AnimationConfiguration(
61 | lastAnimation.animation,
62 | duration: lastAnimation.duration,
63 | delay: lastAnimation.delay,
64 | completion: completion
65 | )
66 | let newChain = lastChain + [boxedFunction]
67 | previousAnimations.append(newChain)
68 | return AnimationChain(options: options, animations: previousAnimations)
69 | }
70 |
71 | /**
72 | Starts a new animation chain after the previous one completed.
73 | This is useful if you want another set of sequential animations to start after a previous one.
74 | Each chain can have an own completion closure.
75 | The appended chain will start executing together with the completion closure of the previous one.
76 |
77 | - parameter duration The duration that will be used for all animations added to the `AnimationChain`.
78 | - parameter delay The delay before the execution of the first animation in the chain, default to 0.
79 | - parameter options The `UIViewAnimationOptions` that will be used for every animation in the chain, default is nil.
80 | - parameter animations The animations that should be executed first in the chain.
81 |
82 | - return A new `AnimationChain` with the new chain appended.
83 | **/
84 | public func chainAfterCompletion(
85 | _ duration: TimeInterval,
86 | delay: TimeInterval = 0,
87 | options: UIView.AnimationOptions = [],
88 | animations newAnimations: @escaping Animation
89 | ) -> AnimationChain {
90 |
91 | let boxedFunction = AnimationConfiguration(newAnimations, duration: duration, delay: delay, options: options)
92 | let newChain = animations + [[boxedFunction]]
93 | return AnimationChain(options: options, animations: newChain)
94 | }
95 |
96 | /**
97 | Starts the animation of all animations in the current chain.
98 | Calls the completion closures added to individual chains after their completion.
99 | **/
100 | public func animate() {
101 |
102 | var animationChains: [[AnimationConfiguration]] = []
103 | if animations.count > 1 {
104 | stride(from: animations.count - 1, to: 0, by: -1).forEach { index in
105 | var (current, previous) = (animations[index], animations[index-1])
106 | let lastBox = previous.removeLast()
107 | let wrappedAnimations = wrap(configurations: current, inCompletionOf: lastBox)
108 | previous.append(wrappedAnimations)
109 | animationChains.insert(previous, at: 0)
110 | }
111 | } else {
112 | animationChains = animations
113 | }
114 |
115 | for chain in animationChains {
116 | chain.forEach(Animator.perform)
117 | }
118 | }
119 |
120 | private func wrap(configurations: [AnimationConfiguration], inCompletionOf configuration: AnimationConfiguration) -> AnimationConfiguration {
121 | var completionConfiguration = configuration
122 | completionConfiguration.add { _ in
123 | configurations.forEach(Animator.perform)
124 | }
125 |
126 | return completionConfiguration
127 | }
128 | }
129 |
130 | extension UIView {
131 |
132 | /**
133 | Used to start a new `AnimationChain`.
134 | More animations can be added by calling `-thenAfter` on the return value.
135 | A completion closure can be added by calling `-completion` on the return value.
136 | All animations will be executed after calling `-animate`.
137 |
138 | - parameter duration The duration that will be used for all animations added to the `AnimationChain`.
139 | - parameter delay The delay before the execution of the first animation in the chain, default to 0.
140 | - parameter options The `UIViewAnimationOptions` that will be used for every animation in the chain, default is nil.
141 | - parameter animations The animations that should be executed first in the chain.
142 |
143 | - return A new `AnimationChain` with the added animation.
144 | **/
145 | public class func beginAnimationChain(
146 | _ duration: TimeInterval,
147 | delay: TimeInterval = 0,
148 | options: UIView.AnimationOptions = [],
149 | animations: @escaping Animation
150 | ) -> AnimationChain {
151 |
152 | let boxedFunction = AnimationConfiguration(animations, duration: duration, delay: delay, options: options)
153 | return AnimationChain(options: options, animations: [[boxedFunction]])
154 | }
155 | }
156 |
157 |
158 |
159 |
--------------------------------------------------------------------------------
/ChainedAnimation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | AF6A02501D84204900F89BD9 /* ChainedAnimation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF6A02461D84204900F89BD9 /* ChainedAnimation.framework */; };
11 | AF6A02551D84204900F89BD9 /* ChainedAnimationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF6A02541D84204900F89BD9 /* ChainedAnimationTests.swift */; };
12 | AF6A02571D84204900F89BD9 /* ChainedAnimation.h in Headers */ = {isa = PBXBuildFile; fileRef = AF6A02491D84204900F89BD9 /* ChainedAnimation.h */; settings = {ATTRIBUTES = (Public, ); }; };
13 | AF6A02611D84205400F89BD9 /* AnimationChain.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF6A02601D84205400F89BD9 /* AnimationChain.swift */; };
14 | AF6A02631D84265700F89BD9 /* MockAnimationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF6A02621D84265700F89BD9 /* MockAnimationProvider.swift */; };
15 | AF79A3C11D8430C50060857F /* AnimationConfigurationTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3C01D8430C50060857F /* AnimationConfigurationTests.swift */; };
16 | AF79A3C31D8431100060857F /* ChainedAnimationTestCase.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3C21D8431100060857F /* ChainedAnimationTestCase.swift */; };
17 | AF79A3C51D8438090060857F /* AnimationProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3C41D8438090060857F /* AnimationProvider.swift */; };
18 | AF79A3C71D8438410060857F /* Animator.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3C61D8438410060857F /* Animator.swift */; };
19 | AF79A3C91D8438770060857F /* AnimationConfiguration.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3C81D8438770060857F /* AnimationConfiguration.swift */; };
20 | AF79A3CB1D8438F60060857F /* Types.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3CA1D8438F60060857F /* Types.swift */; };
21 | AF79A3D31D843C0E0060857F /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3D21D843C0E0060857F /* AppDelegate.swift */; };
22 | AF79A3D51D843C0E0060857F /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3D41D843C0E0060857F /* ViewController.swift */; };
23 | AF79A3D81D843C0E0060857F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AF79A3D61D843C0E0060857F /* Main.storyboard */; };
24 | AF79A3DA1D843C0E0060857F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = AF79A3D91D843C0E0060857F /* Assets.xcassets */; };
25 | AF79A3DD1D843C0E0060857F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = AF79A3DB1D843C0E0060857F /* LaunchScreen.storyboard */; };
26 | AF79A3E31D843C450060857F /* UIView+Helper.swift in Sources */ = {isa = PBXBuildFile; fileRef = AF79A3E21D843C450060857F /* UIView+Helper.swift */; };
27 | AF79A3E41D843D2B0060857F /* ChainedAnimation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = AF6A02461D84204900F89BD9 /* ChainedAnimation.framework */; };
28 | AF79A3E51D843D2B0060857F /* ChainedAnimation.framework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = AF6A02461D84204900F89BD9 /* ChainedAnimation.framework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
29 | /* End PBXBuildFile section */
30 |
31 | /* Begin PBXContainerItemProxy section */
32 | AF6A02511D84204900F89BD9 /* PBXContainerItemProxy */ = {
33 | isa = PBXContainerItemProxy;
34 | containerPortal = AF6A023D1D84204900F89BD9 /* Project object */;
35 | proxyType = 1;
36 | remoteGlobalIDString = AF6A02451D84204900F89BD9;
37 | remoteInfo = ChainedAnimation;
38 | };
39 | AF79A3E61D843D2B0060857F /* PBXContainerItemProxy */ = {
40 | isa = PBXContainerItemProxy;
41 | containerPortal = AF6A023D1D84204900F89BD9 /* Project object */;
42 | proxyType = 1;
43 | remoteGlobalIDString = AF6A02451D84204900F89BD9;
44 | remoteInfo = ChainedAnimation;
45 | };
46 | /* End PBXContainerItemProxy section */
47 |
48 | /* Begin PBXCopyFilesBuildPhase section */
49 | AF79A3E81D843D2B0060857F /* Embed Frameworks */ = {
50 | isa = PBXCopyFilesBuildPhase;
51 | buildActionMask = 2147483647;
52 | dstPath = "";
53 | dstSubfolderSpec = 10;
54 | files = (
55 | AF79A3E51D843D2B0060857F /* ChainedAnimation.framework in Embed Frameworks */,
56 | );
57 | name = "Embed Frameworks";
58 | runOnlyForDeploymentPostprocessing = 0;
59 | };
60 | /* End PBXCopyFilesBuildPhase section */
61 |
62 | /* Begin PBXFileReference section */
63 | AF6A02461D84204900F89BD9 /* ChainedAnimation.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; includeInIndex = 0; path = ChainedAnimation.framework; sourceTree = BUILT_PRODUCTS_DIR; };
64 | AF6A02491D84204900F89BD9 /* ChainedAnimation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ChainedAnimation.h; sourceTree = ""; };
65 | AF6A024A1D84204900F89BD9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
66 | AF6A024F1D84204900F89BD9 /* ChainedAnimationTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = ChainedAnimationTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; };
67 | AF6A02541D84204900F89BD9 /* ChainedAnimationTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ChainedAnimationTests.swift; sourceTree = ""; };
68 | AF6A02561D84204900F89BD9 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
69 | AF6A02601D84205400F89BD9 /* AnimationChain.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationChain.swift; sourceTree = ""; };
70 | AF6A02621D84265700F89BD9 /* MockAnimationProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = MockAnimationProvider.swift; sourceTree = ""; };
71 | AF79A3C01D8430C50060857F /* AnimationConfigurationTests.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationConfigurationTests.swift; sourceTree = ""; };
72 | AF79A3C21D8431100060857F /* ChainedAnimationTestCase.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ChainedAnimationTestCase.swift; sourceTree = ""; };
73 | AF79A3C41D8438090060857F /* AnimationProvider.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationProvider.swift; sourceTree = ""; };
74 | AF79A3C61D8438410060857F /* Animator.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Animator.swift; sourceTree = ""; };
75 | AF79A3C81D8438770060857F /* AnimationConfiguration.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AnimationConfiguration.swift; sourceTree = ""; };
76 | AF79A3CA1D8438F60060857F /* Types.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Types.swift; sourceTree = ""; };
77 | AF79A3D01D843C0E0060857F /* ChainedAnimationExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ChainedAnimationExample.app; sourceTree = BUILT_PRODUCTS_DIR; };
78 | AF79A3D21D843C0E0060857F /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; };
79 | AF79A3D41D843C0E0060857F /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; };
80 | AF79A3D71D843C0E0060857F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
81 | AF79A3D91D843C0E0060857F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
82 | AF79A3DC1D843C0E0060857F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
83 | AF79A3DE1D843C0E0060857F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
84 | AF79A3E21D843C450060857F /* UIView+Helper.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = "UIView+Helper.swift"; sourceTree = ""; };
85 | /* End PBXFileReference section */
86 |
87 | /* Begin PBXFrameworksBuildPhase section */
88 | AF6A02421D84204900F89BD9 /* Frameworks */ = {
89 | isa = PBXFrameworksBuildPhase;
90 | buildActionMask = 2147483647;
91 | files = (
92 | );
93 | runOnlyForDeploymentPostprocessing = 0;
94 | };
95 | AF6A024C1D84204900F89BD9 /* Frameworks */ = {
96 | isa = PBXFrameworksBuildPhase;
97 | buildActionMask = 2147483647;
98 | files = (
99 | AF6A02501D84204900F89BD9 /* ChainedAnimation.framework in Frameworks */,
100 | );
101 | runOnlyForDeploymentPostprocessing = 0;
102 | };
103 | AF79A3CD1D843C0E0060857F /* Frameworks */ = {
104 | isa = PBXFrameworksBuildPhase;
105 | buildActionMask = 2147483647;
106 | files = (
107 | AF79A3E41D843D2B0060857F /* ChainedAnimation.framework in Frameworks */,
108 | );
109 | runOnlyForDeploymentPostprocessing = 0;
110 | };
111 | /* End PBXFrameworksBuildPhase section */
112 |
113 | /* Begin PBXGroup section */
114 | AF6A023C1D84204900F89BD9 = {
115 | isa = PBXGroup;
116 | children = (
117 | AF6A02481D84204900F89BD9 /* ChainedAnimation */,
118 | AF6A02531D84204900F89BD9 /* ChainedAnimationTests */,
119 | AF79A3D11D843C0E0060857F /* ChainedAnimationExample */,
120 | AF6A02471D84204900F89BD9 /* Products */,
121 | );
122 | sourceTree = "";
123 | };
124 | AF6A02471D84204900F89BD9 /* Products */ = {
125 | isa = PBXGroup;
126 | children = (
127 | AF6A02461D84204900F89BD9 /* ChainedAnimation.framework */,
128 | AF6A024F1D84204900F89BD9 /* ChainedAnimationTests.xctest */,
129 | AF79A3D01D843C0E0060857F /* ChainedAnimationExample.app */,
130 | );
131 | name = Products;
132 | sourceTree = "";
133 | };
134 | AF6A02481D84204900F89BD9 /* ChainedAnimation */ = {
135 | isa = PBXGroup;
136 | children = (
137 | AF6A02491D84204900F89BD9 /* ChainedAnimation.h */,
138 | AF6A02601D84205400F89BD9 /* AnimationChain.swift */,
139 | AF79A3CA1D8438F60060857F /* Types.swift */,
140 | AF79A3C81D8438770060857F /* AnimationConfiguration.swift */,
141 | AF79A3C61D8438410060857F /* Animator.swift */,
142 | AF79A3C41D8438090060857F /* AnimationProvider.swift */,
143 | AF6A024A1D84204900F89BD9 /* Info.plist */,
144 | );
145 | path = ChainedAnimation;
146 | sourceTree = "";
147 | };
148 | AF6A02531D84204900F89BD9 /* ChainedAnimationTests */ = {
149 | isa = PBXGroup;
150 | children = (
151 | AF6A02541D84204900F89BD9 /* ChainedAnimationTests.swift */,
152 | AF79A3C21D8431100060857F /* ChainedAnimationTestCase.swift */,
153 | AF79A3C01D8430C50060857F /* AnimationConfigurationTests.swift */,
154 | AF6A02621D84265700F89BD9 /* MockAnimationProvider.swift */,
155 | AF6A02561D84204900F89BD9 /* Info.plist */,
156 | );
157 | path = ChainedAnimationTests;
158 | sourceTree = "";
159 | };
160 | AF79A3D11D843C0E0060857F /* ChainedAnimationExample */ = {
161 | isa = PBXGroup;
162 | children = (
163 | AF79A3D21D843C0E0060857F /* AppDelegate.swift */,
164 | AF79A3E21D843C450060857F /* UIView+Helper.swift */,
165 | AF79A3D41D843C0E0060857F /* ViewController.swift */,
166 | AF79A3D61D843C0E0060857F /* Main.storyboard */,
167 | AF79A3D91D843C0E0060857F /* Assets.xcassets */,
168 | AF79A3DB1D843C0E0060857F /* LaunchScreen.storyboard */,
169 | AF79A3DE1D843C0E0060857F /* Info.plist */,
170 | );
171 | path = ChainedAnimationExample;
172 | sourceTree = "";
173 | };
174 | /* End PBXGroup section */
175 |
176 | /* Begin PBXHeadersBuildPhase section */
177 | AF6A02431D84204900F89BD9 /* Headers */ = {
178 | isa = PBXHeadersBuildPhase;
179 | buildActionMask = 2147483647;
180 | files = (
181 | AF6A02571D84204900F89BD9 /* ChainedAnimation.h in Headers */,
182 | );
183 | runOnlyForDeploymentPostprocessing = 0;
184 | };
185 | /* End PBXHeadersBuildPhase section */
186 |
187 | /* Begin PBXNativeTarget section */
188 | AF6A02451D84204900F89BD9 /* ChainedAnimation */ = {
189 | isa = PBXNativeTarget;
190 | buildConfigurationList = AF6A025A1D84204900F89BD9 /* Build configuration list for PBXNativeTarget "ChainedAnimation" */;
191 | buildPhases = (
192 | AF6A02411D84204900F89BD9 /* Sources */,
193 | AF6A02421D84204900F89BD9 /* Frameworks */,
194 | AF6A02431D84204900F89BD9 /* Headers */,
195 | AF6A02441D84204900F89BD9 /* Resources */,
196 | );
197 | buildRules = (
198 | );
199 | dependencies = (
200 | );
201 | name = ChainedAnimation;
202 | productName = ChainedAnimation;
203 | productReference = AF6A02461D84204900F89BD9 /* ChainedAnimation.framework */;
204 | productType = "com.apple.product-type.framework";
205 | };
206 | AF6A024E1D84204900F89BD9 /* ChainedAnimationTests */ = {
207 | isa = PBXNativeTarget;
208 | buildConfigurationList = AF6A025D1D84204900F89BD9 /* Build configuration list for PBXNativeTarget "ChainedAnimationTests" */;
209 | buildPhases = (
210 | AF6A024B1D84204900F89BD9 /* Sources */,
211 | AF6A024C1D84204900F89BD9 /* Frameworks */,
212 | AF6A024D1D84204900F89BD9 /* Resources */,
213 | );
214 | buildRules = (
215 | );
216 | dependencies = (
217 | AF6A02521D84204900F89BD9 /* PBXTargetDependency */,
218 | );
219 | name = ChainedAnimationTests;
220 | productName = ChainedAnimationTests;
221 | productReference = AF6A024F1D84204900F89BD9 /* ChainedAnimationTests.xctest */;
222 | productType = "com.apple.product-type.bundle.unit-test";
223 | };
224 | AF79A3CF1D843C0E0060857F /* ChainedAnimationExample */ = {
225 | isa = PBXNativeTarget;
226 | buildConfigurationList = AF79A3E11D843C0E0060857F /* Build configuration list for PBXNativeTarget "ChainedAnimationExample" */;
227 | buildPhases = (
228 | AF79A3CC1D843C0E0060857F /* Sources */,
229 | AF79A3CD1D843C0E0060857F /* Frameworks */,
230 | AF79A3CE1D843C0E0060857F /* Resources */,
231 | AF79A3E81D843D2B0060857F /* Embed Frameworks */,
232 | );
233 | buildRules = (
234 | );
235 | dependencies = (
236 | AF79A3E71D843D2B0060857F /* PBXTargetDependency */,
237 | );
238 | name = ChainedAnimationExample;
239 | productName = ChainedAnimationExample;
240 | productReference = AF79A3D01D843C0E0060857F /* ChainedAnimationExample.app */;
241 | productType = "com.apple.product-type.application";
242 | };
243 | /* End PBXNativeTarget section */
244 |
245 | /* Begin PBXProject section */
246 | AF6A023D1D84204900F89BD9 /* Project object */ = {
247 | isa = PBXProject;
248 | attributes = {
249 | LastSwiftUpdateCheck = 0800;
250 | LastUpgradeCheck = 1000;
251 | ORGANIZATIONNAME = "Silvan Dähn";
252 | TargetAttributes = {
253 | AF6A02451D84204900F89BD9 = {
254 | CreatedOnToolsVersion = 8.0;
255 | LastSwiftMigration = 1000;
256 | ProvisioningStyle = Automatic;
257 | };
258 | AF6A024E1D84204900F89BD9 = {
259 | CreatedOnToolsVersion = 8.0;
260 | LastSwiftMigration = 1000;
261 | ProvisioningStyle = Automatic;
262 | };
263 | AF79A3CF1D843C0E0060857F = {
264 | CreatedOnToolsVersion = 8.0;
265 | LastSwiftMigration = 0900;
266 | ProvisioningStyle = Automatic;
267 | };
268 | };
269 | };
270 | buildConfigurationList = AF6A02401D84204900F89BD9 /* Build configuration list for PBXProject "ChainedAnimation" */;
271 | compatibilityVersion = "Xcode 3.2";
272 | developmentRegion = English;
273 | hasScannedForEncodings = 0;
274 | knownRegions = (
275 | en,
276 | Base,
277 | );
278 | mainGroup = AF6A023C1D84204900F89BD9;
279 | productRefGroup = AF6A02471D84204900F89BD9 /* Products */;
280 | projectDirPath = "";
281 | projectRoot = "";
282 | targets = (
283 | AF6A02451D84204900F89BD9 /* ChainedAnimation */,
284 | AF6A024E1D84204900F89BD9 /* ChainedAnimationTests */,
285 | AF79A3CF1D843C0E0060857F /* ChainedAnimationExample */,
286 | );
287 | };
288 | /* End PBXProject section */
289 |
290 | /* Begin PBXResourcesBuildPhase section */
291 | AF6A02441D84204900F89BD9 /* Resources */ = {
292 | isa = PBXResourcesBuildPhase;
293 | buildActionMask = 2147483647;
294 | files = (
295 | );
296 | runOnlyForDeploymentPostprocessing = 0;
297 | };
298 | AF6A024D1D84204900F89BD9 /* Resources */ = {
299 | isa = PBXResourcesBuildPhase;
300 | buildActionMask = 2147483647;
301 | files = (
302 | );
303 | runOnlyForDeploymentPostprocessing = 0;
304 | };
305 | AF79A3CE1D843C0E0060857F /* Resources */ = {
306 | isa = PBXResourcesBuildPhase;
307 | buildActionMask = 2147483647;
308 | files = (
309 | AF79A3DD1D843C0E0060857F /* LaunchScreen.storyboard in Resources */,
310 | AF79A3DA1D843C0E0060857F /* Assets.xcassets in Resources */,
311 | AF79A3D81D843C0E0060857F /* Main.storyboard in Resources */,
312 | );
313 | runOnlyForDeploymentPostprocessing = 0;
314 | };
315 | /* End PBXResourcesBuildPhase section */
316 |
317 | /* Begin PBXSourcesBuildPhase section */
318 | AF6A02411D84204900F89BD9 /* Sources */ = {
319 | isa = PBXSourcesBuildPhase;
320 | buildActionMask = 2147483647;
321 | files = (
322 | AF79A3C71D8438410060857F /* Animator.swift in Sources */,
323 | AF6A02611D84205400F89BD9 /* AnimationChain.swift in Sources */,
324 | AF79A3C51D8438090060857F /* AnimationProvider.swift in Sources */,
325 | AF79A3CB1D8438F60060857F /* Types.swift in Sources */,
326 | AF79A3C91D8438770060857F /* AnimationConfiguration.swift in Sources */,
327 | );
328 | runOnlyForDeploymentPostprocessing = 0;
329 | };
330 | AF6A024B1D84204900F89BD9 /* Sources */ = {
331 | isa = PBXSourcesBuildPhase;
332 | buildActionMask = 2147483647;
333 | files = (
334 | AF79A3C31D8431100060857F /* ChainedAnimationTestCase.swift in Sources */,
335 | AF79A3C11D8430C50060857F /* AnimationConfigurationTests.swift in Sources */,
336 | AF6A02551D84204900F89BD9 /* ChainedAnimationTests.swift in Sources */,
337 | AF6A02631D84265700F89BD9 /* MockAnimationProvider.swift in Sources */,
338 | );
339 | runOnlyForDeploymentPostprocessing = 0;
340 | };
341 | AF79A3CC1D843C0E0060857F /* Sources */ = {
342 | isa = PBXSourcesBuildPhase;
343 | buildActionMask = 2147483647;
344 | files = (
345 | AF79A3D51D843C0E0060857F /* ViewController.swift in Sources */,
346 | AF79A3E31D843C450060857F /* UIView+Helper.swift in Sources */,
347 | AF79A3D31D843C0E0060857F /* AppDelegate.swift in Sources */,
348 | );
349 | runOnlyForDeploymentPostprocessing = 0;
350 | };
351 | /* End PBXSourcesBuildPhase section */
352 |
353 | /* Begin PBXTargetDependency section */
354 | AF6A02521D84204900F89BD9 /* PBXTargetDependency */ = {
355 | isa = PBXTargetDependency;
356 | target = AF6A02451D84204900F89BD9 /* ChainedAnimation */;
357 | targetProxy = AF6A02511D84204900F89BD9 /* PBXContainerItemProxy */;
358 | };
359 | AF79A3E71D843D2B0060857F /* PBXTargetDependency */ = {
360 | isa = PBXTargetDependency;
361 | target = AF6A02451D84204900F89BD9 /* ChainedAnimation */;
362 | targetProxy = AF79A3E61D843D2B0060857F /* PBXContainerItemProxy */;
363 | };
364 | /* End PBXTargetDependency section */
365 |
366 | /* Begin PBXVariantGroup section */
367 | AF79A3D61D843C0E0060857F /* Main.storyboard */ = {
368 | isa = PBXVariantGroup;
369 | children = (
370 | AF79A3D71D843C0E0060857F /* Base */,
371 | );
372 | name = Main.storyboard;
373 | sourceTree = "";
374 | };
375 | AF79A3DB1D843C0E0060857F /* LaunchScreen.storyboard */ = {
376 | isa = PBXVariantGroup;
377 | children = (
378 | AF79A3DC1D843C0E0060857F /* Base */,
379 | );
380 | name = LaunchScreen.storyboard;
381 | sourceTree = "";
382 | };
383 | /* End PBXVariantGroup section */
384 |
385 | /* Begin XCBuildConfiguration section */
386 | AF6A02581D84204900F89BD9 /* Debug */ = {
387 | isa = XCBuildConfiguration;
388 | buildSettings = {
389 | ALWAYS_SEARCH_USER_PATHS = NO;
390 | CLANG_ANALYZER_NONNULL = YES;
391 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
392 | CLANG_CXX_LIBRARY = "libc++";
393 | CLANG_ENABLE_MODULES = YES;
394 | CLANG_ENABLE_OBJC_ARC = YES;
395 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
396 | CLANG_WARN_BOOL_CONVERSION = YES;
397 | CLANG_WARN_COMMA = YES;
398 | CLANG_WARN_CONSTANT_CONVERSION = YES;
399 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
400 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
401 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
402 | CLANG_WARN_EMPTY_BODY = YES;
403 | CLANG_WARN_ENUM_CONVERSION = YES;
404 | CLANG_WARN_INFINITE_RECURSION = YES;
405 | CLANG_WARN_INT_CONVERSION = YES;
406 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
407 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
408 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
409 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
410 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
411 | CLANG_WARN_STRICT_PROTOTYPES = YES;
412 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
413 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
414 | CLANG_WARN_UNREACHABLE_CODE = YES;
415 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
416 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
417 | COPY_PHASE_STRIP = NO;
418 | CURRENT_PROJECT_VERSION = 1;
419 | DEBUG_INFORMATION_FORMAT = dwarf;
420 | ENABLE_STRICT_OBJC_MSGSEND = YES;
421 | ENABLE_TESTABILITY = YES;
422 | GCC_C_LANGUAGE_STANDARD = gnu99;
423 | GCC_DYNAMIC_NO_PIC = NO;
424 | GCC_NO_COMMON_BLOCKS = YES;
425 | GCC_OPTIMIZATION_LEVEL = 0;
426 | GCC_PREPROCESSOR_DEFINITIONS = (
427 | "DEBUG=1",
428 | "$(inherited)",
429 | );
430 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
431 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
432 | GCC_WARN_UNDECLARED_SELECTOR = YES;
433 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
434 | GCC_WARN_UNUSED_FUNCTION = YES;
435 | GCC_WARN_UNUSED_VARIABLE = YES;
436 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
437 | MTL_ENABLE_DEBUG_INFO = YES;
438 | ONLY_ACTIVE_ARCH = YES;
439 | SDKROOT = iphoneos;
440 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG;
441 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
442 | SWIFT_VERSION = 4.0;
443 | TARGETED_DEVICE_FAMILY = "1,2";
444 | VERSIONING_SYSTEM = "apple-generic";
445 | VERSION_INFO_PREFIX = "";
446 | };
447 | name = Debug;
448 | };
449 | AF6A02591D84204900F89BD9 /* Release */ = {
450 | isa = XCBuildConfiguration;
451 | buildSettings = {
452 | ALWAYS_SEARCH_USER_PATHS = NO;
453 | CLANG_ANALYZER_NONNULL = YES;
454 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
455 | CLANG_CXX_LIBRARY = "libc++";
456 | CLANG_ENABLE_MODULES = YES;
457 | CLANG_ENABLE_OBJC_ARC = YES;
458 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES;
459 | CLANG_WARN_BOOL_CONVERSION = YES;
460 | CLANG_WARN_COMMA = YES;
461 | CLANG_WARN_CONSTANT_CONVERSION = YES;
462 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES;
463 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
464 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES;
465 | CLANG_WARN_EMPTY_BODY = YES;
466 | CLANG_WARN_ENUM_CONVERSION = YES;
467 | CLANG_WARN_INFINITE_RECURSION = YES;
468 | CLANG_WARN_INT_CONVERSION = YES;
469 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES;
470 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES;
471 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES;
472 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
473 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES;
474 | CLANG_WARN_STRICT_PROTOTYPES = YES;
475 | CLANG_WARN_SUSPICIOUS_MOVE = YES;
476 | CLANG_WARN_SUSPICIOUS_MOVES = YES;
477 | CLANG_WARN_UNREACHABLE_CODE = YES;
478 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
479 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
480 | COPY_PHASE_STRIP = NO;
481 | CURRENT_PROJECT_VERSION = 1;
482 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
483 | ENABLE_NS_ASSERTIONS = NO;
484 | ENABLE_STRICT_OBJC_MSGSEND = YES;
485 | GCC_C_LANGUAGE_STANDARD = gnu99;
486 | GCC_NO_COMMON_BLOCKS = YES;
487 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
488 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
489 | GCC_WARN_UNDECLARED_SELECTOR = YES;
490 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
491 | GCC_WARN_UNUSED_FUNCTION = YES;
492 | GCC_WARN_UNUSED_VARIABLE = YES;
493 | IPHONEOS_DEPLOYMENT_TARGET = 10.0;
494 | MTL_ENABLE_DEBUG_INFO = NO;
495 | SDKROOT = iphoneos;
496 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule";
497 | SWIFT_VERSION = 4.0;
498 | TARGETED_DEVICE_FAMILY = "1,2";
499 | VALIDATE_PRODUCT = YES;
500 | VERSIONING_SYSTEM = "apple-generic";
501 | VERSION_INFO_PREFIX = "";
502 | };
503 | name = Release;
504 | };
505 | AF6A025B1D84204900F89BD9 /* Debug */ = {
506 | isa = XCBuildConfiguration;
507 | buildSettings = {
508 | CLANG_ENABLE_MODULES = YES;
509 | CODE_SIGN_IDENTITY = "";
510 | DEFINES_MODULE = YES;
511 | DYLIB_COMPATIBILITY_VERSION = 1;
512 | DYLIB_CURRENT_VERSION = 1;
513 | DYLIB_INSTALL_NAME_BASE = "@rpath";
514 | INFOPLIST_FILE = ChainedAnimation/Info.plist;
515 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
516 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
517 | PRODUCT_BUNDLE_IDENTIFIER = com.silvandaehn.ChainedAnimation;
518 | PRODUCT_NAME = "$(TARGET_NAME)";
519 | SKIP_INSTALL = YES;
520 | SWIFT_OPTIMIZATION_LEVEL = "-Onone";
521 | SWIFT_VERSION = 4.2;
522 | };
523 | name = Debug;
524 | };
525 | AF6A025C1D84204900F89BD9 /* Release */ = {
526 | isa = XCBuildConfiguration;
527 | buildSettings = {
528 | CLANG_ENABLE_MODULES = YES;
529 | CODE_SIGN_IDENTITY = "";
530 | DEFINES_MODULE = YES;
531 | DYLIB_COMPATIBILITY_VERSION = 1;
532 | DYLIB_CURRENT_VERSION = 1;
533 | DYLIB_INSTALL_NAME_BASE = "@rpath";
534 | INFOPLIST_FILE = ChainedAnimation/Info.plist;
535 | INSTALL_PATH = "$(LOCAL_LIBRARY_DIR)/Frameworks";
536 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
537 | PRODUCT_BUNDLE_IDENTIFIER = com.silvandaehn.ChainedAnimation;
538 | PRODUCT_NAME = "$(TARGET_NAME)";
539 | SKIP_INSTALL = YES;
540 | SWIFT_VERSION = 4.2;
541 | };
542 | name = Release;
543 | };
544 | AF6A025E1D84204900F89BD9 /* Debug */ = {
545 | isa = XCBuildConfiguration;
546 | buildSettings = {
547 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
548 | INFOPLIST_FILE = ChainedAnimationTests/Info.plist;
549 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
550 | PRODUCT_BUNDLE_IDENTIFIER = com.silvandaehn.ChainedAnimationTests;
551 | PRODUCT_NAME = "$(TARGET_NAME)";
552 | SWIFT_VERSION = 4.2;
553 | };
554 | name = Debug;
555 | };
556 | AF6A025F1D84204900F89BD9 /* Release */ = {
557 | isa = XCBuildConfiguration;
558 | buildSettings = {
559 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
560 | INFOPLIST_FILE = ChainedAnimationTests/Info.plist;
561 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks";
562 | PRODUCT_BUNDLE_IDENTIFIER = com.silvandaehn.ChainedAnimationTests;
563 | PRODUCT_NAME = "$(TARGET_NAME)";
564 | SWIFT_VERSION = 4.2;
565 | };
566 | name = Release;
567 | };
568 | AF79A3DF1D843C0E0060857F /* Debug */ = {
569 | isa = XCBuildConfiguration;
570 | buildSettings = {
571 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
572 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
573 | INFOPLIST_FILE = ChainedAnimationExample/Info.plist;
574 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
575 | PRODUCT_BUNDLE_IDENTIFIER = com.silvandaehn.ChainedAnimationExample;
576 | PRODUCT_NAME = "$(TARGET_NAME)";
577 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
578 | };
579 | name = Debug;
580 | };
581 | AF79A3E01D843C0E0060857F /* Release */ = {
582 | isa = XCBuildConfiguration;
583 | buildSettings = {
584 | ALWAYS_EMBED_SWIFT_STANDARD_LIBRARIES = YES;
585 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
586 | INFOPLIST_FILE = ChainedAnimationExample/Info.plist;
587 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
588 | PRODUCT_BUNDLE_IDENTIFIER = com.silvandaehn.ChainedAnimationExample;
589 | PRODUCT_NAME = "$(TARGET_NAME)";
590 | SWIFT_SWIFT3_OBJC_INFERENCE = Default;
591 | };
592 | name = Release;
593 | };
594 | /* End XCBuildConfiguration section */
595 |
596 | /* Begin XCConfigurationList section */
597 | AF6A02401D84204900F89BD9 /* Build configuration list for PBXProject "ChainedAnimation" */ = {
598 | isa = XCConfigurationList;
599 | buildConfigurations = (
600 | AF6A02581D84204900F89BD9 /* Debug */,
601 | AF6A02591D84204900F89BD9 /* Release */,
602 | );
603 | defaultConfigurationIsVisible = 0;
604 | defaultConfigurationName = Release;
605 | };
606 | AF6A025A1D84204900F89BD9 /* Build configuration list for PBXNativeTarget "ChainedAnimation" */ = {
607 | isa = XCConfigurationList;
608 | buildConfigurations = (
609 | AF6A025B1D84204900F89BD9 /* Debug */,
610 | AF6A025C1D84204900F89BD9 /* Release */,
611 | );
612 | defaultConfigurationIsVisible = 0;
613 | defaultConfigurationName = Release;
614 | };
615 | AF6A025D1D84204900F89BD9 /* Build configuration list for PBXNativeTarget "ChainedAnimationTests" */ = {
616 | isa = XCConfigurationList;
617 | buildConfigurations = (
618 | AF6A025E1D84204900F89BD9 /* Debug */,
619 | AF6A025F1D84204900F89BD9 /* Release */,
620 | );
621 | defaultConfigurationIsVisible = 0;
622 | defaultConfigurationName = Release;
623 | };
624 | AF79A3E11D843C0E0060857F /* Build configuration list for PBXNativeTarget "ChainedAnimationExample" */ = {
625 | isa = XCConfigurationList;
626 | buildConfigurations = (
627 | AF79A3DF1D843C0E0060857F /* Debug */,
628 | AF79A3E01D843C0E0060857F /* Release */,
629 | );
630 | defaultConfigurationIsVisible = 0;
631 | defaultConfigurationName = Release;
632 | };
633 | /* End XCConfigurationList section */
634 | };
635 | rootObject = AF6A023D1D84204900F89BD9 /* Project object */;
636 | }
637 |
--------------------------------------------------------------------------------