├── .gitignore
├── AXAnimationChain-Swift.podspec
├── AXAnimationChain.podspec
├── AXAnimationChain.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcuserdata
│ └── devedbox.xcuserdatad
│ └── xcschemes
│ ├── AXAnimationChain.xcscheme
│ └── xcschememanagement.plist
├── AXAnimationChain
├── AXAnimationChain.modulemap
├── AnimationConvertableViewController.h
├── AnimationConvertableViewController.m
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ ├── Contents.json
│ ├── image1.imageset
│ │ ├── 006k3ED2ly1fbnta30d2rj30k00zkn2n-1.jpg
│ │ ├── 006k3ED2ly1fbnta30d2rj30k00zkn2n.jpg
│ │ └── Contents.json
│ └── image2.imageset
│ │ ├── 006k3ED2ly1fbnta6w64dj30k00zkjwr-1.jpg
│ │ ├── 006k3ED2ly1fbnta6w64dj30k00zkjwr.jpg
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── Classes
│ ├── AXAnimationChain.h
│ ├── AXChainAnimator+Block.h
│ ├── AXChainAnimator+Block.m
│ ├── AXChainAnimator.h
│ ├── AXChainAnimator.m
│ ├── CALayer+AnchorPoint.h
│ ├── CALayer+AnchorPoint.m
│ ├── CoreAnimation
│ │ ├── AXCoreAnimation.h
│ │ ├── AXDecayAnimation.h
│ │ ├── AXDecayAnimation.m
│ │ ├── AXSpringAnimation.h
│ │ ├── AXSpringAnimation.m
│ │ ├── CAAnimation+Convertable.h
│ │ ├── CAAnimation+Convertable.m
│ │ ├── CAAnimation+ImmediateValue.h
│ │ ├── CAAnimation+ImmediateValue.m
│ │ ├── CAMediaTimingFunction+Extends.h
│ │ └── CAMediaTimingFunction+Extends.m
│ ├── Swifty
│ │ ├── AXChainAnimator.swift
│ │ ├── AXCoreAnimations.swift
│ │ ├── UIView+AnimationChain.swift
│ │ └── UIView+Effects.swift
│ ├── UIView+AnimationChain.h
│ ├── UIView+AnimationChain.m
│ ├── UIView+ChainAnimator.h
│ ├── UIView+ChainAnimator.m
│ ├── UIView+Effects.h
│ ├── UIView+Effects.m
│ └── module.modulemap
├── DecayAnimationViewController.swift
├── ImageAnimationViewController.h
├── ImageAnimationViewController.m
├── Info.plist
├── StageAnimationsViewController.swift
├── ViewController.h
├── ViewController.m
└── main.m
├── AXAnimationChainSwift.podspec
├── AXAnimationChainTests
├── AXAnimationChainTests.m
├── ImmediateValueTests.swift
└── Info.plist
├── AXAnimationChainUITests
├── AXAnimationChainUITests.m
└── Info.plist
├── LICENSE
├── README.md
├── _config.yml
├── docs
├── .d
└── AXSpringAnimation.md
└── src
└── img
└── logo.png
/.gitignore:
--------------------------------------------------------------------------------
1 | # Xcode
2 | #
3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore
4 |
5 | ## Build generated
6 | build/
7 | DerivedData/
8 |
9 | ## Various settings
10 | *.pbxuser
11 | !default.pbxuser
12 | *.mode1v3
13 | !default.mode1v3
14 | *.mode2v3
15 | !default.mode2v3
16 | *.perspectivev3
17 | !default.perspectivev3
18 | xcuserdata/
19 |
20 | ## Other
21 | *.moved-aside
22 | *.xcuserstate
23 |
24 | ## Obj-C/Swift specific
25 | *.hmap
26 | *.ipa
27 | *.dSYM.zip
28 | *.dSYM
29 |
30 | # CocoaPods
31 | #
32 | # We recommend against adding the Pods directory to your .gitignore. However
33 | # you should judge for yourself, the pros and cons are mentioned at:
34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control
35 | #
36 | # Pods/
37 |
38 | # Carthage
39 | #
40 | # Add this line if you want to avoid checking in source code from Carthage dependencies.
41 | # Carthage/Checkouts
42 |
43 | Carthage/Build
44 |
45 | # fastlane
46 | #
47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
48 | # screenshots whenever they are needed.
49 | # For more information about the recommended setup visit:
50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md
51 |
52 | fastlane/report.xml
53 | fastlane/screenshots
54 |
55 | #Code Injection
56 | #
57 | # After new code Injection tools there's a generated folder /iOSInjectionProject
58 | # https://github.com/johnno1962/injectionforxcode
59 |
60 | iOSInjectionProject/
61 |
--------------------------------------------------------------------------------
/AXAnimationChain-Swift.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 |
4 | s.name = "AXAnimationChain-Swift"
5 | s.version = "0.4.1"
6 | s.summary = "`AXAnimationChain-Swift` is an iOS chain animation kit using swift3.0."
7 |
8 | s.description = <<-DESC
9 | `AXAnimationChain-Swift` is an iOS chain animation kit using swift3.0 which is easy to use.
10 | DESC
11 | s.homepage = "https://github.com/devedbox/AXAnimationChain"
12 | s.license = { :type => "MIT", :file => "LICENSE" }
13 | s.author = { "devedbox" => "devedbox@qq.com" }
14 | s.platform = :ios, "8.0"
15 | s.source = { :git => "https://github.com/devedbox/AXAnimationChain.git", :tag => s.version }
16 | #s.source_files = 'AXAnimationChain/Classes/UIView+ChainAnimator.{h,m}', 'AXAnimationChain/Classes/AXChainAnimator.{h,m}', 'AXAnimationChain/Classes/CoreAnimation/*.{h,m}', 'AXAnimationChain/Classes/Swifty/*.swift'
17 | s.source_files = 'AXAnimationChain/Classes/Swifty/*.swift'
18 | #s.xcconfig = {'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/AXAnimationChain/Classes/**'}
19 |
20 | s.pod_target_xcconfig = {'SWIFT_INCLUDE_PATHS' => '$(PODS_ROOT)/AXAnimationChain/Classes/**'}
21 | s.preserve_paths = 'AXAnimationChain/Classes/module.modulemap'
22 |
23 | s.dependency 'AXAnimationChainSwift'
24 |
25 | s.frameworks = "UIKit", "Foundation", "QuartzCore"
26 | s.requires_arc = true
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/AXAnimationChain.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 |
4 | s.name = "AXAnimationChain"
5 | s.version = "0.4.1"
6 | s.summary = "`AXAnimationChain` is an iOS chain animation manater."
7 |
8 | s.description = <<-DESC
9 | `AXAnimationChain` is an iOS chain animation manater which is easy to use.
10 | DESC
11 | s.homepage = "https://github.com/devedbox/AXAnimationChain"
12 | s.license = { :type => "MIT", :file => "LICENSE" }
13 | s.author = { "devedbox" => "devedbox@qq.com" }
14 | s.platform = :ios, "8.0"
15 | s.source = { :git => "https://github.com/devedbox/AXAnimationChain.git", :tag => s.version }
16 | s.source_files = 'AXAnimationChain/Classes/*.{h,m}', 'AXAnimationChain/Classes/CoreAnimation/*.{h,m}'
17 | s.frameworks = "UIKit", "Foundation", "QuartzCore"
18 | s.requires_arc = true
19 |
20 | s.subspec 'CoreAnimation' do |ss|
21 | ss.source_files = 'AXAnimationChain/Classes/CoreAnimation/*.{h,m}'
22 | end
23 |
24 | s.subspec 'CoreMediaTimingFunction' do |sss|
25 | sss.source_files = 'AXAnimationChain/Classes/CoreAnimation/CAMediaTimingFunction+Extends.{h,m}'
26 | end
27 |
28 | end
29 |
--------------------------------------------------------------------------------
/AXAnimationChain.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/AXAnimationChain.xcodeproj/xcuserdata/devedbox.xcuserdatad/xcschemes/AXAnimationChain.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
43 |
49 |
50 |
51 |
52 |
53 |
59 |
60 |
61 |
62 |
63 |
64 |
74 |
76 |
82 |
83 |
84 |
85 |
86 |
87 |
93 |
95 |
101 |
102 |
103 |
104 |
106 |
107 |
110 |
111 |
112 |
--------------------------------------------------------------------------------
/AXAnimationChain.xcodeproj/xcuserdata/devedbox.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | AXAnimationChain.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | DC5E8A9D1DFBEBC400597663
16 |
17 | primary
18 |
19 |
20 | DC5E8AB61DFBEBC400597663
21 |
22 | primary
23 |
24 |
25 | DC5E8AC11DFBEBC400597663
26 |
27 | primary
28 |
29 |
30 |
31 |
32 |
33 |
--------------------------------------------------------------------------------
/AXAnimationChain/AXAnimationChain.modulemap:
--------------------------------------------------------------------------------
1 | framework module AXAnimationChain {
2 | umbrella header "Headers/AXAnimationChain.h"
3 |
4 | export *
5 | module * { export * }
6 |
7 | explicit module AXCoreAnimation {
8 | umbrella header "AXCoreAnimation.h"
9 |
10 | export *
11 | module * { export * }
12 | }
13 | }
14 |
--------------------------------------------------------------------------------
/AXAnimationChain/AnimationConvertableViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // AnimationConvertableViewController.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/6.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AnimationConvertableViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/AXAnimationChain/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 |
16 | @end
17 |
18 |
--------------------------------------------------------------------------------
/AXAnimationChain/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import "AppDelegate.h"
10 |
11 | @interface AppDelegate ()
12 |
13 | @end
14 |
15 | @implementation AppDelegate
16 |
17 |
18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
19 | // Override point for customization after application launch.
20 | return YES;
21 | }
22 |
23 |
24 | - (void)applicationWillResignActive:(UIApplication *)application {
25 | // 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.
26 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game.
27 | }
28 |
29 |
30 | - (void)applicationDidEnterBackground:(UIApplication *)application {
31 | // 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.
32 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
33 | }
34 |
35 |
36 | - (void)applicationWillEnterForeground:(UIApplication *)application {
37 | // 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.
38 | }
39 |
40 |
41 | - (void)applicationDidBecomeActive:(UIApplication *)application {
42 | // 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.
43 | }
44 |
45 |
46 | - (void)applicationWillTerminate:(UIApplication *)application {
47 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
48 | }
49 |
50 |
51 | @end
52 |
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "20x20",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "20x20",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "29x29",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "29x29",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "40x40",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "40x40",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "iphone",
35 | "size" : "60x60",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "iphone",
40 | "size" : "60x60",
41 | "scale" : "3x"
42 | }
43 | ],
44 | "info" : {
45 | "version" : 1,
46 | "author" : "xcode"
47 | }
48 | }
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "info" : {
3 | "version" : 1,
4 | "author" : "xcode"
5 | }
6 | }
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/image1.imageset/006k3ED2ly1fbnta30d2rj30k00zkn2n-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devedbox/AXAnimationChain/222c7aef6e5d413a42a790b36c2ff9763884454e/AXAnimationChain/Assets.xcassets/image1.imageset/006k3ED2ly1fbnta30d2rj30k00zkn2n-1.jpg
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/image1.imageset/006k3ED2ly1fbnta30d2rj30k00zkn2n.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devedbox/AXAnimationChain/222c7aef6e5d413a42a790b36c2ff9763884454e/AXAnimationChain/Assets.xcassets/image1.imageset/006k3ED2ly1fbnta30d2rj30k00zkn2n.jpg
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/image1.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "006k3ED2ly1fbnta30d2rj30k00zkn2n.jpg",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "006k3ED2ly1fbnta30d2rj30k00zkn2n-1.jpg",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/image2.imageset/006k3ED2ly1fbnta6w64dj30k00zkjwr-1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devedbox/AXAnimationChain/222c7aef6e5d413a42a790b36c2ff9763884454e/AXAnimationChain/Assets.xcassets/image2.imageset/006k3ED2ly1fbnta6w64dj30k00zkjwr-1.jpg
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/image2.imageset/006k3ED2ly1fbnta6w64dj30k00zkjwr.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devedbox/AXAnimationChain/222c7aef6e5d413a42a790b36c2ff9763884454e/AXAnimationChain/Assets.xcassets/image2.imageset/006k3ED2ly1fbnta6w64dj30k00zkjwr.jpg
--------------------------------------------------------------------------------
/AXAnimationChain/Assets.xcassets/image2.imageset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "universal",
5 | "scale" : "1x"
6 | },
7 | {
8 | "idiom" : "universal",
9 | "filename" : "006k3ED2ly1fbnta6w64dj30k00zkjwr.jpg",
10 | "scale" : "2x"
11 | },
12 | {
13 | "idiom" : "universal",
14 | "filename" : "006k3ED2ly1fbnta6w64dj30k00zkjwr-1.jpg",
15 | "scale" : "3x"
16 | }
17 | ],
18 | "info" : {
19 | "version" : 1,
20 | "author" : "xcode"
21 | }
22 | }
--------------------------------------------------------------------------------
/AXAnimationChain/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 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/AXAnimationChain.h:
--------------------------------------------------------------------------------
1 | //
2 | // AXAnimationChain.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/4.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #ifndef AXAnimationChain_h
27 | #define AXAnimationChain_h
28 |
29 | #import "AXChainAnimator.h"
30 | #import "AXChainAnimator+Block.h"
31 | #import "UIView+ChainAnimator.h"
32 | #import "UIView+AnimationChain.h"
33 | #import "AXCoreAnimation.h"
34 | #import "UIView+Effects.h"
35 | #import "CALayer+AnchorPoint.h"
36 |
37 | #endif /* AXAnimationChain_h */
38 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/AXChainAnimator+Block.h:
--------------------------------------------------------------------------------
1 | //
2 | // AXChainAnimator+Block.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/11.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "AXChainAnimator.h"
27 | NS_ASSUME_NONNULL_BEGIN
28 | @interface AXChainAnimator (Block)
29 | /// Begin with block reachable.
30 | ///
31 | - (AXChainAnimator * (^)(AXChainAnimator *animator))beginWith;
32 | /// Next to block reachable.
33 | ///
34 | - (AXChainAnimator * (^)(AXChainAnimator *animator))nextTo;
35 | /// Combine with block reachable.
36 | ///
37 | - (AXChainAnimator * (^)(AXChainAnimator *animator))combineWith;
38 | /// Begin time block reachable.
39 | ///
40 | - (AXChainAnimator * (^)(NSTimeInterval beginTime))beginTime;
41 | /// Duration block reachable.
42 | ///
43 | - (AXChainAnimator * (^)(NSTimeInterval duration))duration;
44 | /// Speed block reachable.
45 | ///
46 | - (AXChainAnimator * (^)(CGFloat speed))speed;
47 | /// TimeOffset block reachable.
48 | ///
49 | - (AXChainAnimator * (^)(NSTimeInterval timeOffset))timeOffset;
50 | /// RepeatCount block reachable.
51 | ///
52 | - (AXChainAnimator * (^)(CGFloat repeatCount))repeatCount;
53 | /// RepeatDuration block reachable.
54 | ///
55 | - (AXChainAnimator * (^)(NSTimeInterval repeatDuration))repeatDuration;
56 | /// FillMode block reachable.
57 | ///
58 | - (AXChainAnimator * (^)(NSString *fillMode))fillMode;
59 | /// Target block reachable.
60 | ///
61 | - (AXChainAnimator * (^)(NSObject *target))target;
62 | /// Completion SEL reachale.
63 | ///
64 | - (AXChainAnimator * (^)(SEL completion))complete;
65 | /// Completion block reachale.
66 | ///
67 | - (AXChainAnimator * (^)(dispatch_block_t completion))completeWithBlock;
68 | /// Start block reachable. Same as call the method `-start`
69 | ///
70 | - (dispatch_block_t)animate;
71 | @end
72 |
73 | @interface AXBasicChainAnimator (Block)
74 | /// Begin with block reachable.
75 | ///
76 | - (AXBasicChainAnimator * (^)(AXBasicChainAnimator *animator))beginWith;
77 | /// Next to block reachable.
78 | ///
79 | - (AXBasicChainAnimator * (^)(AXBasicChainAnimator *animator))nextTo;
80 | /// Combine with block reachable.
81 | ///
82 | - (AXBasicChainAnimator * (^)(AXBasicChainAnimator *animator))combineWith;
83 | /// Begin time block reachable.
84 | ///
85 | - (AXBasicChainAnimator * (^)(NSTimeInterval beginTime))beginTime;
86 | /// Duration block reachable.
87 | ///
88 | - (AXBasicChainAnimator * (^)(NSTimeInterval duration))duration;
89 | /// Speed block reachable.
90 | ///
91 | - (AXBasicChainAnimator * (^)(CGFloat speed))speed;
92 | /// TimeOffset block reachable.
93 | ///
94 | - (AXBasicChainAnimator * (^)(NSTimeInterval timeOffset))timeOffset;
95 | /// RepeatCount block reachable.
96 | ///
97 | - (AXBasicChainAnimator * (^)(CGFloat repeatCount))repeatCount;
98 | /// RepeatDuration block reachable.
99 | ///
100 | - (AXBasicChainAnimator * (^)(NSTimeInterval repeatDuration))repeatDuration;
101 | /// FillMode block reachable.
102 | ///
103 | - (AXBasicChainAnimator * (^)(NSString *fillMode))fillMode;
104 | /// Property block reachable.
105 | ///
106 | - (AXBasicChainAnimator * (^)(NSString *property))property;
107 | /// FromValue block reachable.
108 | ///
109 | - (AXBasicChainAnimator * (^)(id fromValue))fromValue;
110 | /// ToValue block reachable.
111 | ///
112 | - (AXBasicChainAnimator * (^)(id toValue))toValue;
113 | /// ByValue block reachable.
114 | ///
115 | - (AXBasicChainAnimator * (^)(id byValue))byValue;
116 | /// Target block reachable.
117 | ///
118 | - (AXBasicChainAnimator * (^)(NSObject *target))target;
119 | /// Completion SEL reachale.
120 | ///
121 | - (AXBasicChainAnimator * (^)(SEL completion))complete;
122 | /// Completion block reachale.
123 | ///
124 | - (AXBasicChainAnimator * (^)(dispatch_block_t completion))completeWithBlock;
125 | @end
126 |
127 | @interface AXKeyframeChainAnimator (Block)
128 | /// Begin with block reachable.
129 | ///
130 | - (AXKeyframeChainAnimator * (^)(AXKeyframeChainAnimator *animator))beginWith;
131 | /// Next to block reachable.
132 | ///
133 | - (AXKeyframeChainAnimator * (^)(AXKeyframeChainAnimator *animator))nextTo;
134 | /// Combine with block reachable.
135 | ///
136 | - (AXKeyframeChainAnimator * (^)(AXKeyframeChainAnimator *animator))combineWith;
137 | /// Begin time block reachable.
138 | ///
139 | - (AXKeyframeChainAnimator * (^)(NSTimeInterval beginTime))beginTime;
140 | /// Duration block reachable.
141 | ///
142 | - (AXKeyframeChainAnimator * (^)(NSTimeInterval duration))duration;
143 | /// Speed block reachable.
144 | ///
145 | - (AXKeyframeChainAnimator * (^)(CGFloat speed))speed;
146 | /// TimeOffset block reachable.
147 | ///
148 | - (AXKeyframeChainAnimator * (^)(NSTimeInterval timeOffset))timeOffset;
149 | /// RepeatCount block reachable.
150 | ///
151 | - (AXKeyframeChainAnimator * (^)(CGFloat repeatCount))repeatCount;
152 | /// RepeatDuration block reachable.
153 | ///
154 | - (AXKeyframeChainAnimator * (^)(NSTimeInterval repeatDuration))repeatDuration;
155 | /// FillMode block reachable.
156 | ///
157 | - (AXKeyframeChainAnimator * (^)(NSString *fillMode))fillMode;
158 | /// Property block reachable.
159 | ///
160 | - (AXKeyframeChainAnimator * (^)(NSString *property))property;
161 | /// Values block reachable.
162 | ///
163 | - (AXKeyframeChainAnimator * (^)(NSArray *values))values;
164 | /// Path block reachable.
165 | ///
166 | - (AXKeyframeChainAnimator * (^)(UIBezierPath *path))path;
167 | /// KeyTimes block reachable.
168 | ///
169 | - (AXKeyframeChainAnimator * (^)(NSArray *keyTimes))keyTimes;
170 | /// TimingFunctions block reachable.
171 | ///
172 | - (AXKeyframeChainAnimator * (^)(NSArray *timingFunctions))timingFunctions;
173 | /// CalculationMode block reachable.
174 | ///
175 | - (AXKeyframeChainAnimator * (^)(NSString *calculationMode))calculationMode;
176 | /// TensionValues block reachable.
177 | ///
178 | - (AXKeyframeChainAnimator * (^)(NSArray *tensionValues))tensionValues;
179 | /// ContinuityValues block reachable.
180 | ///
181 | - (AXKeyframeChainAnimator * (^)(NSArray *continuityValues))continuityValues;
182 | /// BiasValues block reachable.
183 | ///
184 | - (AXKeyframeChainAnimator * (^)(NSArray *biasValues))biasValues;
185 | /// RotationMode block reachable.
186 | ///
187 | - (AXKeyframeChainAnimator * (^)(NSString *rotationMode))rotationMode;
188 | /// Target block reachable.
189 | ///
190 | - (AXKeyframeChainAnimator * (^)(NSObject *target))target;
191 | /// Completion SEL reachale.
192 | ///
193 | - (AXKeyframeChainAnimator * (^)(SEL completion))complete;
194 | /// Completion block reachale.
195 | ///
196 | - (AXKeyframeChainAnimator * (^)(dispatch_block_t completion))completeWithBlock;
197 | @end
198 |
199 | @interface AXSpringChainAnimator (Block)
200 | /// Begin with block reachable.
201 | ///
202 | - (AXSpringChainAnimator * (^)(AXSpringChainAnimator *animator))beginWith;
203 | /// Next to block reachable.
204 | ///
205 | - (AXSpringChainAnimator * (^)(AXSpringChainAnimator *animator))nextTo;
206 | /// Combine with block reachable.
207 | ///
208 | - (AXSpringChainAnimator * (^)(AXSpringChainAnimator *animator))combineWith;
209 | /// Begin time block reachable.
210 | ///
211 | - (AXSpringChainAnimator * (^)(NSTimeInterval beginTime))beginTime;
212 | /// Duration block reachable.
213 | ///
214 | - (AXSpringChainAnimator * (^)(NSTimeInterval duration))duration;
215 | /// Speed block reachable.
216 | ///
217 | - (AXSpringChainAnimator * (^)(CGFloat speed))speed;
218 | /// TimeOffset block reachable.
219 | ///
220 | - (AXSpringChainAnimator * (^)(NSTimeInterval timeOffset))timeOffset;
221 | /// RepeatCount block reachable.
222 | ///
223 | - (AXSpringChainAnimator * (^)(CGFloat repeatCount))repeatCount;
224 | /// RepeatDuration block reachable.
225 | ///
226 | - (AXSpringChainAnimator * (^)(NSTimeInterval repeatDuration))repeatDuration;
227 | /// FillMode block reachable.
228 | ///
229 | - (AXSpringChainAnimator * (^)(NSString *fillMode))fillMode;
230 | /// Property block reachable.
231 | ///
232 | - (AXSpringChainAnimator * (^)(NSString *property))property;
233 | /// FromValue block reachable.
234 | ///
235 | - (AXSpringChainAnimator * (^)(id fromValue))fromValue;
236 | /// ToValue block reachable.
237 | ///
238 | - (AXSpringChainAnimator * (^)(id toValue))toValue;
239 | /// ByValue block reachable.
240 | ///
241 | - (AXSpringChainAnimator * (^)(id byValue))byValue;
242 | /// Mass block reachable.
243 | ///
244 | - (AXSpringChainAnimator * (^)(CGFloat mass))mass;
245 | /// Stiffness block reachable.
246 | ///
247 | - (AXSpringChainAnimator * (^)(CGFloat stiffness))stiffness;
248 | /// Damping block reachable.
249 | ///
250 | - (AXSpringChainAnimator * (^)(CGFloat damping))damping;
251 | /// InitialVelocity block reachable.
252 | ///
253 | - (AXSpringChainAnimator * (^)(CGFloat initialVelocity))initialVelocity;
254 | /// Target block reachable.
255 | ///
256 | - (AXSpringChainAnimator * (^)(NSObject *target))target;
257 | /// Completion SEL reachale.
258 | ///
259 | - (AXSpringChainAnimator * (^)(SEL completion))complete;
260 | /// Completion block reachale.
261 | ///
262 | - (AXSpringChainAnimator * (^)(dispatch_block_t completion))completeWithBlock;
263 | @end
264 |
265 | @interface AXTransitionChainAnimator (Block)
266 | /// Begin with block reachable.
267 | ///
268 | - (AXTransitionChainAnimator * (^)(AXTransitionChainAnimator *animator))beginWith;
269 | /// Next to block reachable.
270 | ///
271 | - (AXTransitionChainAnimator * (^)(AXTransitionChainAnimator *animator))nextTo;
272 | /// Combine with block reachable.
273 | ///
274 | - (AXTransitionChainAnimator * (^)(AXTransitionChainAnimator *animator))combineWith;
275 | /// Begin time block reachable.
276 | ///
277 | - (AXTransitionChainAnimator * (^)(NSTimeInterval beginTime))beginTime;
278 | /// Duration block reachable.
279 | ///
280 | - (AXTransitionChainAnimator * (^)(NSTimeInterval duration))duration;
281 | /// Speed block reachable.
282 | ///
283 | - (AXTransitionChainAnimator * (^)(CGFloat speed))speed;
284 | /// TimeOffset block reachable.
285 | ///
286 | - (AXTransitionChainAnimator * (^)(NSTimeInterval timeOffset))timeOffset;
287 | /// RepeatCount block reachable.
288 | ///
289 | - (AXTransitionChainAnimator * (^)(CGFloat repeatCount))repeatCount;
290 | /// RepeatDuration block reachable.
291 | ///
292 | - (AXTransitionChainAnimator * (^)(NSTimeInterval repeatDuration))repeatDuration;
293 | /// FillMode block reachable.
294 | ///
295 | - (AXTransitionChainAnimator * (^)(NSString *fillMode))fillMode;
296 | /// Type block reachable.
297 | ///
298 | - (AXTransitionChainAnimator * (^)(NSString *type))type;
299 | /// Subtype block reachable.
300 | ///
301 | - (AXTransitionChainAnimator * (^)(NSString *subtype))subtype;
302 | /// StartProgress block reachable.
303 | ///
304 | - (AXTransitionChainAnimator * (^)(CGFloat startProgress))startProgress;
305 | /// EndProgress block reachable.
306 | ///
307 | - (AXTransitionChainAnimator * (^)(CGFloat endProgress))endProgress;
308 | /// Filter block reachable.
309 | ///
310 | - (AXTransitionChainAnimator * (^)(id filter))filter;
311 | /// Target block reachable.
312 | ///
313 | - (AXTransitionChainAnimator * (^)(NSObject *target))target;
314 | /// Completion SEL reachale.
315 | ///
316 | - (AXTransitionChainAnimator * (^)(SEL completion))complete;
317 | /// Completion block reachale.
318 | ///
319 | - (AXTransitionChainAnimator * (^)(dispatch_block_t completion))completeWithBlock;
320 | @end
321 | NS_ASSUME_NONNULL_END
322 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/AXChainAnimator+Block.m:
--------------------------------------------------------------------------------
1 | //
2 | // AXChainAnimator+Block.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/15.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "AXChainAnimator+Block.h"
27 |
28 | @implementation AXChainAnimator (Block)
29 | - (AXChainAnimator *(^)(AXChainAnimator *))beginWith {
30 | return ^AXChainAnimator* (AXChainAnimator *animator) {
31 | return [self beginWith:animator];
32 | };
33 | }
34 |
35 | - (AXChainAnimator *(^)(AXChainAnimator *))nextTo {
36 | return ^AXChainAnimator* (AXChainAnimator *animator) {
37 | return [self nextTo:animator];
38 | };
39 | }
40 |
41 | - (AXChainAnimator *(^)(AXChainAnimator *))combineWith {
42 | return ^AXChainAnimator* (AXChainAnimator *animator) {
43 | return [self combineWith:animator];
44 | };
45 | }
46 |
47 | - (AXChainAnimator *(^)(NSTimeInterval))beginTime {
48 | return ^AXChainAnimator* (NSTimeInterval beginTime) {
49 | return [self beginTime:beginTime];
50 | };
51 | }
52 |
53 | - (AXChainAnimator *(^)(NSTimeInterval))duration {
54 | return ^AXChainAnimator* (NSTimeInterval duration) {
55 | return [self duration:duration];
56 | };
57 | }
58 |
59 | - (AXChainAnimator *(^)(CGFloat))speed {
60 | return ^AXChainAnimator* (CGFloat speed) {
61 | return [self speed:speed];
62 | };
63 | }
64 |
65 | - (AXChainAnimator *(^)(NSTimeInterval))timeOffset {
66 | return ^AXChainAnimator* (NSTimeInterval timeOffset) {
67 | return [self timeOffset:timeOffset];
68 | };
69 | }
70 |
71 | - (AXChainAnimator *(^)(CGFloat))repeatCount {
72 | return ^AXChainAnimator* (CGFloat repeatCount) {
73 | return [self repeatCount:repeatCount];
74 | };
75 | }
76 |
77 | - (AXChainAnimator *(^)(NSTimeInterval))repeatDuration {
78 | return ^AXChainAnimator* (NSTimeInterval repeatDuration) {
79 | return [self repeatDuration:repeatDuration];
80 | };
81 | }
82 |
83 | - (AXChainAnimator *(^)(NSString *))fillMode {
84 | return ^AXChainAnimator* (NSString *fillMode) {
85 | return [self fillMode:fillMode];
86 | };
87 | }
88 |
89 | - (AXChainAnimator *(^)(NSObject *))target {
90 | return ^AXChainAnimator* (NSObject *target) {
91 | return [self target:target];
92 | };
93 | }
94 |
95 | - (AXChainAnimator *(^)(SEL))complete {
96 | return ^AXChainAnimator* (SEL completion) {
97 | return [self complete:completion];
98 | };
99 | }
100 |
101 | - (AXChainAnimator *(^)(dispatch_block_t))completeWithBlock {
102 | return ^AXChainAnimator* (dispatch_block_t completion) {
103 | return [self completeWithBlock:completion];
104 | };
105 | }
106 |
107 | - (dispatch_block_t)animate {
108 | return ^() {
109 | [self start];
110 | };
111 | }
112 | @end
113 |
114 | @implementation AXBasicChainAnimator (Block)
115 | - (AXBasicChainAnimator *(^)(AXBasicChainAnimator *))beginWith {
116 | return ^AXBasicChainAnimator* (AXBasicChainAnimator *animator) {
117 | return [self beginWith:animator];
118 | };
119 | }
120 |
121 | - (AXBasicChainAnimator *(^)(AXBasicChainAnimator *))nextTo {
122 | return ^AXBasicChainAnimator* (AXBasicChainAnimator *animator) {
123 | return [self nextTo:animator];
124 | };
125 | }
126 |
127 | - (AXBasicChainAnimator *(^)(AXBasicChainAnimator *))combineWith {
128 | return ^AXBasicChainAnimator* (AXBasicChainAnimator *animator) {
129 | return [self combineWith:animator];
130 | };
131 | }
132 |
133 | - (AXBasicChainAnimator *(^)(NSTimeInterval))beginTime {
134 | return ^AXBasicChainAnimator* (NSTimeInterval beginTime) {
135 | return [self beginTime:beginTime];
136 | };
137 | }
138 |
139 | - (AXBasicChainAnimator *(^)(NSTimeInterval))duration {
140 | return ^AXBasicChainAnimator* (NSTimeInterval duration) {
141 | return [self duration:duration];
142 | };
143 | }
144 |
145 | - (AXBasicChainAnimator *(^)(CGFloat))speed {
146 | return ^AXBasicChainAnimator* (CGFloat speed) {
147 | return [self speed:speed];
148 | };
149 | }
150 |
151 | - (AXBasicChainAnimator *(^)(NSTimeInterval))timeOffset {
152 | return ^AXBasicChainAnimator* (NSTimeInterval timeOffset) {
153 | return [self timeOffset:timeOffset];
154 | };
155 | }
156 |
157 | - (AXBasicChainAnimator *(^)(CGFloat))repeatCount {
158 | return ^AXBasicChainAnimator* (CGFloat repeatCount) {
159 | return [self repeatCount:repeatCount];
160 | };
161 | }
162 |
163 | - (AXBasicChainAnimator *(^)(NSTimeInterval))repeatDuration {
164 | return ^AXBasicChainAnimator* (NSTimeInterval repeatDuration) {
165 | return [self repeatDuration:repeatDuration];
166 | };
167 | }
168 |
169 | - (AXBasicChainAnimator *(^)(NSString *))fillMode {
170 | return ^AXBasicChainAnimator* (NSString *fillMode) {
171 | return [self fillMode:fillMode];
172 | };
173 | }
174 |
175 | - (AXBasicChainAnimator *(^)(NSString *))property {
176 | return ^AXBasicChainAnimator* (NSString *property) {
177 | return [self property:property];
178 | };
179 | }
180 |
181 | - (AXBasicChainAnimator *(^)(id))fromValue {
182 | return ^AXBasicChainAnimator* (id fromValue) {
183 | return [self fromValue:fromValue];
184 | };
185 | }
186 |
187 | - (AXBasicChainAnimator *(^)(id))toValue {
188 | return ^AXBasicChainAnimator* (id toValue) {
189 | return [self toValue:toValue];
190 | };
191 | }
192 |
193 | - (AXBasicChainAnimator *(^)(id))byValue {
194 | return ^AXBasicChainAnimator* (id byValue) {
195 | return [self byValue:byValue];
196 | };
197 | }
198 |
199 | - (AXBasicChainAnimator *(^)(NSObject *))target {
200 | return ^AXBasicChainAnimator* (NSObject *target) {
201 | return [self target:target];
202 | };
203 | }
204 |
205 | - (AXBasicChainAnimator *(^)(SEL))complete {
206 | return ^AXBasicChainAnimator* (SEL completion) {
207 | return [self complete:completion];
208 | };
209 | }
210 |
211 | - (AXBasicChainAnimator *(^)(dispatch_block_t))completeWithBlock {
212 | return ^AXBasicChainAnimator* (dispatch_block_t completion) {
213 | return [self completeWithBlock:completion];
214 | };
215 | }
216 | @end
217 |
218 | @implementation AXKeyframeChainAnimator (Block)
219 | - (AXKeyframeChainAnimator *(^)(AXKeyframeChainAnimator *))beginWith {
220 | return ^AXKeyframeChainAnimator* (AXKeyframeChainAnimator *animator) {
221 | return [self beginWith:animator];
222 | };
223 | }
224 |
225 | - (AXKeyframeChainAnimator *(^)(AXKeyframeChainAnimator *))nextTo {
226 | return ^AXKeyframeChainAnimator* (AXKeyframeChainAnimator *animator) {
227 | return [self nextTo:animator];
228 | };
229 | }
230 |
231 | - (AXKeyframeChainAnimator *(^)(AXKeyframeChainAnimator *))combineWith {
232 | return ^AXKeyframeChainAnimator* (AXKeyframeChainAnimator *animator) {
233 | return [self combineWith:animator];
234 | };
235 | }
236 |
237 | - (AXKeyframeChainAnimator *(^)(NSTimeInterval))beginTime {
238 | return ^AXKeyframeChainAnimator* (NSTimeInterval beginTime) {
239 | return [self beginTime:beginTime];
240 | };
241 | }
242 |
243 | - (AXKeyframeChainAnimator *(^)(NSTimeInterval))duration {
244 | return ^AXKeyframeChainAnimator* (NSTimeInterval duration) {
245 | return [self duration:duration];
246 | };
247 | }
248 |
249 | - (AXKeyframeChainAnimator *(^)(CGFloat))speed {
250 | return ^AXKeyframeChainAnimator* (CGFloat speed) {
251 | return [self speed:speed];
252 | };
253 | }
254 |
255 | - (AXKeyframeChainAnimator *(^)(NSTimeInterval))timeOffset {
256 | return ^AXKeyframeChainAnimator* (NSTimeInterval timeOffset) {
257 | return [self timeOffset:timeOffset];
258 | };
259 | }
260 |
261 | - (AXKeyframeChainAnimator *(^)(CGFloat))repeatCount {
262 | return ^AXKeyframeChainAnimator* (CGFloat repeatCount) {
263 | return [self repeatCount:repeatCount];
264 | };
265 | }
266 |
267 | - (AXKeyframeChainAnimator *(^)(NSTimeInterval))repeatDuration {
268 | return ^AXKeyframeChainAnimator* (NSTimeInterval repeatDuration) {
269 | return [self repeatDuration:repeatDuration];
270 | };
271 | }
272 |
273 | - (AXKeyframeChainAnimator *(^)(NSString *))fillMode {
274 | return ^AXKeyframeChainAnimator* (NSString *fillMode) {
275 | return [self fillMode:fillMode];
276 | };
277 | }
278 |
279 | - (AXKeyframeChainAnimator *(^)(NSString *))property {
280 | return ^AXKeyframeChainAnimator* (NSString *property) {
281 | return [self property:property];
282 | };
283 | }
284 |
285 | - (AXKeyframeChainAnimator *(^)(NSArray *))values {
286 | return ^AXKeyframeChainAnimator* (NSArray *values) {
287 | return [self values:values];
288 | };
289 | }
290 |
291 | - (AXKeyframeChainAnimator *(^)(UIBezierPath *))path {
292 | return ^AXKeyframeChainAnimator* (UIBezierPath *path) {
293 | return [self path:path];
294 | };
295 | }
296 |
297 | - (AXKeyframeChainAnimator *(^)(NSArray *))keyTimes {
298 | return ^AXKeyframeChainAnimator* (NSArray *keyTimes) {
299 | return [self keyTimes:keyTimes];
300 | };
301 | }
302 |
303 | - (AXKeyframeChainAnimator *(^)(NSArray *))timingFunctions {
304 | return ^AXKeyframeChainAnimator* (NSArray *timingFunctions) {
305 | return [self timingFunctions:timingFunctions];
306 | };
307 | }
308 |
309 | - (AXKeyframeChainAnimator *(^)(NSString *))calculationMode {
310 | return ^AXKeyframeChainAnimator* (NSString *calculationMode) {
311 | return [self calculationMode:calculationMode];
312 | };
313 | }
314 |
315 | - (AXKeyframeChainAnimator *(^)(NSArray *))tensionValues {
316 | return ^AXKeyframeChainAnimator* (NSArray *tensionValues) {
317 | return [self tensionValues:tensionValues];
318 | };
319 | }
320 |
321 | - (AXKeyframeChainAnimator *(^)(NSArray *))continuityValues {
322 | return ^AXKeyframeChainAnimator* (NSArray *continuityValues) {
323 | return [self continuityValues:continuityValues];
324 | };
325 | }
326 |
327 | - (AXKeyframeChainAnimator *(^)(NSArray *))biasValues {
328 | return ^AXKeyframeChainAnimator* (NSArray *biasValues) {
329 | return [self biasValues:biasValues];
330 | };
331 | }
332 |
333 | - (AXKeyframeChainAnimator *(^)(NSString *))rotationMode {
334 | return ^AXKeyframeChainAnimator* (NSString *rotationMode) {
335 | return [self rotationMode:rotationMode];
336 | };
337 | }
338 |
339 |
340 | - (AXKeyframeChainAnimator *(^)(NSObject *))target {
341 | return ^AXKeyframeChainAnimator* (NSObject *target) {
342 | return [self target:target];
343 | };
344 | }
345 |
346 | - (AXKeyframeChainAnimator *(^)(SEL))complete {
347 | return ^AXKeyframeChainAnimator* (SEL completion) {
348 | return [self complete:completion];
349 | };
350 | }
351 |
352 | - (AXKeyframeChainAnimator *(^)(dispatch_block_t))completeWithBlock {
353 | return ^AXKeyframeChainAnimator* (dispatch_block_t completion) {
354 | return [self completeWithBlock:completion];
355 | };
356 | }
357 | @end
358 |
359 | @implementation AXSpringChainAnimator (Block)
360 | - (AXSpringChainAnimator *(^)(AXSpringChainAnimator *))beginWith {
361 | return ^AXSpringChainAnimator* (AXSpringChainAnimator *animator) {
362 | return [self beginWith:animator];
363 | };
364 | }
365 |
366 | - (AXSpringChainAnimator *(^)(AXSpringChainAnimator *))nextTo {
367 | return ^AXSpringChainAnimator* (AXSpringChainAnimator *animator) {
368 | return [self nextTo:animator];
369 | };
370 | }
371 |
372 | - (AXSpringChainAnimator *(^)(AXSpringChainAnimator *))combineWith {
373 | return ^AXSpringChainAnimator* (AXSpringChainAnimator *animator) {
374 | return [self combineWith:animator];
375 | };
376 | }
377 |
378 | - (AXSpringChainAnimator *(^)(NSTimeInterval))beginTime {
379 | return ^AXSpringChainAnimator* (NSTimeInterval beginTime) {
380 | return [self beginTime:beginTime];
381 | };
382 | }
383 |
384 | - (AXSpringChainAnimator *(^)(NSTimeInterval))duration {
385 | return ^AXSpringChainAnimator* (NSTimeInterval duration) {
386 | return [self duration:duration];
387 | };
388 | }
389 |
390 | - (AXSpringChainAnimator *(^)(CGFloat))speed {
391 | return ^AXSpringChainAnimator* (CGFloat speed) {
392 | return [self speed:speed];
393 | };
394 | }
395 |
396 | - (AXSpringChainAnimator *(^)(NSTimeInterval))timeOffset {
397 | return ^AXSpringChainAnimator* (NSTimeInterval timeOffset) {
398 | return [self timeOffset:timeOffset];
399 | };
400 | }
401 |
402 | - (AXSpringChainAnimator *(^)(CGFloat))repeatCount {
403 | return ^AXSpringChainAnimator* (CGFloat repeatCount) {
404 | return [self repeatCount:repeatCount];
405 | };
406 | }
407 |
408 | - (AXSpringChainAnimator *(^)(NSTimeInterval))repeatDuration {
409 | return ^AXSpringChainAnimator* (NSTimeInterval repeatDuration) {
410 | return [self repeatDuration:repeatDuration];
411 | };
412 | }
413 |
414 | - (AXSpringChainAnimator *(^)(NSString *))fillMode {
415 | return ^AXSpringChainAnimator* (NSString *fillMode) {
416 | return [self fillMode:fillMode];
417 | };
418 | }
419 |
420 | - (AXSpringChainAnimator *(^)(NSString *))property {
421 | return ^AXSpringChainAnimator* (NSString *property) {
422 | return [self property:property];
423 | };
424 | }
425 |
426 | - (AXSpringChainAnimator *(^)(id))fromValue {
427 | return ^AXSpringChainAnimator* (id fromValue) {
428 | return [self fromValue:fromValue];
429 | };
430 | }
431 |
432 | - (AXSpringChainAnimator *(^)(id))toValue {
433 | return ^AXSpringChainAnimator* (id toValue) {
434 | return [self toValue:toValue];
435 | };
436 | }
437 |
438 | - (AXSpringChainAnimator *(^)(id))byValue {
439 | return ^AXSpringChainAnimator* (id byValue) {
440 | return [self byValue:byValue];
441 | };
442 | }
443 |
444 | - (AXSpringChainAnimator *(^)(CGFloat))mass {
445 | return ^AXSpringChainAnimator* (CGFloat mass) {
446 | return [self mass:mass];
447 | };
448 | }
449 |
450 | - (AXSpringChainAnimator *(^)(CGFloat))stiffness {
451 | return ^AXSpringChainAnimator* (CGFloat stiffness) {
452 | return [self stiffness:stiffness];
453 | };
454 | }
455 |
456 | - (AXSpringChainAnimator *(^)(CGFloat))damping {
457 | return ^AXSpringChainAnimator* (CGFloat damping) {
458 | return [self damping:damping];
459 | };
460 | }
461 |
462 | - (AXSpringChainAnimator *(^)(CGFloat))initialVelocity {
463 | return ^AXSpringChainAnimator* (CGFloat initialVelocity) {
464 | return [self initialVelocity:initialVelocity];
465 | };
466 | }
467 |
468 | - (AXSpringChainAnimator *(^)(NSObject *))target {
469 | return ^AXSpringChainAnimator* (NSObject *target) {
470 | return [self target:target];
471 | };
472 | }
473 |
474 | - (AXSpringChainAnimator *(^)(SEL))complete {
475 | return ^AXSpringChainAnimator* (SEL completion) {
476 | return [self complete:completion];
477 | };
478 | }
479 |
480 | - (AXSpringChainAnimator *(^)(dispatch_block_t))completeWithBlock {
481 | return ^AXSpringChainAnimator* (dispatch_block_t completion) {
482 | return [self completeWithBlock:completion];
483 | };
484 | }
485 | @end
486 |
487 | @implementation AXTransitionChainAnimator (Block)
488 | - (AXTransitionChainAnimator *(^)(AXTransitionChainAnimator *))beginWith {
489 | return ^AXTransitionChainAnimator* (AXTransitionChainAnimator *animator) {
490 | return [self beginWith:animator];
491 | };
492 | }
493 |
494 | - (AXTransitionChainAnimator *(^)(AXTransitionChainAnimator *))nextTo {
495 | return ^AXTransitionChainAnimator* (AXTransitionChainAnimator *animator) {
496 | return [self nextTo:animator];
497 | };
498 | }
499 |
500 | - (AXTransitionChainAnimator *(^)(AXTransitionChainAnimator *))combineWith {
501 | return ^AXTransitionChainAnimator* (AXTransitionChainAnimator *animator) {
502 | return [self combineWith:animator];
503 | };
504 | }
505 |
506 | - (AXTransitionChainAnimator *(^)(NSTimeInterval))beginTime {
507 | return ^AXTransitionChainAnimator* (NSTimeInterval beginTime) {
508 | return [self beginTime:beginTime];
509 | };
510 | }
511 |
512 | - (AXTransitionChainAnimator *(^)(NSTimeInterval))duration {
513 | return ^AXTransitionChainAnimator* (NSTimeInterval duration) {
514 | return [self duration:duration];
515 | };
516 | }
517 |
518 | - (AXTransitionChainAnimator *(^)(CGFloat))speed {
519 | return ^AXTransitionChainAnimator* (CGFloat speed) {
520 | return [self speed:speed];
521 | };
522 | }
523 |
524 | - (AXTransitionChainAnimator *(^)(NSTimeInterval))timeOffset {
525 | return ^AXTransitionChainAnimator* (NSTimeInterval timeOffset) {
526 | return [self timeOffset:timeOffset];
527 | };
528 | }
529 |
530 | - (AXTransitionChainAnimator *(^)(CGFloat))repeatCount {
531 | return ^AXTransitionChainAnimator* (CGFloat repeatCount) {
532 | return [self repeatCount:repeatCount];
533 | };
534 | }
535 |
536 | - (AXTransitionChainAnimator *(^)(NSTimeInterval))repeatDuration {
537 | return ^AXTransitionChainAnimator* (NSTimeInterval repeatDuration) {
538 | return [self repeatDuration:repeatDuration];
539 | };
540 | }
541 |
542 | - (AXTransitionChainAnimator *(^)(NSString *))fillMode {
543 | return ^AXTransitionChainAnimator* (NSString *fillMode) {
544 | return [self fillMode:fillMode];
545 | };
546 | }
547 |
548 | - (AXTransitionChainAnimator *(^)(NSString *))type {
549 | return ^AXTransitionChainAnimator* (NSString *type) {
550 | return [self type:type];
551 | };
552 | }
553 |
554 | - (AXTransitionChainAnimator *(^)(NSString *))subtype {
555 | return ^AXTransitionChainAnimator* (NSString *subtype) {
556 | return [self subtype:subtype];
557 | };
558 | }
559 |
560 | - (AXTransitionChainAnimator *(^)(CGFloat))startProgress {
561 | return ^AXTransitionChainAnimator* (CGFloat startProgress) {
562 | return [self startProgress:startProgress];
563 | };
564 | }
565 |
566 | - (AXTransitionChainAnimator *(^)(CGFloat))endProgress {
567 | return ^AXTransitionChainAnimator* (CGFloat endProgress) {
568 | return [self endProgress:endProgress];
569 | };
570 | }
571 |
572 | - (AXTransitionChainAnimator *(^)(id))filter {
573 | return ^AXTransitionChainAnimator* (id filter) {
574 | return [self filter:filter];
575 | };
576 | }
577 |
578 | - (AXTransitionChainAnimator *(^)(NSObject *))target {
579 | return ^AXTransitionChainAnimator* (NSObject *target) {
580 | return [self target:target];
581 | };
582 | }
583 |
584 | - (AXTransitionChainAnimator *(^)(SEL))complete {
585 | return ^AXTransitionChainAnimator* (SEL completion) {
586 | return [self complete:completion];
587 | };
588 | }
589 |
590 | - (AXTransitionChainAnimator *(^)(dispatch_block_t))completeWithBlock {
591 | return ^AXTransitionChainAnimator* (dispatch_block_t completion) {
592 | return [self completeWithBlock:completion];
593 | };
594 | }
595 | @end
596 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/AXChainAnimator.h:
--------------------------------------------------------------------------------
1 | //
2 | // AXAnimationChain.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | #import
28 | #import
29 | #import "AXCoreAnimation.h"
30 |
31 | NS_ASSUME_NONNULL_BEGIN
32 | /// CAMediaTiming protocol reachable.
33 | @protocol AXMediaTimingDelegate
34 | /// Set the begin time of the animation object with a time interval.
35 | ///
36 | /// @param beginTime a time interval since the super object.
37 | /// @return Original instance object.
38 | ///
39 | /// @see
40 | - (instancetype)beginTime:(NSTimeInterval)beginTime;
41 | /// Set the duration of the animation object with a time interval.
42 | ///
43 | /// @param duration time duration.
44 | /// @return Original instance object.
45 | ///
46 | /// @see
47 | - (instancetype)duration:(NSTimeInterval)duration;
48 | /// Set the speed of the animation object of a speed value.
49 | ///
50 | /// @param speed a float value of the speed.
51 | /// @return Original instance object.
52 | ///
53 | /// @see
54 | - (instancetype)speed:(CGFloat)speed;
55 | /// Set the time offset of animation object with a time interval.
56 | ///
57 | /// @param timeOffset a double value of timg offset.
58 | /// @return Original instance object.
59 | ///
60 | /// @see
61 | - (instancetype)timeOffset:(NSTimeInterval)timeOffset;
62 | /// Set the repeat count of the core animation. Work like `reeapDuration:`.
63 | ///
64 | /// @param repeatCount repeat count of the core animation.
65 | /// @return the receiver.
66 | ///
67 | /// @see
68 | - (instancetype)repeatCount:(CGFloat)repeatCount;
69 | /// Set the repeat duration of the core animation. Work like `reeapCount:`.
70 | ///
71 | /// @param repeatDuration repeat duration of the core animation.
72 | /// @return the receiver.
73 | ///
74 | /// @see
75 | - (instancetype)repeatDuration:(NSTimeInterval)repeatDuration;
76 | /// Set the autoreverses of the core animation.
77 | ///
78 | /// @return the receiver.
79 | ///
80 | /// @see
81 | - (instancetype)autoreverses;
82 | /// Set the fill mode of the core animation.
83 | ///
84 | /// @param fillMode fill mode of the core animation.
85 | /// @return the receiver.
86 | ///
87 | /// @see
88 | - (instancetype)fillMode:(NSString *)fillMode;
89 | /// Remove the animation when the animator has finished the animating. Defaults to NO.
90 | /// @discusstion This way is not recommended to chain the animations because that
91 | /// if the begining animation is finished and removed, the result will
92 | /// effect the next animators.
93 | - (instancetype)removedOnCompletion;
94 | @end
95 |
96 | @protocol AXBasicChainAnimatorDelegate;
97 | @protocol AXKeyframeChainAnimatorDelegate;
98 | @protocol AXSpringChainAnimatorDelegate;
99 | @protocol AXTransitionChainAnimatorDelegate;
100 |
101 | /// Animator chain defines.
102 | @protocol AXAnimatorChainDelegate
103 | /// Father animator object.
104 | @property(weak, nonatomic, nullable) id superAnimator;
105 | /// Child animator object.
106 | @property(strong, nonatomic, nullable) id childAnimator;
107 | /// Brothers animator objects.
108 | @property(strong, nonatomic, nullable) NSArray> *combinedAnimators;
109 | /// Core animation of the animator.
110 | @property(readonly, nonatomic) CAAnimation *animation;
111 | /// Basic animator. Begin with basic animation.
112 | @property(readonly, nonatomic) id basic;
113 | /// Key frame animator. Begin with keyframe animation.
114 | @property(readonly, nonatomic) id keyframe;
115 | /// Spring animator. Begin with spring animation.
116 | @property(readonly, nonatomic) id spring;
117 | /// Transition animator. Begin with transition animation.
118 | @property(readonly, nonatomic) id transition;
119 | // Chain releationship manager.
120 | /// Begin with a new animator with a specific animation.
121 | ///
122 | /// @param animator animator to begin with.
123 | /// @return a new animator.
124 | ///
125 | - (instancetype)beginWith:(id)animator;
126 | /// Next to a animator as the node of the chain.
127 | ///
128 | /// @param animator aimator to be nexted to.
129 | /// @return the next-to animator.
130 | ///
131 | - (instancetype)nextTo:(id)animator;
132 | /// Combine with a animator to the node of the receiver.
133 | ///
134 | /// @param animator animator to be combined with.
135 | /// @return the combined animator.
136 | ///
137 | - (instancetype)combineWith:(id)animator;
138 | /// Start animating the animation chain.
139 | ///
140 | - (void)start;
141 | /// Add target to the specific animator.
142 | ///
143 | /// @param target the target will trigger the completion SEL.
144 | /// @return SELF.
145 | ///
146 | - (instancetype)target:(nullable NSObject *)target;
147 | /// Add completion selector to the animator.
148 | ///
149 | /// @param completion completion selector of the target.
150 | /// @return SELF.
151 | ///
152 | - (instancetype)complete:(nullable SEL)completion;
153 | /// Called when animator has finished using block on main thread.
154 | ///
155 | /// @param completion completion block of the complete action.
156 | /// @return SELF.
157 | ///
158 | - (instancetype)completeWithBlock:(dispatch_block_t)completion;
159 | @end
160 | /// Chain animator defines.
161 | @protocol AXChainAnimatorDelegate
162 | // CAMediaTimingFunction reachable. Default using default function:
163 | - (instancetype)timingFunction:(CAMediaTimingFunction *)timingFunction;
164 | /// Using linear timing function.
165 | - (instancetype)linear;
166 | /// Using ease in timing function.
167 | - (instancetype)easeIn;
168 | /// Using ease out timing function.
169 | - (instancetype)easeOut;
170 | /// Using ease in out timing function.
171 | - (instancetype)easeInOut;
172 | // Custom tming functions like CSS3:
173 | /// Using ease in sine timing function.
174 | - (instancetype)easeInSine;
175 | /// Using ease out sine timing function.
176 | - (instancetype)easeOutSine;
177 | /// Using ease in out sine timing function.
178 | - (instancetype)easeInOutSine;
179 | /// Using ease in quad timing function.
180 | - (instancetype)easeInQuad;
181 | /// Using ease out quad timing function.
182 | - (instancetype)easeOutQuad;
183 | /// Using ease in out quad timing function.
184 | - (instancetype)easeInOutQuad;
185 | /// Using ease in cubic timing function.
186 | - (instancetype)easeInCubic;
187 | /// Using ease out cubic timing function.
188 | - (instancetype)easeOutCubic;
189 | /// Using ease in out cubic timing function.
190 | - (instancetype)easeInOutCubic;
191 | /// Using ease in quart timing function.
192 | - (instancetype)easeInQuart;
193 | /// Using ease out quart timing function.
194 | - (instancetype)easeOutQuart;
195 | /// Using ease in out quart timing function.
196 | - (instancetype)easeInOutQuart;
197 | /// Using ease in quint timing function.
198 | - (instancetype)easeInQuint;
199 | /// Using ease out quint timing function.
200 | - (instancetype)easeOutQuint;
201 | /// Using ease in out quint timing function.
202 | - (instancetype)easeInOutQuint;
203 | /// Using ease in expo timing function.
204 | - (instancetype)easeInExpo;
205 | /// Using ease out expo timing function.
206 | - (instancetype)easeOutExpo;
207 | /// Using ease in out expo timing function.
208 | - (instancetype)easeInOutExpo;
209 | /// Using ease in circ timing function.
210 | - (instancetype)easeInCirc;
211 | /// Using ease out circ timing function.
212 | - (instancetype)easeOutCirc;
213 | /// Using ease in out circ timing function.
214 | - (instancetype)easeInOutCirc;
215 | /// Using ease in back timing function.
216 | - (instancetype)easeInBack;
217 | /// Using ease out back timing function.
218 | - (instancetype)easeOutBack;
219 | /// Using ease in out back timing function.
220 | - (instancetype)easeInOutBack;
221 | @end
222 | /// CAPropertyAnimation reachable.
223 | @protocol AXPropertyChainAnimatorDelegate
224 | /// Set animated property key path value.
225 | ///
226 | /// @param property a key path of animatable properties.
227 | /// @return the receiver.
228 | ///
229 | - (instancetype)property:(NSString *)property;
230 | @end
231 |
232 | @protocol AXKeyframeChainAnimatorDelegate;
233 | /// CABasicAnimation reachable.
234 | @protocol AXBasicChainAnimatorDelegate
235 | /// Set fromValue of the basic animation.
236 | ///
237 | /// @param fromValue animation from value.
238 | /// @return the receiver.
239 | ///
240 | - (instancetype)fromValue:(id)fromValue;
241 | /// Set toValue of the basic animation.
242 | ///
243 | /// @param toValue animation to value.
244 | /// @return the receiver.
245 | ///
246 | - (instancetype)toValue:(id)toValue;
247 | /// Set byValue of the basic animation.
248 | ///
249 | /// @param byValue animation by value.
250 | /// @return the receiver.
251 | ///
252 | - (instancetype)byValue:(id)byValue;
253 |
254 | // Effects converting to Keyframe animation.
255 | /// Using ease in elastic timing function.
256 | - (id)easeInElastic;
257 | /// Using ease out elastic timing function.
258 | - (id)easeOutElastic;
259 | /// Using ease in out elastic timing function.
260 | - (id)easeInOutElastic;
261 | /// Using ease in bounce timing function.
262 | - (id)easeInBounce;
263 | /// Using ease out bounce timing function.
264 | - (id)easeOutBounce;
265 | /// Using ease in out bounce timing function.
266 | - (id)easeInOutBounce;
267 | /// Using gravity timing function.
268 | - (id)gravity;
269 | @end
270 | /// CAKeyframeAnimation reachable.
271 | @protocol AXKeyframeChainAnimatorDelegate
272 | /// Set values of the core keyframe animation.
273 | ///
274 | /// @param values values of the keyframe animation.
275 | /// @return the receiver.
276 | ///
277 | - (instancetype)values:(nullable NSArray *)values;
278 | /// Set the path of the core keyframe animation.
279 | ///
280 | /// @param path path setted to the keyframe animation.
281 | /// @return the receiver.
282 | ///
283 | - (instancetype)path:(nullable UIBezierPath *)path;
284 | /// Set the key times to the core keyframe animation.
285 | ///
286 | /// @param keyTimes key times setted to the keyframe animation.
287 | /// @return the receiver.
288 | ///
289 | - (instancetype)keyTimes:(nullable NSArray *)keyTimes;
290 | /// Set timing functions to the core keyframe animation.
291 | ///
292 | /// @param timingFunctions timing functions setted to the keyframe animation.
293 | /// @return the receiver.
294 | ///
295 | - (instancetype)timingFunctions:(nullable NSArray *)timingFunctions;
296 | /// Set calculation mode to the core keyframe animation.
297 | ///
298 | /// @param calculationMode calculation mode setted to keyframe animation.
299 | /// @return the receiver.
300 | ///
301 | - (instancetype)calculationMode:(NSString *)calculationMode;
302 | /// Set tension values to the core keyframe animation.
303 | ///
304 | /// @param tensionValues tension values setted to the keyframe animation.
305 | /// @return the receiver.
306 | ///
307 | - (instancetype)tensionValues:(nullable NSArray *)tensionValues;
308 | /// Set the continuity valyes to the core keyframe animation.
309 | ///
310 | /// @param continuityValues continuity values setted to the keyframe animation.
311 | /// @return the receiver.
312 | ///
313 | - (instancetype)continuityValues:(nullable NSArray *)continuityValues;
314 | /// Set bias values to the core keyframe animation.
315 | ///
316 | /// @param biasValues bias values setted to the keyframe animation.
317 | /// @return the receiver.
318 | ///
319 | - (instancetype)biasValues:(nullable NSArray *)biasValues;
320 | /// Set the rotation mode to the core keyframe animation.
321 | ///
322 | /// @param rotationMode rotation mode setted to the keyframe animation.
323 | /// @return the receiver.
324 | ///
325 | - (instancetype)rotationMode:(nullable NSString *)rotationMode;
326 | @end
327 | /// CASpringAnimation/AXSpringAnimation reachable.
328 | @protocol AXSpringChainAnimatorDelegate
329 | /// Set the mass to the core spring animation.
330 | ///
331 | /// @param mass mass setted to the spring animation.
332 | /// @return the receiver.
333 | ///
334 | - (instancetype)mass:(CGFloat)mass;
335 | /// Set the stiffness to the core spring animation.
336 | ///
337 | /// @param stiffness seiffness setted to the spring animation.
338 | /// @return the receiver.
339 | ///
340 | - (instancetype)stiffness:(CGFloat)stiffness;
341 | /// Set the damping to the core spring animation.
342 | ///
343 | /// @param damping damping setted to the spring animation.
344 | /// @return the receiver.
345 | ///
346 | - (instancetype)damping:(CGFloat)damping;
347 | /// Set the initial velocity to the core spring animation.
348 | ///
349 | /// @param initialVelocity initial velocity setted to the spring animation.
350 | /// @return the receiver.
351 | ///
352 | - (instancetype)initialVelocity:(CGFloat)initialVelocity;
353 | @end
354 | /// CATransitionAnimation reachable.
355 | @protocol AXTransitionChainAnimatorDelegate
356 | /// Set type to the core transition animation.
357 | ///
358 | /// @param type tpye setted to the transtion animation.
359 | /// @return the receiver.
360 | ///
361 | - (instancetype)type:(NSString *)type;
362 | /// Set subtype to the core transition animation.
363 | ///
364 | /// @param subtype subtype setted to the transition animation.
365 | /// @return the receiver.
366 | ///
367 | - (instancetype)subtype:(NSString *)subtype;
368 | /// Set the start progress to the core transition animation.
369 | ///
370 | /// @param startProgress start progress setted to the transition animation.
371 | /// @return the receiver.
372 | ///
373 | - (instancetype)startProgress:(CGFloat)startProgress;
374 | /// Set the end progress to the core transition animation.
375 | ///
376 | /// @param endProgress end progress setted to the transition animaton.
377 | /// @return the receiver.
378 | ///
379 | - (instancetype)endProgress:(CGFloat)endProgress;
380 | /// Set the filter to the core transition animation.
381 | ///
382 | /// @param filter filter setted to the transition animation.
383 | /// @return the receiver.
384 | ///
385 | - (instancetype)filter:(id)filter;
386 | @end
387 |
388 | @class AXBasicChainAnimator;
389 | @class AXSpringChainAnimator;
390 | @class AXKeyframeChainAnimator;
391 | @class AXTransitionChainAnimator;
392 |
393 | @interface AXChainAnimator : NSObject
394 | /// Father animator.
395 | @property(weak, nonatomic, nullable) AXChainAnimator *superAnimator;
396 | /// Next to animator.
397 | @property(strong, nonatomic, nullable) AXChainAnimator *childAnimator;
398 | /// Combined animators.
399 | @property(strong, nonatomic, nullable) NSArray *combinedAnimators;
400 | /// Animated view.
401 | @property(weak, nonatomic) UIView *animatedView;
402 | /// Create a animator with a specific core animation object.
403 | + (instancetype)animatorWithAnimation:(CAAnimation *)animation;
404 | /// Required initial method.
405 | - (instancetype)initWithAnimator:(__kindof AXChainAnimator *)animator;
406 | /// Begin with a new animator and replace the receiver animator.
407 | - (instancetype)beginWith:(nonnull AXChainAnimator *)animator;
408 | /// Link a new animator to the child animator of the receiver animator.
409 | - (instancetype)nextTo:(nonnull AXChainAnimator *)animator;
410 | /// Link a new animator to the combined animators of the receiver animator.
411 | - (instancetype)combineWith:(nonnull AXChainAnimator *)animator;
412 | /// Begin with a basic animator.
413 | - (AXBasicChainAnimator *)beginBasic;
414 | /// Begin with a spring animator.
415 | - (AXSpringChainAnimator *)beginSpring;
416 | /// Begin with a keyframe animator.
417 | ///
418 | /// @return a new keyframe animator.
419 | - (AXKeyframeChainAnimator *)beginKeyframe;
420 | /*
421 | - (instancetype)beginTransition; */
422 | /// Combine with a basic animator and return the animator.
423 | - (AXBasicChainAnimator *)combineBasic;
424 | /// Combine with a spring animator and return the animator.
425 | - (AXSpringChainAnimator *)combineSpring;
426 | /// Combine with a keyframe animator.
427 | - (AXKeyframeChainAnimator *)combineKeyframe;
428 | /// Combine with a transition animator.
429 | - (AXTransitionChainAnimator *)combineTransition;
430 | /// Next to a basic animator.
431 | - (AXBasicChainAnimator *)nextToBasic;
432 | /// Next to a spring animator.
433 | - (AXSpringChainAnimator *)nextToSpring;
434 | /// Next to a keyframe animator.
435 | - (AXKeyframeChainAnimator *)nextToKeyframe;
436 | /// Next to a transition animator.
437 | - (AXTransitionChainAnimator *)nextToTransition;
438 | @end
439 |
440 | @interface AXBasicChainAnimator : AXChainAnimator
441 | /// Core animation.
442 | @property(readonly, nonatomic) CABasicAnimation *animation;
443 |
444 | - (AXKeyframeChainAnimator *)easeInElastic;
445 | - (AXKeyframeChainAnimator *)easeOutElastic;
446 | - (AXKeyframeChainAnimator *)easeInOutElastic;
447 | - (AXKeyframeChainAnimator *)easeInBounce;
448 | - (AXKeyframeChainAnimator *)easeOutBounce;
449 | - (AXKeyframeChainAnimator *)easeInOutBounce;
450 |
451 | - (AXKeyframeChainAnimator *)gravity;
452 | @end
453 |
454 | @interface AXKeyframeChainAnimator : AXChainAnimator
455 | /// Core animation.
456 | @property(readonly, nonatomic) CAKeyframeAnimation *animation;
457 | @end
458 |
459 | @interface AXSpringChainAnimator : AXBasicChainAnimator
460 | /// Core animation.
461 | @property(readonly, nonatomic) AXCASpringAnimation *animation;
462 | @end
463 |
464 | @interface AXTransitionChainAnimator : AXChainAnimator
465 | /// Core animation.
466 | @property(readonly, nonatomic) CATransition *animation;
467 | @end
468 |
469 | @interface AXChainAnimator (Animator)
470 | /// Basic animator. Begin with basic animation.
471 | @property(readonly, nonatomic, null_resettable) AXBasicChainAnimator *basic;
472 | /// Key frame animator. Begin with keyframe animation.
473 | @property(readonly, nonatomic, null_resettable) AXKeyframeChainAnimator *keyframe;
474 | /// Spring animator. Begin with spring animation.
475 | @property(readonly, nonatomic, null_resettable) AXSpringChainAnimator *spring;
476 | /// Transition animator. Begin with transition animation.
477 | @property(readonly, nonatomic, null_resettable) AXTransitionChainAnimator *transition;
478 | @end
479 |
480 | @interface AXChainAnimator (TopAnimator)
481 | /// Top animator. Might be SELF if there is not any child animator.
482 | @property(readonly, nonatomic, nonnull) __kindof AXChainAnimator *topAnimator;
483 | /// Replace the top animator in combined animators of super animator with a new animator.
484 | ///
485 | /// @param animator animator to replace.
486 | /// @warning Not implementated.
487 | ///
488 | - (instancetype)replaceCombinedAnimatorWithAnimator:(__kindof AXChainAnimator *)animator;
489 | @end
490 |
491 | @interface AXChainAnimator (AnchorPoint)
492 | /// Move anchor to a new anchor point. This will change the position of the layer.
493 | ///
494 | /// @param point a new anchor point. Between [0, 1].
495 | - (instancetype)moveAnchorToPoint:(CGPoint)point;
496 | /// Move anchor point to default anchor value.
497 | - (instancetype)anchorToDefault;
498 | /// Move anchor point to center point.
499 | - (instancetype)anchorToCenter;
500 | /// Move anchor point to top.
501 | - (instancetype)anchorToTop;
502 | /// Move anchor point to left.
503 | - (instancetype)anchorToLeft;
504 | /// Move anchor point to bottom.
505 | - (instancetype)anchorToBottom;
506 | /// Move anchor point to right.
507 | - (instancetype)anchorToRight;
508 | /// Move anchor point to left-top.
509 | - (instancetype)anchorToLeftTop;
510 | /// Move anchor point to left-bottom.
511 | - (instancetype)anchorToLeftBottom;
512 | /// Move anchor point to right-top.
513 | - (instancetype)anchorToRightTop;
514 | /// Move anchor point to right-bottom.
515 | - (instancetype)anchorToRightBottom;
516 | @end
517 | NS_ASSUME_NONNULL_END
518 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CALayer+AnchorPoint.h:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+AnchorPoint.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/2/10.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | /// Category to handler the anchor point.
28 | @interface CALayer (AnchorPoint)
29 | /// Move anchor to a new anchor point. This will change the position of the layer.
30 | ///
31 | /// @param point a new anchor point. Between [0, 1].
32 | - (void)moveAnchorToPoint:(CGPoint)point;
33 | /// Move anchor point to default anchor value.
34 | - (void)anchorToDefault;
35 | /// Move anchor point to center point.
36 | - (void)anchorToCenter;
37 | /// Move anchor point to top.
38 | - (void)anchorToTop;
39 | /// Move anchor point to left.
40 | - (void)anchorToLeft;
41 | /// Move anchor point to bottom.
42 | - (void)anchorToBottom;
43 | /// Move anchor point to right.
44 | - (void)anchorToRight;
45 | /// Move anchor point to left-top.
46 | - (void)anchorToLeftTop;
47 | /// Move anchor point to left-bottom.
48 | - (void)anchorToLeftBottom;
49 | /// Move anchor point to right-top.
50 | - (void)anchorToRightTop;
51 | /// Move anchor point to right-bottom.
52 | - (void)anchorToRightBottom;
53 | @end
54 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CALayer+AnchorPoint.m:
--------------------------------------------------------------------------------
1 | //
2 | // CALayer+AnchorPoint.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/2/10.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "CALayer+AnchorPoint.h"
27 |
28 | @implementation CALayer (AnchorPoint)
29 | - (void)moveAnchorToPoint:(CGPoint)point {
30 | // If the new point is equal to the old anchor point, return immediately。
31 | if (CGPointEqualToPoint(point, self.anchorPoint)) return;
32 |
33 | CGPoint newPoint = CGPointMake(self.bounds.size.width * point.x, self.bounds.size.height * point.y);
34 | CGPoint oldPoint = CGPointMake(self.bounds.size.width * self.anchorPoint.x, self.bounds.size.height * self.anchorPoint.y);
35 |
36 | newPoint = CGPointApplyAffineTransform(newPoint, self.affineTransform);
37 | oldPoint = CGPointApplyAffineTransform(oldPoint, self.affineTransform);
38 |
39 | CGPoint position = self.position;
40 |
41 | position.x += newPoint.x - oldPoint.x;
42 | position.y += newPoint.y - oldPoint.y;
43 |
44 | self.position = position;
45 | self.anchorPoint = point;
46 | }
47 |
48 | - (void)anchorToDefault {
49 | [self anchorToCenter];
50 | }
51 |
52 | - (void)anchorToCenter {
53 | [self moveAnchorToPoint:CGPointMake(.5, .5)];
54 | }
55 |
56 | - (void)anchorToTop {
57 | [self moveAnchorToPoint:CGPointMake(.5, .0)];
58 | }
59 |
60 | - (void)anchorToLeft {
61 | [self moveAnchorToPoint:CGPointMake(.0, .5)];
62 | }
63 |
64 | - (void)anchorToBottom {
65 | [self moveAnchorToPoint:CGPointMake(.5, 1.0)];
66 | }
67 |
68 | - (void)anchorToRight {
69 | [self moveAnchorToPoint:CGPointMake(1.0, .5)];
70 | }
71 |
72 | - (void)anchorToLeftTop {
73 | [self moveAnchorToPoint:CGPointMake(.0, .0)];
74 | }
75 |
76 | - (void)anchorToLeftBottom {
77 | [self moveAnchorToPoint:CGPointMake(.0, 1.0)];
78 | }
79 |
80 | - (void)anchorToRightTop {
81 | [self moveAnchorToPoint:CGPointMake(1.0, .0)];
82 | }
83 |
84 | - (void)anchorToRightBottom {
85 | [self moveAnchorToPoint:CGPointMake(1.0, 1.0)];
86 | }
87 | @end
88 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/AXCoreAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // AXCoreAnimation.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/11.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #ifndef AXCoreAnimation_h
27 | #define AXCoreAnimation_h
28 |
29 | #import "AXDecayAnimation.h"
30 | #import "AXSpringAnimation.h"
31 | #import "CAAnimation+Convertable.h"
32 | #import "CAAnimation+ImmediateValue.h"
33 | #import "CAMediaTimingFunction+Extends.h"
34 |
35 | #endif /* AXCoreAnimation_h */
36 | extern NSUInteger const kAXCAKeyframeAnimationFrameCount;
37 | /// Set the frame count of keyframe animation. Default is 69ps.
38 | ///
39 | /// @param count count of frames of keyframe animation.
40 | ///
41 | extern void CACVTSetFrameCountOfKeyframe(NSUInteger count);
42 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/AXDecayAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // AXDecayAnimation.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/3/31.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 |
28 | #ifndef AXDecayAnimationUnavailable
29 | #define AXDecayAnimationUnavailable(AXDecayAnimationClass)\
30 | @interface AXDecayAnimationClass (Unavailable)\
31 | - (void)setTimingFunction:(CAMediaTimingFunction *)timingFunction __attribute__((unavailable));\
32 | - (void)setValues:(NSArray *)values __attribute__((unavailable));\
33 | - (void)setPath:(CGPathRef)path __attribute__((unavailable));\
34 | - (void)setKeyTimes:(NSArray *)keyTimes __attribute__((unavailable));\
35 | - (void)setTimingFunctions:(NSArray *)timingFunctions __attribute__((unavailable));\
36 | - (void)setCalculationMode:(NSString *)calculationMode __attribute__((unavailable));\
37 | - (void)setTensionValues:(NSArray *)tensionValues __attribute__((unavailable));\
38 | - (void)setContinuityValues:(NSArray *)continuityValues __attribute__((unavailable));\
39 | - (void)setBiasValues:(NSArray *)biasValues __attribute__((unavailable));\
40 | - (void)setRotationMode:(NSString *)rotationMode __attribute__((unavailable));\
41 | @end
42 | #endif
43 |
44 | NS_ASSUME_NONNULL_BEGIN
45 | @interface AXDecayAnimation : CAKeyframeAnimation
46 | /* The initial velocity of the object attached to the spring. Defaults
47 | * to zero, which represents an unmoving object. Negative values
48 | * represent the object moving away from the spring attachment point,
49 | * positive values represent the object moving towards the spring
50 | * attachment point. */
51 | @property(assign, nonatomic) CGFloat velocity;
52 | /**
53 | @abstract The deceleration factor.
54 | @discussion Values specifies should be in the range [0, 1]. Lower values results in faster deceleration. Defaults to 0.998.
55 | */
56 | @property(assign, nonatomic) CGFloat deceleration;
57 | /**
58 | @abstract The expected duration.
59 | @discussion Derived based on input velocity and deceleration values.
60 | */
61 | @property(readonly, nonatomic) CFTimeInterval settlingDuration;
62 |
63 | @property(nullable, strong, nonatomic) id fromValue;
64 | @end
65 |
66 | AXDecayAnimationUnavailable(AXDecayAnimation)
67 | NS_ASSUME_NONNULL_END
68 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/AXDecayAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // AXDecayAnimation.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/3/31.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | #import
28 | #import "AXDecayAnimation.h"
29 | #import "CAMediaTimingFunction+Extends.h"
30 |
31 | extern NSArray * CGPointValuesWithComponents(NSArray *xValues, NSArray *yValues);
32 | extern NSArray * CGSizeValuesWithComponents(NSArray *widthValues, NSArray *heightValues);
33 | extern NSArray * CGRectValuesWithComponents(NSArray *xValues, NSArray *yValues, NSArray *widths, NSArray *heights);
34 | extern NSArray * UIColorValuesWithComponents(NSArray *redValues, NSArray *greenValues, NSArray *blueValues, NSArray *alphaValues);
35 | extern NSArray * CATransform3DValuesWithComponents(NSArray *m11, NSArray *m12, NSArray *m13, NSArray *m14, NSArray *m21, NSArray *m22, NSArray *m23, NSArray *m24, NSArray *m31, NSArray *m32, NSArray *m33, NSArray *m34, NSArray *m41, NSArray *m42, NSArray *m43, NSArray *m44);
36 |
37 | static NSArray * _AXDecayNSNumberValuesCaculationWithBeginValue(CGFloat beginNumber, NSTimeInterval duration, CAMediaTimingFunction *timing, CAKeyframeValuesFunction function) {
38 | // 69 FPS per second.
39 | NSUInteger components = (NSUInteger)ceil(69 * duration)+2;
40 |
41 | NSMutableArray *numbers = [NSMutableArray arrayWithCapacity:components];
42 |
43 | const double increment = 1.0 / (double)(components - 1);
44 |
45 | double progress = 0.0,
46 | v,
47 | value = beginNumber;
48 |
49 | NSUInteger i;
50 | // Add the begin number to the numbers in case of losing first frame.
51 | [numbers addObject:@(beginNumber)];
52 | for (i = 1; i < components; i++)
53 | {
54 | v = (function?:timing.valuesFuntion)(duration * progress * 1000, 0, 1, duration/components);
55 | value = value + v;
56 |
57 | [numbers addObject:@(value)];
58 |
59 | progress += increment;
60 | }
61 |
62 | return [numbers copy];
63 | }
64 |
65 | NSArray * _AXDecayKeyframeValuesWithBeginFrame(id fromValue, NSTimeInterval duration, CAMediaTimingFunction *timing, CAKeyframeValuesFunction function)
66 | {
67 | id beginValue;
68 | beginValue = fromValue;
69 |
70 | if ([beginValue isKindOfClass:[NSNumber class]]) {
71 | return
72 | _AXDecayNSNumberValuesCaculationWithBeginValue([beginValue floatValue], duration, timing, function);
73 | } else if ([beginValue isKindOfClass:[UIColor class]]) {
74 | const CGFloat *fromComponents = CGColorGetComponents(((UIColor*)beginValue).CGColor);
75 | return UIColorValuesWithComponents(
76 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromComponents[0], duration, timing, function),
77 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromComponents[1], duration, timing, function),
78 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromComponents[2], duration, timing, function),
79 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromComponents[3], duration, timing, function)
80 | );
81 | } else if ([beginValue isKindOfClass:[NSValue class]]) {
82 | NSString *valueType = [NSString stringWithCString:[beginValue objCType] encoding:NSStringEncodingConversionAllowLossy];
83 | if ([valueType rangeOfString:@"CGRect"].location == 1) {
84 | CGRect fromRect = [beginValue CGRectValue];
85 | return CGRectValuesWithComponents(_AXDecayNSNumberValuesCaculationWithBeginValue(fromRect.origin.x, duration, timing, function),
86 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromRect.origin.y, duration, timing, function),
87 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromRect.size.width, duration, timing, function),
88 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromRect.size.height, duration, timing, function));
89 |
90 | } else if ([valueType rangeOfString:@"CGPoint"].location == 1) {
91 | CGPoint fromPoint = [beginValue CGPointValue];
92 | return CGPointValuesWithComponents(
93 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromPoint.x, duration, timing, function),
94 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromPoint.y, duration, timing, function)
95 | );
96 |
97 | } else if ([valueType rangeOfString:@"CATransform3D"].location == 1) {
98 | CATransform3D fromTransform = [beginValue CATransform3DValue];
99 | return CATransform3DValuesWithComponents(
100 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m11, duration, timing, function),
101 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m12, duration, timing, function),
102 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m13, duration, timing, function),
103 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m14, duration, timing, function),
104 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m21, duration, timing, function),
105 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m22, duration, timing, function),
106 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m23, duration, timing, function),
107 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m24, duration, timing, function),
108 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m31, duration, timing, function),
109 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m32, duration, timing, function),
110 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m33, duration, timing, function),
111 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m34, duration, timing, function),
112 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m41, duration, timing, function),
113 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m42, duration, timing, function),
114 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m43, duration, timing, function),
115 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromTransform.m44, duration, timing, function)
116 | );
117 | } else if ([valueType rangeOfString:@"CGSize"].location == 1) {
118 | CGSize fromSize = [beginValue CGSizeValue];
119 | return CGSizeValuesWithComponents(
120 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromSize.width, duration, timing, function),
121 | _AXDecayNSNumberValuesCaculationWithBeginValue(fromSize.height, duration, timing, function)
122 | );
123 | }
124 | }
125 | return nil;
126 | }
127 |
128 | @interface AXDecayAnimation ()
129 | /// Handled ve.
130 | @property(assign, nonatomic) CGFloat handledVelocity;
131 | @end
132 |
133 | @implementation AXDecayAnimation
134 | - (instancetype)init {
135 | if (self = [super init]) {
136 | [self initializer];
137 | }
138 | return self;
139 | }
140 |
141 | - (void)initializer {
142 | _velocity = 0.0;
143 | _handledVelocity = 0.0;
144 | _deceleration = 0.998;
145 |
146 | super.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
147 | }
148 |
149 | - (void)setVelocity:(CGFloat)velocity {
150 | _velocity = velocity;
151 | _handledVelocity = _velocity;
152 | [self _setValues];
153 | }
154 |
155 | - (void)setDeceleration:(CGFloat)deceleration {
156 | _deceleration = deceleration;
157 | [self _setValues];
158 | }
159 |
160 | - (void)setTimingFunction:(CAMediaTimingFunction *)timingFunction {
161 | @throw @"Decay animation won't be effected by timing function.";
162 | }
163 |
164 | - (CFTimeInterval)settlingDuration {
165 | // compute duration till threshold velocity
166 | float scaledVelocity = _velocity / 1000.;
167 |
168 | double k = 1 * 5. / 1000.;
169 | double v = k / scaledVelocity;
170 | double d = log(_deceleration) * 1000.;
171 | double duration = log(fabs(v)) / d;
172 |
173 | // ensure velocity threshold is exceeded
174 | if (isnan(duration) || duration < 0) {
175 | duration = 0;
176 | }
177 | // return log(0.0001)/log(_deceleration);
178 | return duration;
179 | }
180 |
181 | - (void)_setValues {
182 | _handledVelocity = _velocity;
183 |
184 | NSTimeInterval duration = self.settlingDuration;
185 | super.duration = duration;
186 | NSArray *values = _AXDecayKeyframeValuesWithBeginFrame(self.fromValue, duration, self.timingFunction, ^double(double t, double b, double c, double d) {
187 | // v0 = v / 1000
188 | // v = v0 * powf(deceleration, dt);
189 | // v = v * 1000;
190 |
191 | // x0 = x;
192 | // x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration)
193 | float v0;
194 | float dt = /*(t/d)*duration*1000.*/d*1000.;
195 | float kv = powf(_deceleration, dt);
196 | float kx = _deceleration * (1 - kv) / (1 - _deceleration);
197 |
198 | v0 = _handledVelocity / 1000.;
199 | _handledVelocity = v0 * kv * 1000.;
200 | // x = x + v0 * kx;
201 | return v0*kx;
202 | });
203 |
204 | super.values = values;
205 | }
206 | @end
207 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/AXSpringAnimation.h:
--------------------------------------------------------------------------------
1 | //
2 | // AXSpringAnimation.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/8.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 |
28 | #ifndef AXCASpringAnimation
29 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
30 | #define AXCASpringAnimation CASpringAnimation
31 | #else
32 | #define AXCASpringAnimation AXSpringAnimation
33 | #endif
34 | #endif
35 | #ifndef AXSpringAnimationUnavailable
36 | #define AXSpringAnimationUnavailable(AXSpringAnimationClass)\
37 | @interface AXSpringAnimationClass (Unavailable)\
38 | - (void)setValues:(NSArray *)values __attribute__((unavailable));\
39 | - (void)setPath:(CGPathRef)path __attribute__((unavailable));\
40 | - (void)setKeyTimes:(NSArray *)keyTimes __attribute__((unavailable));\
41 | - (void)setTimingFunctions:(NSArray *)timingFunctions __attribute__((unavailable));\
42 | - (void)setCalculationMode:(NSString *)calculationMode __attribute__((unavailable));\
43 | - (void)setTensionValues:(NSArray *)tensionValues __attribute__((unavailable));\
44 | - (void)setContinuityValues:(NSArray *)continuityValues __attribute__((unavailable));\
45 | - (void)setBiasValues:(NSArray *)biasValues __attribute__((unavailable));\
46 | - (void)setRotationMode:(NSString *)rotationMode __attribute__((unavailable));\
47 | @end
48 | #endif
49 |
50 | NS_ASSUME_NONNULL_BEGIN
51 | @interface AXSpringAnimation : CAKeyframeAnimation
52 | /* The mass of the object attached to the end of the spring. Must be greater
53 | than 0. Defaults to one. */
54 |
55 | @property(assign, nonatomic) CGFloat mass;
56 |
57 | /* The spring stiffness coefficient. Must be greater than 0.
58 | * Defaults to 100. */
59 |
60 | @property(assign, nonatomic) CGFloat stiffness;
61 |
62 | /* The damping coefficient. Must be greater than or equal to 0.
63 | * Defaults to 10. */
64 |
65 | @property(assign, nonatomic) CGFloat damping;
66 |
67 | /* The initial velocity of the object attached to the spring. Defaults
68 | * to zero, which represents an unmoving object. Negative values
69 | * represent the object moving away from the spring attachment point,
70 | * positive values represent the object moving towards the spring
71 | * attachment point. */
72 |
73 | @property(assign, nonatomic) CGFloat initialVelocity;
74 |
75 | /* Returns the estimated duration required for the spring system to be
76 | * considered at rest. The duration is evaluated for the current animation
77 | * parameters. */
78 |
79 | @property(readonly, nonatomic) CFTimeInterval settlingDuration;
80 |
81 | /* The objects defining the property values being interpolated between.
82 | * All are optional, and no more than two should be non-nil. The object
83 | * type should match the type of the property being animated (using the
84 | * standard rules described in CALayer.h). The supported modes of
85 | * animation are:
86 | *
87 | * - both `fromValue' and `toValue' non-nil. Interpolates between
88 | * `fromValue' and `toValue'.
89 | *
90 | * - `fromValue' and `byValue' non-nil. Interpolates between
91 | * `fromValue' and `fromValue' plus `byValue'.
92 | *
93 | * - `byValue' and `toValue' non-nil. Interpolates between `toValue'
94 | * minus `byValue' and `toValue'. */
95 |
96 | @property(nullable, strong, nonatomic) id fromValue;
97 | @property(nullable, strong, nonatomic) id toValue;
98 | @property(nullable, strong, nonatomic) id byValue;
99 | @end
100 |
101 | AXSpringAnimationUnavailable(AXSpringAnimation)
102 | NS_ASSUME_NONNULL_END
103 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/AXSpringAnimation.m:
--------------------------------------------------------------------------------
1 | //
2 | // AXSpringAnimation.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/8.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "AXSpringAnimation.h"
27 | #import "CAMediaTimingFunction+Extends.h"
28 |
29 | extern NSArray * CAKeyframeValuesWithFrames(id fromValue, id toValue, NSTimeInterval duration, CAMediaTimingFunction *timing, CAKeyframeValuesFunction function);
30 | extern id CalculateToValueWithByValue(id value, id byValue, BOOL plus);
31 |
32 | @interface AXSpringAnimation ()
33 | {
34 | CAMediaTimingFunction *_timingFunction;
35 | }
36 | @end
37 |
38 | @implementation AXSpringAnimation
39 | - (instancetype)init {
40 | if (self = [super init]) {
41 | [self initializer];
42 | }
43 | return self;
44 | }
45 |
46 | - (void)initializer {
47 | _mass = 1;
48 | _stiffness = 100;
49 | _damping = 10;
50 | super.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
51 | _timingFunction = super.timingFunction;
52 | }
53 |
54 | - (void)setMass:(CGFloat)mass {
55 | _mass = mass;
56 | [self _setValues];
57 | }
58 |
59 | - (void)setStiffness:(CGFloat)stiffness {
60 | _stiffness = stiffness;
61 | [self _setValues];
62 | }
63 |
64 | - (void)setDamping:(CGFloat)damping {
65 | _damping = damping;
66 | [self _setValues];
67 | }
68 |
69 | - (void)setInitialVelocity:(CGFloat)initialVelocity {
70 | _initialVelocity = initialVelocity;
71 | [self _setValues];
72 | }
73 |
74 | - (void)setFromValue:(id)fromValue {
75 | _fromValue = fromValue;
76 | [self _setValues];
77 | }
78 |
79 | - (void)setByValue:(id)byValue {
80 | _byValue = byValue;
81 | [self _setValues];
82 | }
83 |
84 | - (void)setToValue:(id)toValue {
85 | _toValue = toValue;
86 | [self _setValues];
87 | }
88 |
89 | - (void)setTimingFunction:(CAMediaTimingFunction *)timingFunction {
90 | [super setTimingFunction:[CAMediaTimingFunction linear]];
91 | _timingFunction = timingFunction;
92 | [self _setValues];
93 | }
94 |
95 | - (CAMediaTimingFunction *)timingFunction {
96 | return _timingFunction;
97 | }
98 |
99 | - (CFTimeInterval)settlingDuration {
100 | double beta = _damping/(2*_mass);
101 | double omega0 = sqrt(_stiffness/_mass);
102 |
103 | double flag = -(log(0.001))/MIN(beta, omega0);
104 | double duration = -(log(0.0004))/MIN(beta, omega0);
105 |
106 | return (flag+duration)/2;
107 | }
108 |
109 | - (void)_setValues {
110 | /*
111 | self.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear]; */
112 |
113 | id fromValue;
114 | id toValue;
115 | if (self.fromValue && self.toValue) {
116 | fromValue = self.fromValue;
117 | toValue = self.toValue;
118 | } else if (self.fromValue && self.byValue) {
119 | fromValue = self.fromValue;
120 | toValue = CalculateToValueWithByValue(self.fromValue, self.byValue, YES);
121 | } else if (self.byValue && self.toValue) {
122 | fromValue = CalculateToValueWithByValue(self.toValue, self.byValue, NO);
123 | toValue = self.toValue;
124 | }
125 |
126 | if (fromValue && toValue) {
127 | super.values = CAKeyframeValuesWithFrames(fromValue, toValue, self.settlingDuration, self.timingFunction, ^double (double t, double b, double c, double d) {
128 | double flag = t > 0 ? (_timingFunction?:super.timingFunction).valuesFuntion(t, 0, 1, d)/[CAMediaTimingFunction linear].valuesFuntion(t, 0, 1, d) : 0.0;
129 | t = t/d*self.settlingDuration;
130 | if (!isnan(flag)) t *= flag;
131 | double beta = _damping/(2*_mass);
132 | double omega0 = sqrt(_stiffness/_mass);
133 | double omega = sqrt(fabs(pow(omega0, 2.0)-pow(beta, 2.0)));
134 | if (beta >= omega0) {
135 | beta = beta > omega0 ? omega0 : beta;
136 | return (1-exp(-beta*t)*(1-(_initialVelocity-beta)*t))*(c-b)+b;
137 | } else {
138 | return (1-exp(-beta*t)*(cos(omega*t)-sin(omega*t)*((_initialVelocity-beta)/omega)))*(c-b)+b;
139 | }
140 | });
141 | }
142 | }
143 | @end
144 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/CAAnimation+Convertable.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAAnimation+Convertable.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/3.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | #import
28 | #import "CAMediaTimingFunction+Extends.h"
29 | #import "AXSpringAnimation.h"
30 | #import "AXDecayAnimation.h"
31 | NS_ASSUME_NONNULL_BEGIN
32 |
33 | @interface CAKeyframeAnimation (Convertable)
34 | /// Convert animation from CABasicAnimation.
35 | /// @discusstion Converting keyframe animation from basic animation will use the values function of the timing functions automatically.
36 | /// Animation with property instance of `CGPath` will be ignored.
37 | ///
38 | /// @param basicAnimation basic animation to convert.
39 | /// @return Converted keyframe animation.
40 | ///
41 | + (nullable instancetype)animationWithBasic:(nullable CABasicAnimation *)basicAnimation;
42 | /// Convert animation from CABasicAnimation using custom values function.
43 | ///
44 | + (nullable instancetype)animationWithBasic:(nullable CABasicAnimation *)basicAnimation usingValuesFunction:(CAKeyframeValuesFunction _Nullable)valuesFunction;
45 | /// Convert animation from SpringAnimation.
46 | ///
47 | /// @param animation spring animation to convert.
48 | /// @return Converted keyframe animation.
49 | + (nullable instancetype)animationWithSpring:(nullable AXCASpringAnimation *)animation;
50 | @end
51 |
52 | @interface CABasicAnimation (Convertable)
53 | /// Convert animation from CAKeyframeAnimation.
54 | /// @discusstion Using default timing function. If the keyfram is converted from a basic animation, the timing dunction will be the one of the basic animation.
55 | ///
56 | /// @param animation keyframe animation to convert.
57 | /// @return Converted basic animation.
58 | + (nullable instancetype)animationWithKeyframe:(nullable CAKeyframeAnimation *)animation;
59 | /// Convert animation from CAKeyframeAnimation using custom timing function.
60 | ///
61 | + (nullable instancetype)animationWithKeyframe:(nullable CAKeyframeAnimation *)animation usingTimingFunction:(nullable CAMediaTimingFunction *)timingFunction;
62 | /// Convert animation from SpringAnimation.
63 | ///
64 | + (nullable instancetype)animationWithSpring:(nullable AXCASpringAnimation *)animation;
65 | @end
66 |
67 | @interface AXCASpringAnimation (Convertable)
68 | /// Convert animation from CABasicAnimation.
69 | ///
70 | + (nullable instancetype)animationWithBasic:(nullable CABasicAnimation *)animation;
71 | @end
72 |
73 | @interface AXDecayAnimation (Convertable)
74 | /// Convert animation from CABasicAnimation.
75 | ///
76 | + (nullable instancetype)animationWithBasic:(nullable CABasicAnimation *)animation;
77 | @end
78 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
79 | @interface AXSpringAnimation (Convertable_Same)
80 | /// Convert core spring animation to AXSpringAnimation.
81 | ///
82 | + (instancetype)animationWithCoreSpring:(CASpringAnimation *)animation;
83 | @end
84 |
85 | @interface CASpringAnimation (Convertable_Same)
86 | /// Convert AXSpringAnimation to core animation.
87 | ///
88 | + (instancetype)animationWithAXSpring:(AXSpringAnimation *)animation;
89 | @end
90 | #endif
91 | NS_ASSUME_NONNULL_END
92 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/CAAnimation+ImmediateValue.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAAnimation+ImmediateValue.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/4/1.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 |
28 | #ifndef AXDisableImmediateValue
29 | #define AXDisableImmediateValue(AnimationClass) \
30 | @interface AnimationClass (ImmediateValue)\
31 | - (nullable id)immediateValueAtTime:(CFTimeInterval)time error:(NSError __autoreleasing * _Nullable *_Nullable)error __attribute__((unavailable));\
32 | @end
33 | #endif
34 |
35 | extern NSUInteger const kAXImmediateValueCannotBeCalculatedErrorCode;
36 |
37 | /// Get the immediate value of the animation values.
38 | /// @discusstion Do not using this method on `CAAnimation`, `CATransition` and `CAAnimationGroup`, because these
39 | /// animations cannot be calculated. if u try to call `immediateValueAtTime` on those animations,
40 | /// There will be an exception throwed.
41 | ///
42 | @interface CAAnimation (ImmediateValue)
43 | /// Immediate value from the value function.
44 | ///
45 | /// @importance `keyTimes` and `path` properties of keyframe animation is not allowed.
46 | ///
47 | - (nullable id)immediateValueAtTime:(CFTimeInterval)time error:(NSError __autoreleasing * _Nullable *_Nullable)error;
48 | @end
49 |
50 | AXDisableImmediateValue(CATransition)
51 | AXDisableImmediateValue(CAAnimationGroup)
52 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/CAAnimation+ImmediateValue.m:
--------------------------------------------------------------------------------
1 | //
2 | // CAAnimation+ImmediateValue.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/4/1.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "CAAnimation+ImmediateValue.h"
27 | #import "CAAnimation+Convertable.h"
28 | #import "CAMediaTimingFunction+Extends.h"
29 |
30 | #ifndef _imp_AXDisableImmediateValue
31 | #define _imp_AXDisableImmediateValue(AnimationClass) \
32 | @implementation AnimationClass (ImmediateValue)\
33 | - (id)immediateValueAtTime:(CFTimeInterval)time error:(NSError *__autoreleasing _Nullable * _Nullable)error {\
34 | if (error != NULL) *error = [NSError errorWithDomain:@"axanimation_chain.caanimation.immediatevalue" code:kAXImmediateValueCannotBeCalculatedErrorCode userInfo:@{NSLocalizedFailureReasonErrorKey:[NSString stringWithFormat:@"Values of instance of animation class `%@` cannot be calculated.", NSStringFromClass(self.class)]}];\
35 | return nil;\
36 | }\
37 | @end
38 | #endif
39 |
40 | NSUInteger const kAXImmediateValueCannotBeCalculatedErrorCode = 0x2711; //10001
41 |
42 | extern NSUInteger kAXCAKeyframeAnimationFrameCount;
43 | extern id CalculateToValueWithByValue(id value, id byValue, BOOL plus);
44 | extern NSArray * CAKeyframeValuesWithFrames(id fromValue, id toValue, NSTimeInterval duration, CAMediaTimingFunction *timing, CAKeyframeValuesFunction function);
45 |
46 | static id _ImmediateValueAtIndex(id fromValue, id toValue, NSTimeInterval duration, CFTimeInterval time, CAMediaTimingFunction *timing, CAKeyframeValuesFunction function) {
47 | NSUInteger allFramesCount = ceil(kAXCAKeyframeAnimationFrameCount * duration)+2;
48 | CGFloat pt = time/duration;
49 |
50 | NSArray *values = CAKeyframeValuesWithFrames(fromValue, toValue, duration, timing, NULL);
51 |
52 | NSUInteger index = ceil(pt * allFramesCount);
53 | if (index > values.count-1) return nil;
54 |
55 | id value = values[index];
56 | return value;
57 | }
58 |
59 | @implementation CABasicAnimation (ImmediateValue)
60 | - (id)immediateValueAtTime:(CFTimeInterval)time error:(NSError *__autoreleasing _Nullable * _Nullable)error {
61 | id fromValue = self.fromValue;
62 | id toValue = self.toValue;
63 | id byValue = self.byValue;
64 |
65 | if (fromValue && toValue) {
66 | return _ImmediateValueAtIndex(fromValue, toValue, self.duration, time, self.timingFunction, NULL);
67 | } else if (fromValue && byValue) {
68 | toValue = CalculateToValueWithByValue(fromValue, byValue, YES);
69 | return _ImmediateValueAtIndex(fromValue, toValue, self.duration, time, self.timingFunction, NULL);
70 | } else if (toValue && byValue) {
71 | fromValue = CalculateToValueWithByValue(toValue, byValue, NO);
72 | return _ImmediateValueAtIndex(fromValue, toValue, self.duration, time, self.timingFunction, NULL);
73 | } else {
74 | if (fromValue) return fromValue;
75 | if (byValue) return byValue;
76 | if (toValue) return toValue;
77 | }
78 | return nil;
79 | }
80 | @end
81 | #if __IPHONE_OS_VERSION_MAX_ALLOWED >= __IPHONE_9_0
82 | @implementation CASpringAnimation (ImmediateValue)
83 | - (id)immediateValueAtTime:(CFTimeInterval)time error:(NSError *__autoreleasing _Nullable * _Nullable)error {
84 | // Conver to AXSpringAnimation.
85 | AXSpringAnimation *spring = [AXSpringAnimation animationWithCoreSpring:self];
86 | return [spring immediateValueAtTime:time error:error];
87 | return [super immediateValueAtTime:time error:error];
88 | }
89 | @end
90 | #endif
91 | @implementation CAKeyframeAnimation (ImmediateValue)
92 | - (id)immediateValueAtTime:(CFTimeInterval)time error:(NSError *__autoreleasing _Nullable * _Nullable)error {
93 | NSAssert(self.keyTimes.count==0&&self.path==NULL, @"`keyTimes` and `path` properties of keyframe animation should not be setted.");
94 |
95 | if (self.keyTimes.count != 0 || self.path != NULL) return nil;
96 | if (time >= self.duration) return self.values.lastObject;
97 |
98 | NSUInteger allFramesCount = self.values.count;
99 | CGFloat pt = time/self.duration;
100 |
101 | NSUInteger index = ceil(pt * allFramesCount);
102 | if (index > self.values.count-1) return self.values.lastObject;
103 |
104 | id value = self.values[index];
105 | return value;
106 | }
107 | @end
108 |
109 | #pragma mark - Disabled.
110 | /// Exception for `CAAnimation`.
111 | _imp_AXDisableImmediateValue(CAAnimation)
112 | /// Exception for `CATransition`.
113 | _imp_AXDisableImmediateValue(CATransition)
114 | /// Exception for `CAAnimationGroup`.
115 | _imp_AXDisableImmediateValue(CAAnimationGroup)
116 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/CAMediaTimingFunction+Extends.h:
--------------------------------------------------------------------------------
1 | //
2 | // CAMediaTimingFunction+Extends.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/3.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | NS_ASSUME_NONNULL_BEGIN
28 | typedef double (^CAKeyframeValuesFunction)(double t, double b, double c, double d);
29 | typedef double (^AXCASpringValuesFunction)(double t, double b, double c, double d, double mass, double stiffness, double damping);
30 | /// Timing functions for easings: http://easings.net/zh-cn
31 | @interface CAMediaTimingFunction (Extends)
32 | // System default:
33 | + (instancetype)defaultTimingFunction;
34 | + (instancetype)linear;
35 | + (instancetype)easeIn;
36 | + (instancetype)easeOut;
37 | + (instancetype)easeInOut;
38 | /*
39 | + (instancetype)decay; */
40 |
41 | + (instancetype)easeInSine;
42 | + (instancetype)easeOutSine;
43 | + (instancetype)easeInOutSine;
44 | + (instancetype)easeInQuad;
45 | + (instancetype)easeOutQuad;
46 | + (instancetype)easeInOutQuad;
47 | + (instancetype)easeInCubic;
48 | + (instancetype)easeOutCubic;
49 | + (instancetype)easeInOutCubic;
50 | + (instancetype)easeInQuart;
51 | + (instancetype)easeOutQuart;
52 | + (instancetype)easeInOutQuart;
53 | + (instancetype)easeInQuint;
54 | + (instancetype)easeOutQuint;
55 | + (instancetype)easeInOutQuint;
56 | + (instancetype)easeInExpo;
57 | + (instancetype)easeOutExpo;
58 | + (instancetype)easeInOutExpo;
59 | + (instancetype)easeInCirc;
60 | + (instancetype)easeOutCirc;
61 | + (instancetype)easeInOutCirc;
62 | + (instancetype)easeInBack;
63 | + (instancetype)easeOutBack;
64 | + (instancetype)easeInOutBack;
65 |
66 | - (CAKeyframeValuesFunction)valuesFuntion;
67 |
68 | + (AXCASpringValuesFunction)springValuesFunction __attribute__((unavailable));
69 |
70 | + (CAKeyframeValuesFunction)easeInElasticValuesFuntion;
71 | + (CAKeyframeValuesFunction)easeOutElasticValuesFuntion;
72 | + (CAKeyframeValuesFunction)easeInOutElasticValuesFuntion;
73 | + (CAKeyframeValuesFunction)easeInBounceValuesFuntion;
74 | + (CAKeyframeValuesFunction)easeOutBounceValuesFuntion;
75 | + (CAKeyframeValuesFunction)easeInOutBounceValuesFuntion;
76 | //
77 | // Not affected by time.
78 | //
79 | + (CAKeyframeValuesFunction)gravityValuesFunction;
80 | + (CAKeyframeValuesFunction)decayValuesFunction __attribute__((unavailable));
81 | @end
82 | NS_ASSUME_NONNULL_END
83 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/CoreAnimation/CAMediaTimingFunction+Extends.m:
--------------------------------------------------------------------------------
1 | //
2 | // CAMediaTimingFunction+Extends.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/3.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "CAMediaTimingFunction+Extends.h"
27 |
28 | @implementation CAMediaTimingFunction (Extends)
29 | + (instancetype)defaultTimingFunction {
30 | return [self functionWithName:kCAMediaTimingFunctionDefault];
31 | }
32 |
33 | + (instancetype)linear {
34 | return [self functionWithName:kCAMediaTimingFunctionLinear];
35 | }
36 |
37 | + (instancetype)easeIn {
38 | return [self functionWithName:kCAMediaTimingFunctionEaseIn];
39 | }
40 |
41 | + (instancetype)easeOut {
42 | return [self functionWithName:kCAMediaTimingFunctionEaseOut];
43 | }
44 |
45 | + (instancetype)easeInOut {
46 | return [self functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
47 | }
48 | /*
49 | + (instancetype)decay {
50 | return [self functionWithControlPoints:0.07 :0.68 :0.23 :1.0];
51 | } */
52 |
53 | + (instancetype)easeInSine {
54 | return [self functionWithControlPoints:0.47 :0 :0.745 :0.715];
55 | }
56 |
57 | + (instancetype)easeOutSine {
58 | return [self functionWithControlPoints:0.39 :0.575 :0.565 :1];
59 | }
60 |
61 | + (instancetype)easeInOutSine {
62 | return [self functionWithControlPoints:0.445 :0.05 :0.55 :0.95];
63 | }
64 |
65 | + (instancetype)easeInQuad {
66 | return [self functionWithControlPoints:0.55 :0.085 :0.68 :0.53];
67 | }
68 |
69 | + (instancetype)easeOutQuad {
70 | return [self functionWithControlPoints:0.25 :0.46 :0.45 :0.94];
71 | }
72 |
73 | + (instancetype)easeInOutQuad {
74 | return [self functionWithControlPoints:0.455 :0.03 :0.515 :0.955];
75 | }
76 |
77 | + (instancetype)easeInCubic {
78 | return [self functionWithControlPoints:0.55 :0.055 :0.675 :0.19];
79 | }
80 |
81 | + (instancetype)easeOutCubic {
82 | return [self functionWithControlPoints:0.215 :0.61 :0.355 :1];
83 | }
84 |
85 | + (instancetype)easeInOutCubic {
86 | return [self functionWithControlPoints:0.645 :0.045 :0.355 :1];
87 | }
88 |
89 | + (instancetype)easeInQuart {
90 | return [self functionWithControlPoints:0.895 :0.03 :0.685 :0.22];
91 | }
92 |
93 | + (instancetype)easeOutQuart {
94 | return [self functionWithControlPoints:0.165 :0.84 :0.44 :1];
95 | }
96 |
97 | + (instancetype)easeInOutQuart {
98 | return [self functionWithControlPoints:0.77 :0 :0.175 :1];
99 | }
100 |
101 | + (instancetype)easeInQuint {
102 | return [self functionWithControlPoints:0.755 :0.05 :0.855 :0.06];
103 | }
104 |
105 | + (instancetype)easeOutQuint {
106 | return [self functionWithControlPoints:0.23 :1 :0.32 :1];
107 | }
108 |
109 | + (instancetype)easeInOutQuint {
110 | return [self functionWithControlPoints:0.86 :0 :0.07 :1];
111 | }
112 |
113 | + (instancetype)easeInExpo {
114 | return [self functionWithControlPoints:0.95 :0.05 :0.795 :0.035];
115 | }
116 |
117 | + (instancetype)easeOutExpo {
118 | return [self functionWithControlPoints:0.19 :1 :0.22 :1];
119 | }
120 |
121 | + (instancetype)easeInOutExpo {
122 | return [self functionWithControlPoints:1 :0 :0 :1];
123 | }
124 |
125 | + (instancetype)easeInCirc {
126 | return [self functionWithControlPoints:0.6 :0.04 :0.98 :0.335];
127 | }
128 |
129 | + (instancetype)easeOutCirc {
130 | return [self functionWithControlPoints:0.075 :0.82 :0.165 :1];
131 | }
132 |
133 | + (instancetype)easeInOutCirc {
134 | return [self functionWithControlPoints:0.785 :0.135 :0.15 :0.86];
135 | }
136 |
137 | + (instancetype)easeInBack {
138 | return [self functionWithControlPoints:0.6 :-0.28 :0.735 :0.045];
139 | }
140 |
141 | + (instancetype)easeOutBack {
142 | return [self functionWithControlPoints:0.175 :0.885 :0.32 :1.275];
143 | }
144 |
145 | + (instancetype)easeInOutBack {
146 | return [self functionWithControlPoints:0.68 :-0.55 :0.265 :1.55];
147 | }
148 | #pragma clang diagnostic push
149 | #pragma clang diagnostic ignored "-Wunsequenced"
150 | static CGPoint AXBezier3ValueWithControlPoints(CGPoint p0, CGPoint p1, CGPoint p2, CGPoint p3, double t) {
151 | return CGPointMake(p0.x * pow(1-t, 3) + 3 * p1.x * t * pow(1-t, 2) + 3 * p2.x * pow(t, 2) * (1-t) + p3.x * pow(t, 3), p0.y * pow(1-t, 3) + 3 * p1.y * t * pow(1-t, 2) + 3 * p2.y * pow(t, 2) * (1-t) + p3.y * pow(t, 3));
152 | }
153 |
154 | static double AXRootsForXValueOnTimeLine(double x0, double x1, double x2, double x3, double x) {
155 | double a = x3-3*x2+3*x1-x0, b = 3*x2 - 6*x1 - 3*x0, c = 3*x1 - 3*x0, d = x0 - x;
156 | double A = pow(b, 2.0) - 3*a*c, B = b*c -9*a*d, C = pow(c, 2.0) - 3*b*d, delta = pow(B, 2.0) - 4*A*C;
157 |
158 | if (A == 0.0 && B == 0) {
159 | return -3*d/c;
160 | } else if (delta > 0.0) {
161 | double Y1 = A*b + 3*a*(-B + pow(delta, .5))/2, Y2 = A*b + 3*a*(-B - pow(delta, .5))/2, Y1Flag = Y1>0?pow(Y1, 1.0/3.0):-pow(-Y1, 1.0/3.0), Y2Flag = Y2>0?pow(Y2, 1.0/3.0):-pow(-Y2, 1.0/3.0);
162 | return (-b - Y1Flag - Y2Flag)/(3*a);
163 | } else if (delta == .0 && A != 0) {
164 | double K = B/A, R1 = -b/a + K, R2 = -K/2; R1 = R1 > 1 ? 0 : R1; R2 = R2 > 1 ? 0 : R2;
165 | return MAX(R1, R2);
166 | } else if (delta < 0 && A > 0) {
167 | double T = (2*A*b - 3*a*B)/(2*pow(A, 3.0/2.0));
168 | if (T > -1 && T < 1) {
169 | double ø = acos(T), R1 = (-b - 2*pow(A, 1.0/2.0)*cos(ø/3))/(3*a), R2 = (-b + pow(A, 1.0/2.0)*(cos(ø/3) + pow(3, 1.0/2.0)*sin(ø/3)))/(3*a), R3 = (-b + pow(A, 1.0/2.0)*(cos(ø/3) - pow(3, 1.0/2.0)*sin(ø/3)))/(3*a); R1 = R1 > 1 ? 0 : R1; R2 = R2 > 1 ? 0 : R2; R3 = R3 > 1 ? 0 : R3;
170 | return MAX(R1, MAX(R2, R3));
171 | }
172 | } return .0;
173 | }
174 | /// Params:
175 | /// t the current time.
176 | /// b the begin value.
177 | /// c the delta value.
178 | /// d the total time.
179 | - (CAKeyframeValuesFunction)valuesFuntion {
180 | CGPoint p0, p1, p2, p3;
181 | float v0[2], v1[2], v2[2], v3[2];
182 |
183 | [self getControlPointAtIndex:0 values:v0];
184 | [self getControlPointAtIndex:1 values:v1];
185 | [self getControlPointAtIndex:2 values:v2];
186 | [self getControlPointAtIndex:3 values:v3];
187 |
188 | p0.x = v0[0];
189 | p0.y = v0[1];
190 | p1.x = v1[0];
191 | p1.y = v1[1];
192 | p2.x = v2[0];
193 | p2.y = v2[1];
194 | p3.x = v3[0];
195 | p3.y = v3[1];
196 |
197 | return ^double (double t, double b, double c, double d) {
198 | double tt = AXRootsForXValueOnTimeLine(p0.x, p1.x, p2.x, p3.x, t/d);
199 | return AXBezier3ValueWithControlPoints(p0, p1, p2, p3, tt).y*(c-b)+b;
200 | };
201 | // Replaced:
202 | /*
203 | if ([flag isEqualToString:kCAMediaTimingFunctionDefault]) {
204 | return ^double (double t, double b, double c, double d) {
205 | double tt = AXRootsForXValueOnTimeLine(0, 0.25, 0.25, 1, t/d);
206 | return AXBezier3ValueWithControlPoints(CGPointMake(.0, .0), CGPointMake(0.25, 0.1), CGPointMake(0.25, 1.0), CGPointMake(1.0, 1.0), tt).y*(c-b)+b;
207 | };
208 | } else if ([flag isEqualToString:kCAMediaTimingFunctionLinear]) {
209 | return ^double (double t, double b, double c, double d) {
210 | return c*(t/=d) + b;
211 | };
212 | } else if ([flag isEqualToString:kCAMediaTimingFunctionEaseIn]) {
213 | return ^double (double t, double b, double c, double d) {
214 | double tt = AXRootsForXValueOnTimeLine(0, 0.42, 1.0, 1.0, t/d);
215 | return AXBezier3ValueWithControlPoints(CGPointMake(.0, .0), CGPointMake(0.42, .0), CGPointMake(1.0, 1.0), CGPointMake(1.0, 1.0), tt).y*(c-b)+b;
216 | };
217 | } else if ([flag isEqualToString:kCAMediaTimingFunctionEaseOut]) {
218 | return ^double (double t, double b, double c, double d) {
219 | double tt = AXRootsForXValueOnTimeLine(0, 0.0, 0.58, 1.0, t/d);
220 | return AXBezier3ValueWithControlPoints(CGPointMake(.0, .0), CGPointMake(.0, .0), CGPointMake(.58, 1.0), CGPointMake(1.0, 1.0), tt).y*(c-b)+b;
221 | };
222 | } else if ([flag isEqualToString:kCAMediaTimingFunctionEaseInEaseOut]) {
223 | return ^double (double t, double b, double c, double d) {
224 | double tt = AXRootsForXValueOnTimeLine(0, 0.42, 0.58, 1.0, t/d);
225 | return AXBezier3ValueWithControlPoints(CGPointMake(.0, .0), CGPointMake(0.42, .0), CGPointMake(.58, 1.0), CGPointMake(1.0, 1.0), tt).y*(c-b)+b;
226 | };
227 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInSine))]) {
228 | return ^double (double t, double b, double c, double d) {
229 | return -c * cos(t/d * (M_PI_2)) + c + b;
230 | };
231 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutSine))]) {
232 | return ^double (double t, double b, double c, double d) {
233 | return c * sin(t/d * (M_PI_2)) + b;
234 | };
235 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutSine))]) {
236 | return ^double (double t, double b, double c, double d) {
237 | return -c/2 * (cos(M_PI*t/d) - 1) + b;
238 | };
239 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInQuad))]) {
240 | return ^double (double t, double b, double c, double d) {
241 | return c*(t/=d)*t + b;
242 | };
243 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutQuad))]) {
244 | return ^double (double t, double b, double c, double d) {
245 | return -c *(t/=d)*(t-2) + b;
246 | };
247 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutQuad))]) {
248 | return ^double (double t, double b, double c, double d) {
249 | if ((t/=d/2) < 1) return c/2*t*t + b;
250 | return -c/2 * ((--t)*(t-2) - 1) + b;
251 | };
252 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInCubic))]) {
253 | return ^double (double t, double b, double c, double d) {
254 | return c*(t/=d)*t*t + b;
255 | };
256 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutCubic))]) {
257 | return ^double (double t, double b, double c, double d) {
258 | return c*((t=t/d-1)*t*t + 1) + b;
259 | };
260 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutCubic))]) {
261 | return ^double (double t, double b, double c, double d) {
262 | if ((t/=d/2) < 1) return c/2*t*t*t + b;
263 | return c/2*((t-=2)*t*t + 2) + b;
264 | };
265 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInQuart))]) {
266 | return ^double (double t, double b, double c, double d) {
267 | return c*(t/=d)*t*t*t + b;
268 | };
269 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutQuart))]) {
270 | return ^double (double t, double b, double c, double d) {
271 | return -c * ((t=t/d-1)*t*t*t - 1) + b;
272 | };
273 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutQuart))]) {
274 | return ^double (double t, double b, double c, double d) {
275 | if ((t/=d/2) < 1) return c/2*t*t*t*t + b;
276 | return -c/2 * ((t-=2)*t*t*t - 2) + b;
277 | };
278 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInQuint))]) {
279 | return ^double (double t, double b, double c, double d) {
280 | return c*(t/=d)*t*t*t*t + b;
281 | };
282 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutQuint))]) {
283 | return ^double (double t, double b, double c, double d) {
284 | return c*((t=t/d-1)*t*t*t*t + 1) + b;
285 | };
286 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutQuint))]) {
287 | return ^double (double t, double b, double c, double d) {
288 | if ((t/=d/2) < 1) return c/2*t*t*t*t*t + b;
289 | return c/2*((t-=2)*t*t*t*t + 2) + b;
290 | };
291 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInExpo))]) {
292 | return ^double (double t, double b, double c, double d) {
293 | return (t==0) ? b : c * pow(2, 10 * (t/d - 1)) + b;
294 | };
295 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutExpo))]) {
296 | return ^double (double t, double b, double c, double d) {
297 | return (t==d) ? b+c : c * (-pow(2, -10 * t/d) + 1) + b;
298 | };
299 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutExpo))]) {
300 | return ^double (double t, double b, double c, double d) {
301 | if (t==0) return b;
302 | if (t==d) return b+c;
303 | if ((t/=d/2) < 1) return c/2 * pow(2, 10 * (t - 1)) + b;
304 | return c/2 * (-pow(2, -10 * --t) + 2) + b;
305 | };
306 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInCirc))]) {
307 | return ^double (double t, double b, double c, double d) {
308 | return -c * (sqrt(1 - (t/=d)*t) - 1) + b;
309 | };
310 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutCirc))]) {
311 | return ^double (double t, double b, double c, double d) {
312 | return c * sqrt(1 - (t=t/d-1)*t) + b;
313 | };
314 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutCirc))]) {
315 | return ^double (double t, double b, double c, double d) {
316 | if ((t/=d/2) < 1) return -c/2 * (sqrt(1 - t*t) - 1) + b;
317 | return c/2 * (sqrt(1 - (t-=2)*t) + 1) + b;
318 | };
319 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInBack))]) {
320 | return ^double (double t, double b, double c, double d) {
321 | const double s = 1.70158;
322 | return c*(t/=d)*t*((s+1)*t - s) + b;
323 | };
324 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeOutBack))]) {
325 | return ^double (double t, double b, double c, double d) {
326 | const double s = 1.70158;
327 | return c*((t=t/d-1)*t*((s+1)*t + s) + 1) + b;
328 | };
329 | } else if ([flag isEqualToString:NSStringFromSelector(@selector(easeInOutBack))]) {
330 | return ^double (double t, double b, double c, double d) {
331 | double s = 1.70158;
332 | if ((t/=d/2) < 1) return c/2*(t*t*(((s*=(1.525))+1)*t - s)) + b;
333 | return c/2*((t-=2)*t*(((s*=(1.525))+1)*t + s) + 2) + b;
334 | };
335 | } else return NULL;
336 | */
337 | }
338 |
339 | + (AXCASpringValuesFunction)springValuesFunction {
340 | @throw @"Spring values function is unavaiable. Please use AXSpringAnimation instead.";
341 | return ^double (double t, double b, double c, double d, double mass, double stiffness, double damping) {
342 | return (1-exp(-damping/(2*mass)*t)*cos(sqrt(fabs(stiffness/mass-pow(damping/(2*mass), 2.0)))*t/(d/(-(2.0*mass*log(0.001))/damping))))*(c-b)+b;
343 | };
344 | }
345 |
346 | + (CAKeyframeValuesFunction)easeInElasticValuesFuntion {
347 | return ^double (double t, double b, double c, double d) {
348 | double s = 1.70158; double p=0; double a=c;
349 |
350 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
351 | if (a < fabs(c)) { a=c; s=p/4; }
352 | else s = p/(2*M_PI) * asin (c/a);
353 | return -(a*pow(2,10*(t-=1)) * sin( (t*d-s)*(2*M_PI)/p )) + b;
354 | };
355 | }
356 |
357 | + (CAKeyframeValuesFunction)easeOutElasticValuesFuntion {
358 | return ^double (double t, double b, double c, double d) {
359 | double s=1.70158, p=0, a=c;
360 | if (t==0) return b; if ((t/=d)==1) return b+c; if (!p) p=d*.3;
361 | if (a < fabs(c)) { a=c; s=p/4; }
362 | else s = p/(2*M_PI) * asin (c/a);
363 | return a*pow(2,-10*t) * sin( (t*d-s)*(2*M_PI)/p ) + c + b;
364 | };
365 | }
366 |
367 | + (CAKeyframeValuesFunction)easeInOutElasticValuesFuntion {
368 | return ^double (double t, double b, double c, double d) {
369 | double s=1.70158, p=0, a=c;
370 | if (t==0) return b; if ((t/=d/2)==2) return b+c; if (!p) p=d*(.3*1.5);
371 | if (a < fabs(c)) { a=c; s=p/4; }
372 | else s = p/(2*M_PI) * asin(c/a);
373 | if (t < 1) return -.5*(a*pow(2,10*(t-=1)) * sin( (t*d-s)*(2*M_PI)/p )) + b;
374 | return a*pow(2,-10*(t-=1)) * sin( (t*d-s)*(2*M_PI)/p )*.5 + c + b;
375 | };
376 | }
377 |
378 | + (CAKeyframeValuesFunction)easeInBounceValuesFuntion {
379 | return ^double (double t, double b, double c, double d) {
380 | return c - [self easeOutBounceValuesFuntion](d-t, 0, c, d) + b;
381 | };
382 | }
383 |
384 | + (CAKeyframeValuesFunction)easeOutBounceValuesFuntion {
385 | return ^double (double t, double b, double c, double d) {
386 | if ((t/=d) < (1/2.75)) {
387 | return c*(7.5625*t*t) + b;
388 | } else if (t < (2/2.75)) {
389 | return c*(7.5625*(t-=(1.5/2.75))*t + .75) + b;
390 | } else if (t < (2.5/2.75)) {
391 | return c*(7.5625*(t-=(2.25/2.75))*t + .9375) + b;
392 | } else {
393 | return c*(7.5625*(t-=(2.625/2.75))*t + .984375) + b;
394 | }
395 | };
396 | }
397 |
398 | + (CAKeyframeValuesFunction)easeInOutBounceValuesFuntion {
399 | return ^double (double t, double b, double c, double d) {
400 | if (t < d/2)
401 | return [self easeInBounceValuesFuntion](t*2, 0, c, d) * .5 + b;
402 | else
403 | return [self easeOutBounceValuesFuntion](t*2-d, 0, c, d) * .5 + c*.5 + b;
404 | };
405 | }
406 |
407 | + (CAKeyframeValuesFunction)gravityValuesFunction {
408 | return ^double (double t, double b, double c, double d) {
409 | return MIN(9.98*pow(t/=d, 2.0)/2.0, 1.0)*c+b;
410 | };
411 | }
412 |
413 | + (CAKeyframeValuesFunction)decayValuesFunction {
414 | @throw @"Decay values function is unavailable. Please use AXDecayAnimation instead.";
415 | return ^double (double t, double b, double c, double d) {
416 | // v0 = v / 1000
417 | // v = v0 * powf(deceleration, dt);
418 | // v = v * 1000;
419 |
420 | // x0 = x;
421 | // x = x0 + v0 * deceleration * (1 - powf(deceleration, dt)) / (1 - deceleration)
422 | CGFloat deceleration = 0.4;
423 | CGFloat duration = (log(0.001)/log(deceleration));
424 | return (0+1*deceleration*(1-powf(deceleration, (t/=d)*duration))/(1-deceleration))*(c-b)+b;
425 | // return (5*(t/=d)-9.98*pow(t, 2.0)/2.0)*c+b;
426 | };
427 | }
428 | #pragma clang diagnostic pop
429 | @end
430 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/Swifty/AXChainAnimator.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AXChainAnimator.swift
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/2/11.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import Foundation
27 | import AXAnimationChainSwift
28 |
29 | public extension AXChainAnimator {
30 | /// A convenient method to combine the complete function and start function.
31 | ///
32 | /// - parameter completion: completion handler of the animator.
33 | ///
34 | public func start(completion: @escaping () -> Void = {}) {
35 | // Call the complete function and start function.
36 | self.complete(completion).start()
37 | }
38 | }
39 |
40 | public extension AXChainAnimator {
41 | /// Replace self of super animator's combined animators with a new animator.
42 | ///
43 | /// - Parameter with: animator to be replaced.
44 | /// - Returns: The animator if repalce succeed, or self.
45 | ///
46 | public func replace(with animator: AXChainAnimator?) -> Self {
47 | guard let _ = animator else {
48 | return self
49 | }
50 | // If super animator does not exits, return self.
51 | guard let _ = superAnimator else {
52 | return self
53 | }
54 |
55 | var _combinedAnimators = superAnimator!.combinedAnimators
56 | // If combined animators of super does not has any elements, return self.
57 | guard let _ = _combinedAnimators else {
58 | return self
59 | }
60 | // If combined animators of super does not contain self, return self.
61 | guard _combinedAnimators!.contains(self) else {
62 | return self
63 | }
64 |
65 | _combinedAnimators![_combinedAnimators!.index(of: self)!] = animator!
66 | superAnimator!.combinedAnimators = _combinedAnimators
67 |
68 | return type(of: self).init(animator:animator!)
69 | }
70 | }
71 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/Swifty/AXCoreAnimations.swift:
--------------------------------------------------------------------------------
1 | //
2 | // AXDecayAnimation+Extensions.swift
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/4/1.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import AXAnimationChainSwift
27 |
28 | extension AXDecayAnimation {
29 | convenience public init(velocity: CGFloat, deceleration: CGFloat = 0.998, value: Any) {
30 | self.init()
31 |
32 | self.velocity = velocity
33 | self.deceleration = deceleration
34 | self.fromValue = value
35 | }
36 | }
37 |
38 | extension AXSpringAnimation {
39 | convenience public init(mass: CGFloat = 1.0, stiffness: CGFloat = 100.0, damping: CGFloat = 10.0, initialVelocity: CGFloat = 0.0) {
40 | self.init()
41 |
42 | self.mass = mass
43 | self.stiffness = stiffness
44 | self.damping = damping
45 | self.initialVelocity = initialVelocity
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/Swifty/UIView+Effects.swift:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Effects.swift
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/15.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | import UIKit
27 | import AXAnimationChainSwift
28 | /// Constant enum type of effects showing directions.
29 | ///
30 | public enum AXAnimationEffectsDirection: Int {
31 | case top, left, bottom, right
32 | }
33 | /// Calculate the settling duration of spring animation parameters: mass/stiffness/damping.
34 | ///
35 | /// - Parameters:
36 | /// - mass: mass of the spring animation to be calculated.
37 | /// - stiffness: stiffness of the spring animation to be calculated.
38 | /// - damping: damping of the spring animation to be calculated.
39 | ///
40 | /// - Returns: duration of the spring to be settling.
41 | private func settlingDurationForSpring(mass: Double, stiffness: Double, damping: Double) -> Double {
42 | let beta = damping/(2*mass)
43 | let omega0 = sqrt(stiffness/mass)
44 |
45 | let flag = -log(0.001)/min(beta, omega0)
46 | let duration = -log(0.0004)/min(beta, omega0)
47 |
48 | return (flag + duration) / 2;
49 | }
50 | /// Animation effects extension of `UIView`.
51 | ///
52 | public extension UIView {
53 | /// Run a \`tada\` animation effect on the receiver.
54 | ///
55 | /// - parameter completion: a completion closure to execute when the animation finished.
56 | ///
57 | public func tada(completion: @escaping () -> Void = {}) {
58 | chainAnimator.basic.property("transform.scale").fromValue(1.0).toValue(1.1).duration(0.15).combineBasic().property("transform.rotation").byValue(.pi/21.0).duration(0.1).autoreverses().repeatCount(2).combineBasic().beginTime(0.1).property("transform.rotation").byValue(-.pi/18.0).duration(0.1).autoreverses().repeatCount(2).nextToBasic().property("transform.scale").toValue(1.0).duration(0.15).start(completion: completion)
59 | }
60 | /// Run a \`bonuce\` animation effect on the receiver.
61 | ///
62 | /// - Parameters:
63 | /// - from: the from direction of the bonuce animation showing up.
64 | /// - completion: a completion closure to execute when the animation finished.
65 | ///
66 | public func bonuce(from direction: AXAnimationEffectsDirection = .top, completion: @escaping () -> Void = {}) {
67 | switch direction {
68 | case .top:
69 | chainAnimator.basic.property("position.y").byValue(50).toValue(self.layer.position.y).duration(0.5).easeOutBounce().start(completion: completion)
70 | case .left:
71 | chainAnimator.basic.property("position.x").byValue(50).toValue(self.layer.position.x).duration(0.5).easeOutBounce().start(completion: completion)
72 | case .bottom:
73 | chainAnimator.basic.property("position.y").fromValue(self.layer.position.y+50).toValue(self.layer.position.y).duration(0.5).easeOutBounce().start(completion: completion)
74 | default:
75 | chainAnimator.basic.property("position.x").fromValue(self.layer.position.x+50).toValue(self.layer.position.x).duration(0.5).easeOutBounce().start(completion: completion)
76 | }
77 | }
78 | /// Run a \`pulse\` animation effect on the receiver.
79 | ///
80 | /// - Parameter completion: a completion closure to execute when the animation finished.
81 | ///
82 | public func pulse(completion: @escaping () -> Void = {}) {
83 | chainAnimator.basic.property("transform.scale").byValue(0.1).duration(0.5).linear().autoreverses().start(completion: completion)
84 | }
85 | /// Run a \`shake\` animation effect on the receiver.
86 | ///
87 | /// - Parameter completion: a completion closure to execute when the animation finished.
88 | ///
89 | public func shake(completion: @escaping () -> Void = {}) {
90 | let position = layer.position
91 | chainAnimator.basic.property("position.x").fromValue(position.x-20).toValue(position.x+20).duration(0.1).linear().autoreverses().repeatCount(1.5).nextToBasic().property("position.x").toValue(position.x).duration(0.1).start(completion: completion)
92 | }
93 | /// Run a \`swing\` animation effect on the receiver.
94 | ///
95 | /// - Parameter completion: a completion closure to execute when the animation finished.
96 | ///
97 | public func swing(completion: @escaping () -> Void = {}) {
98 | chainAnimator.basic.property("transform.rotation").byValue(.pi/21.0).duration(0.1).autoreverses().repeatCount(2).combineBasic().beginTime(0.1).property("transform.rotation").byValue(-.pi/18.0).duration(0.1).autoreverses().repeatCount(2).nextToBasic().property("transform.scale").toValue(1.0).duration(0.15).start(completion: completion)
99 | }
100 | /// Run a \`snap\` animation effect on the receiver.
101 | ///
102 | /// - Parameter from: the from direction of the bonuce animation showing up.
103 | ///
104 | public func snap(from direction: AXAnimationEffectsDirection = .left) {
105 | layer.anchorToRight()
106 | chainAnimator.spring.property("position.x").byValue(150).toValue(self.layer.position.x)/*.mass(1).stiffness(100).damping(13)*/.combineSpring().property("transform.scale.x").byValue(-0.5).combineSpring().beginTime(0.5).property("transform.scale.x").byValue(0.5).mass(1).stiffness(100).damping(13).start()
107 | }
108 | /// Run a \`expand\` animation effect on the receiver.
109 | ///
110 | /// - Parameter completion: a completion closure to execute when the animation finished.
111 | ///
112 | public func expand(completion:@escaping () -> Void = {}) {
113 | chainAnimator.basic.property("transform.scale").fromValue(0.0).toValue(1.0).duration(0.5).start(completion: completion)
114 | }
115 | /// Run a \`compress\` animation effect on the receiver.
116 | ///
117 | /// - Parameter completion: a completion closure to execute when the animation finished.
118 | ///
119 | public func compress(completion: @escaping () -> Void = {}) {
120 | chainAnimator.basic.property("transform.scale").fromValue(1.0).toValue(0.0).duration(0.5).start(completion: completion)
121 | }
122 | /// Run a \`hinge\` animation effect on the receiver.
123 | ///
124 | /// - Parameter completion: a completion closure to execute when the animation finished.
125 | ///
126 | public func hinge(completion: @escaping () -> Void = {}) {
127 | layer.anchorToLeftTop()
128 | chainAnimator.spring.property("transform.rotation").fromValue(0).toValue(acos(Double(bounds.height)/Double(pow(pow(bounds.width, 2.0)+pow(bounds.height, 2.0), 0.5)))).mass(2).stiffness(100).damping(10).combineBasic().beginTime(1.0).property("position.y").byValue(UIScreen.main.bounds.height).duration(0.5).easeInCubic().start(completion: completion)
129 | }
130 | /// Run a \`drop\` animation effect on the receiver.
131 | ///
132 | /// - Parameter completion: a completion closure to execute when the animation finished.
133 | ///
134 | public func drop(completion: @escaping () -> Void = {}) {
135 | chainAnimator.basic.anchorToRightTop().property("transform.rotation").toValue(-Double.pi/18*2).duration(1.0).combineBasic().property("position.y").fromValue(layer.position.y).toValue(UIScreen.main.bounds.height+layer.position.y).duration(0.5).easeInCubic().start(completion: completion)
136 | }
137 | /// Run a morph animation effect on the receiver.
138 | ///
139 | /// - Parameter completion: a completion closure to execute when the animation finished.
140 | ///
141 | public func morph(completion: @escaping () -> Void = {}) {
142 | let duration = 0.25;
143 | let minscale = 0.8;
144 | let maxscale = 1.2;
145 | chainAnimator.basic.property("transform.scale.y").duration(duration).toValue(minscale).linear().combineBasic().property("transform.scale.x").duration(duration).toValue(maxscale).linear().nextToBasic().property("transform.scale.y").duration(duration).toValue(maxscale).linear().combineBasic().property("transform.scale.x").duration(duration).toValue(minscale).linear().nextToBasic().property("transform.scale.y").duration(duration).toValue(minscale).linear().combineBasic().property("transform.scale.x").duration(duration).toValue(maxscale).linear().nextToBasic().property("transform.scale.y").duration(duration).toValue(1.0).linear().combineBasic().property("transform.scale.x").duration(duration).toValue(1.0).linear().start(completion: completion)
146 | }
147 | }
148 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/UIView+AnimationChain.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+AnimationChain.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/22.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | NS_ASSUME_NONNULL_BEGIN
28 | @interface UIView (AnimationChain)
29 | #pragma mark - To values.
30 | - (UIView * (^)(CGRect toFrame))frameTo;
31 | - (UIView * (^)(CGRect toBounds))boundsTo;
32 | - (UIView * (^)(CGSize toSize))sizeTo;
33 | - (UIView * (^)(CGPoint toOrigin))originTo;
34 | - (UIView * (^)(CGFloat toOriginX))originXTo;
35 | - (UIView * (^)(CGFloat toOriginY))originYTo;
36 | - (UIView * (^)(CGPoint toCenter))centerTo;
37 | - (UIView * (^)(CGFloat toCenterX))centerXTo;
38 | - (UIView * (^)(CGFloat toCenterY))centerYTo;
39 | - (UIView * (^)(CGFloat toWidth))widthTo;
40 | - (UIView * (^)(CGFloat toHeight))heightTo;
41 | - (UIView * (^)(CGFloat toOpacity))opacityTo;
42 | - (UIView * (^)(UIColor *toBackgroundColor))backgroundColorTo;
43 | - (UIView * (^)(UIColor *toBorderColor))borderColorTo;
44 | - (UIView * (^)(CGFloat toBorderWidth))borderWidthTo;
45 | - (UIView * (^)(CGFloat toCornerRadius))cornerRadiusTo;
46 | - (UIView * (^)(CGFloat toScale))scaleTo;
47 | - (UIView * (^)(CGFloat toScaleX))scaleXTo;
48 | - (UIView * (^)(CGFloat toScaleY))scaleYTo;
49 | - (UIView * (^)(CGFloat toScaleZ))scaleZTo;
50 | - (UIView * (^)(CGFloat toRotate))rotateTo;
51 | - (UIView * (^)(CGFloat toRotateX))rotateXTo;
52 | - (UIView * (^)(CGFloat toRotateY))rotateYTo;
53 | - (UIView * (^)(CGFloat toRotateZ))rotateZTo;
54 | - (UIView * (^)(CGPoint toTranslate))translateTo;
55 | - (UIView * (^)(CGFloat toTranslateX))translateXTo;
56 | - (UIView * (^)(CGFloat toTranslateY))translateYTo;
57 | - (UIView * (^)(CGFloat toTranslateZ))translateZTo;
58 | #pragma mark - UIImageView.
59 | /// Animate to change the image content of UIImage object for UIImageView.
60 | - (UIView * (^)(UIImage *toImage))imageTo;
61 | #pragma mark - By values.
62 | - (UIView * (^)(CGRect byFrame))frameBy;
63 | - (UIView * (^)(CGRect byBounds))boundsBy;
64 | - (UIView * (^)(CGSize bySize))sizeBy;
65 | - (UIView * (^)(CGPoint byOrigin))originBy;
66 | - (UIView * (^)(CGFloat byOriginX))originXBy;
67 | - (UIView * (^)(CGFloat byOriginY))originYBy;
68 | - (UIView * (^)(CGPoint byCenter))centerBy;
69 | - (UIView * (^)(CGFloat byCenterX))centerXBy;
70 | - (UIView * (^)(CGFloat byCenterY))centerYBy;
71 | - (UIView * (^)(CGFloat byWidth))widthBy;
72 | - (UIView * (^)(CGFloat byHeight))heightBy;
73 | - (UIView * (^)(CGFloat byOpacity))opacityBy;
74 | - (UIView * (^)(UIColor *byBackgroundColor))backgroundColorBy;
75 | - (UIView * (^)(UIColor *byBorderColor))borderColorBy;
76 | - (UIView * (^)(CGFloat byBorderWidth))borderWidthBy;
77 | - (UIView * (^)(CGFloat byCornerRadius))cornerRadiusBy;
78 | - (UIView * (^)(CGFloat byScale))scaleBy;
79 | - (UIView * (^)(CGFloat byScaleX))scaleXBy;
80 | - (UIView * (^)(CGFloat byScaleY))scaleYBy;
81 | - (UIView * (^)(CGFloat byScaleZ))scaleZBy;
82 | - (UIView * (^)(CGFloat byRotate))rotateBy;
83 | - (UIView * (^)(CGFloat byRotateX))rotateXBy;
84 | - (UIView * (^)(CGFloat byRotateY))rotateYBy;
85 | - (UIView * (^)(CGFloat byRotateZ))rotateZBy;
86 | - (UIView * (^)(CGPoint byTranslate))translateBy;
87 | - (UIView * (^)(CGFloat byTranslateX))translateXBy;
88 | - (UIView * (^)(CGFloat byTranslateY))translateYBy;
89 | - (UIView * (^)(CGFloat byTranslateZ))translateZBy;
90 |
91 | - (dispatch_block_t)animate;
92 |
93 | #pragma mark - Timing control.
94 | /// Duration with a time duration. This will effect the last animation chain object.
95 | - (UIView * (^)(NSTimeInterval duration))duration;
96 | /// After time interval of the next animator to begin at. Must not less than 0.
97 | - (UIView * (^)(NSTimeInterval duration))after;
98 | /// Wait until former animators have finished.
99 | /* - (instancetype)wait; */
100 | #pragma mark - Effects.
101 | - (instancetype)linear;
102 | - (instancetype)easeIn;
103 | - (instancetype)easeOut;
104 | - (instancetype)easeInOut;
105 |
106 | - (instancetype)easeInSine;
107 | - (instancetype)easeOutSine;
108 | - (instancetype)easeInOutSine;
109 | - (instancetype)easeInQuad;
110 | - (instancetype)easeOutQuad;
111 | - (instancetype)easeInOutQuad;
112 | - (instancetype)easeInCubic;
113 | - (instancetype)easeOutCubic;
114 | - (instancetype)easeInOutCubic;
115 | - (instancetype)easeInQuart;
116 | - (instancetype)easeOutQuart;
117 | - (instancetype)easeInOutQuart;
118 | - (instancetype)easeInQuint;
119 | - (instancetype)easeOutQuint;
120 | - (instancetype)easeInOutQuint;
121 | - (instancetype)easeInExpo;
122 | - (instancetype)easeOutExpo;
123 | - (instancetype)easeInOutExpo;
124 | - (instancetype)easeInCirc;
125 | - (instancetype)easeOutCirc;
126 | - (instancetype)easeInOutCirc;
127 | - (instancetype)easeInBack;
128 | - (instancetype)easeOutBack;
129 | - (instancetype)easeInOutBack;
130 |
131 | - (instancetype)easeInElastic;
132 | - (instancetype)easeOutElastic;
133 | - (instancetype)easeInOutElastic;
134 | - (instancetype)easeInBounce;
135 | - (instancetype)easeOutBounce;
136 | - (instancetype)easeInOutBounce;
137 |
138 | #pragma mark - Animation.
139 | /// Change the last animation of animator to the CABasicAnimation object.
140 | - (instancetype)basic;
141 | - (instancetype)spring;
142 |
143 | #pragma mark - Target-Action.
144 | - (UIView * (^)(NSObject *target))target;
145 | - (UIView * (^)(SEL completion))complete;
146 |
147 | - (UIView * (^)(dispatch_block_t completion))completeBlock;
148 | @end
149 | NS_ASSUME_NONNULL_END
150 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/UIView+ChainAnimator.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+AnimationChian.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 | #import "AXChainAnimator.h"
28 | NS_ASSUME_NONNULL_BEGIN
29 | @protocol AXAnimationChainViewDelegate
30 | /// Animation chain object.
31 | @property(readonly, nonatomic, nonnull) id chainAnimator;
32 | @end
33 |
34 | @interface UIView (ChainAnimator)
35 | /// Default Animation chain object.
36 | @property(readonly, nonatomic, nonnull) AXChainAnimator *chainAnimator;
37 | /// Managed chain animators.
38 | @property(readonly, nonatomic, nonnull) NSArray *managedChainAnimators;
39 | /// Add chain animator.
40 | - (void)addChainAnimator:(nonnull AXChainAnimator *)animator;
41 | /// Animate all the managed chain animators.
42 | - (void)animateChain;
43 | @end
44 |
45 | @interface AXChainAnimator (UIViewChainAnimator)
46 | + (AXBasicChainAnimator *)basic;
47 | + (AXSpringChainAnimator *)spring;
48 | + (AXKeyframeChainAnimator *)keyframe;
49 | + (AXTransitionChainAnimator *)transition;
50 | @end
51 |
52 | @interface AXChainAnimator (ManagedAnimators)
53 | /// Remove the animator from the animated view.
54 | /// @discusstion If the animator is managed by the animated view, then remove the animator and return YES or NO.
55 | ///
56 | - (BOOL)removeFromAnimatedView;
57 | @end
58 | NS_ASSUME_NONNULL_END
59 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/UIView+ChainAnimator.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+AnimationChian.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "UIView+ChainAnimator.h"
27 | #import
28 |
29 | static char *kAXManagedChainAnimators = "__managed";
30 |
31 | @implementation UIView (ChainAnimator)
32 | - (AXChainAnimator *)chainAnimator {
33 | AXChainAnimator *chain = objc_getAssociatedObject(self, _cmd);
34 | if (!chain) {
35 | chain = [[AXChainAnimator alloc] init];
36 | chain.animatedView = self;
37 | objc_setAssociatedObject(self, _cmd, chain, OBJC_ASSOCIATION_RETAIN_NONATOMIC);
38 | }
39 | return chain;
40 | }
41 |
42 | - (NSArray *)managedChainAnimators {
43 | return objc_getAssociatedObject(self, kAXManagedChainAnimators) ?: @[];
44 | }
45 |
46 | - (void)addChainAnimator:(AXChainAnimator *)animator {
47 | animator.animatedView = self;
48 |
49 | NSMutableArray *managed = [objc_getAssociatedObject(self, kAXManagedChainAnimators) mutableCopy] ?: [NSMutableArray array];
50 | [managed addObject:animator];
51 |
52 | objc_setAssociatedObject(self, kAXManagedChainAnimators, [managed copy], OBJC_ASSOCIATION_RETAIN_NONATOMIC);
53 | }
54 |
55 | - (void)animateChain {
56 | for (AXChainAnimator *animator in self.managedChainAnimators) {
57 | [animator start];
58 | }
59 | }
60 | @end
61 |
62 | @implementation AXChainAnimator (UIViewChainAnimator)
63 | + (AXBasicChainAnimator *)basic {
64 | return AXChainAnimator.new.basic;
65 | }
66 |
67 | + (AXSpringChainAnimator *)spring {
68 | return AXChainAnimator.new.spring;
69 | }
70 |
71 | + (AXKeyframeChainAnimator *)keyframe {
72 | return AXChainAnimator.new.keyframe;
73 | }
74 |
75 | + (AXTransitionChainAnimator *)transition {
76 | return AXChainAnimator.new.transition;
77 | }
78 | @end
79 |
80 | @implementation AXChainAnimator (ManagedAnimators)
81 | - (BOOL)removeFromAnimatedView {
82 | NSMutableArray *managed = [self.animatedView.managedChainAnimators mutableCopy];
83 | if ([managed containsObject:self]) {
84 | [managed removeObject:self]; return YES;
85 | } else {
86 | return NO;
87 | }
88 | }
89 | @end
90 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/UIView+Effects.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Effects.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/14.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import
27 |
28 | @interface UIView (Effects)
29 | - (void)ef_tada;
30 | - (void)ef_bonuce;
31 | - (void)ef_pulse;
32 | - (void)ef_shake;
33 |
34 | - (void)ef_swing;
35 | - (void)ef_expand;
36 | - (void)ef_compress;
37 | - (void)ef_hinge;
38 | - (void)ef_drop;
39 | @end
40 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/UIView+Effects.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIView+Effects.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/14.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 | // Permission is hereby granted, free of charge, to any person obtaining a copy
9 | // of this software and associated documentation files (the "Software"), to deal
10 | // in the Software without restriction, including without limitation the rights
11 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
12 | // copies of the Software, and to permit persons to whom the Software is
13 | // furnished to do so, subject to the following conditions:
14 | //
15 | // The above copyright notice and this permission notice shall be included in all
16 | // copies or substantial portions of the Software.
17 | //
18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
21 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
22 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
23 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
24 | // SOFTWARE.
25 |
26 | #import "UIView+Effects.h"
27 | #import "UIView+ChainAnimator.h"
28 | #import "AXChainAnimator+Block.h"
29 | #import "CALayer+AnchorPoint.h"
30 |
31 | @implementation UIView (Effects)
32 |
33 | - (void)ef_tada {
34 | self.chainAnimator.basic.property(@"transform.scale").fromValue(@1.0).toValue(@1.1).duration(0.15).combineBasic.property(@"transform.rotation").byValue(@(M_PI/21.0)).duration(0.1).autoreverses.repeatCount(2).combineBasic.beginTime(0.1).property(@"transform.rotation").byValue(@(-M_PI/18.0)).duration(0.1).autoreverses.repeatCount(2).nextToBasic.property(@"transform.scale").toValue(@1.0).duration(0.15).animate();
35 | }
36 |
37 | - (void)ef_bonuce {
38 | self.chainAnimator.basic.property(@"position.y").byValue(@50).toValue(@(self.layer.position.y)).duration(0.5).easeOutBounce.animate();
39 | }
40 |
41 | - (void)ef_pulse {
42 | self.chainAnimator.basic.property(@"transform.scale").byValue(@0.1).duration(0.5).linear.autoreverses.animate();
43 | }
44 |
45 | - (void)ef_shake {
46 | CGPoint position = self.layer.position;
47 | self.chainAnimator.basic.property(@"position.x").fromValue(@(position.x-20)).toValue(@(position.x+20)).duration(0.1).linear.autoreverses.repeatCount(1.5).nextToBasic.property(@"position.x").toValue(@(position.x)).duration(0.1).linear.animate();
48 | }
49 |
50 | - (void)ef_swing {
51 | self.chainAnimator.basic.property(@"transform.rotation").byValue(@(M_PI/21.0)).duration(0.1).autoreverses.repeatCount(2).combineBasic.beginTime(0.1).property(@"transform.rotation").byValue(@(-M_PI/18.0)).duration(0.1).autoreverses.repeatCount(2).nextToBasic.property(@"transform.scale").toValue(@1.0).duration(0.15).animate();
52 | }
53 |
54 | - (void)ef_expand {
55 | self.chainAnimator.basic.property(@"transform.scale").fromValue(@.0).toValue(@1).duration(0.5).animate();
56 | }
57 |
58 | - (void)ef_compress {
59 | self.chainAnimator.basic.property(@"transform.scale").fromValue(@1).toValue(@.0).duration(0.5).animate();
60 | }
61 |
62 | - (void)ef_hinge {
63 | [self.layer anchorToLeftTop];
64 | self.chainAnimator.spring.property(@"transform.rotation").fromValue(@0).toValue(@(acos(self.bounds.size.height/pow(pow(CGRectGetWidth(self.bounds), 2.0) + pow(CGRectGetHeight(self.bounds), 2.0), 0.5)))).mass(2.0).stiffness(100).damping(10).combineBasic.beginTime(1.0).property(@"position.y").fromValue(@(self.layer.position.y)).toValue(@(self.layer.position.y + [UIScreen mainScreen].bounds.size.height)).duration(0.5).easeInCubic.animate();
65 | }
66 |
67 | - (void)ef_drop {
68 | self.chainAnimator.beginBasic.anchorToRightTop.property(@"transform.rotation").toValue(@(-M_PI/18*2)).duration(1.0).combineBasic.property(@"position.y").fromValue(@(self.layer.position.y)).toValue(@([UIScreen mainScreen].bounds.size.height+self.layer.position.y)).duration(0.5).easeInCubic.animate();
69 | }
70 | @end
71 |
--------------------------------------------------------------------------------
/AXAnimationChain/Classes/module.modulemap:
--------------------------------------------------------------------------------
1 | module AXAnimationChainSwift {
2 | header "AXChainAnimator.h"
3 | header "UIView+ChainAnimator.h"
4 | header "CoreAnimation/AXCoreAnimation.h"
5 |
6 | header "UIView+Effects.h"
7 |
8 | header "CALayer+AnchorPoint.h"
9 |
10 | export *
11 | }
12 |
--------------------------------------------------------------------------------
/AXAnimationChain/DecayAnimationViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // DecayAnimationViewController.swift
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/4/1.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import ObjectiveC
11 | import AXAnimationChainSwift
12 |
13 | extension UIView {
14 | private struct _AssociatedObjectKey {
15 | static let touchsBeganKey = "touchsBegan"
16 | }
17 | internal var touchsBegan: ((Set, UIEvent?) -> Void)? {
18 | get { return objc_getAssociatedObject(self, _AssociatedObjectKey.touchsBeganKey) as? ((Set, UIEvent?) -> Void) }
19 | set { objc_setAssociatedObject(self, _AssociatedObjectKey.touchsBeganKey, newValue, .OBJC_ASSOCIATION_COPY_NONATOMIC) }
20 | }
21 | override open func touchesBegan(_ touches: Set, with event: UIEvent?) {
22 | super.touchesBegan(touches, with: event)
23 | // print("\((String(#file) as NSString).lastPathComponent)")
24 | touchsBegan?(touches, event)
25 | }
26 | }
27 |
28 | class DecayAnimationViewController: UIViewController, UIGestureRecognizerDelegate {
29 |
30 | @IBOutlet weak var animatedView: UIView!
31 | weak var panGesture: UIPanGestureRecognizer?
32 | weak var longPressGesture: UILongPressGestureRecognizer?
33 |
34 | var shouldBeginInactiveOfAnimatedView = false
35 |
36 | override func viewDidLoad() {
37 | super.viewDidLoad()
38 |
39 | // Do any additional setup after loading the view.
40 | // Add pan ges ture to the animated view.
41 | let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePanGesture(_:)))
42 | pan.delegate = self
43 | view.addGestureRecognizer(pan)
44 | panGesture = pan
45 |
46 | // let tap = UITapGestureRecognizer(target: self, action: #selector(handleTagGesture(_:)))
47 | // tap.delegate = self
48 | // view.addGestureRecognizer(tap)
49 |
50 | let longPress = UILongPressGestureRecognizer(target: self, action: #selector(handleLongPressGesture(_:)))
51 | longPress.delegate = self
52 | longPress.minimumPressDuration = 0.0001
53 | // view.addGestureRecognizer(longPress)
54 | // longPressGesture = longPress
55 |
56 | view.touchsBegan = { [unowned self] touchs, event in
57 | self._applyImmediateValueOfAnimatedView()
58 | }
59 | }
60 |
61 | override func didReceiveMemoryWarning() {
62 | super.didReceiveMemoryWarning()
63 | // Dispose of any resources that can be recreated.
64 | }
65 |
66 | // MARK: Actions.
67 | @objc
68 | private func handleTagGesture(_ genture: UITapGestureRecognizer) {
69 | // _applyImmediateValueOfAnimatedView()
70 | print("State of tap gesture: \(genture.state.rawValue)")
71 | }
72 |
73 | @objc
74 | private func handleLongPressGesture(_ genture: UILongPressGestureRecognizer) {
75 | // _applyImmediateValueOfAnimatedView()
76 | print("State of long press gesture: \(genture.state.rawValue)")
77 | }
78 |
79 | @objc
80 | private func handlePanGesture(_ gesture: UIPanGestureRecognizer) {
81 | var point = gesture.location(in: view)
82 |
83 | switch gesture.state {
84 | case .possible: fallthrough
85 | case .began:
86 | _applyImmediateValueOfAnimatedView()
87 |
88 | point = gesture.location(in: view)
89 |
90 | if animatedView.frame.contains(point) {
91 | shouldBeginInactiveOfAnimatedView = true
92 | } else {
93 | shouldBeginInactiveOfAnimatedView = false
94 | }
95 |
96 | let pauseTime = animatedView.layer.convertTime(CACurrentMediaTime(), from: nil)
97 | print("pause time: \(pauseTime)")
98 | case .changed:
99 | /*
100 | point.x = max(animatedView.frame.width/2+64, point.x)
101 | point.y = max(animatedView.frame.height/2+64, point.y)
102 | point.x = min(view.frame.width-animatedView.frame.width/2, point.x)
103 | point.y = min(view.frame.height-animatedView.frame.height/2, point.y)
104 | */
105 | guard shouldBeginInactiveOfAnimatedView else { break }
106 | animatedView.center = point
107 | case .ended:
108 | guard shouldBeginInactiveOfAnimatedView else { break }
109 | point = gesture.location(in: view)
110 | print("view's center:\(String(describing: animatedView.center)), layer's position:\(String(describing: animatedView.layer.position))")
111 |
112 | let ve = gesture.velocity(in: animatedView)
113 | let decayx = AXDecayAnimation(keyPath: "position.x")
114 | decayx.fromValue = point.x
115 | decayx.velocity = ve.x
116 | decayx.isRemovedOnCompletion=false
117 | decayx.fillMode=kCAFillModeForwards
118 | // decayx.timingFunction = CAMediaTimingFunction.default()
119 | // decayx.isAdditive = true
120 | let decayy = AXDecayAnimation(keyPath: "position.y")
121 | decayy.fromValue = point.y
122 | decayy.velocity = ve.y
123 | decayy.isRemovedOnCompletion=false
124 | decayy.fillMode=kCAFillModeForwards
125 | // decayy.timingFunction = CAMediaTimingFunction.default()
126 | // decayy.isAdditive = true
127 | CATransaction.setCompletionBlock({[weak self] () -> Void in
128 | // print("view's center:\(String(describing: self?.animatedView.center)), layer's position:\(String(describing: self?.animatedView.layer.position))")
129 | // self?.animatedView.layer.position = CGPoint(x: decayx.values?.last as! Double, y: decayy.values?.last as! Double)
130 | // self?.animatedView.layer.removeAllAnimations()
131 | // print("view's center:\(String(describing: self?.animatedView.center)), layer's position:\(String(describing: self?.animatedView.layer.position))")
132 | self?._applyImmediateValueOfAnimatedView()
133 | })
134 | CATransaction.begin()
135 | CATransaction.setDisableActions(false)
136 | animatedView.layer.add(decayx, forKey: "position.x")
137 | animatedView.layer.add(decayy, forKey: "position.y")
138 | CATransaction.commit()
139 |
140 | case .cancelled: break
141 | case .failed: break
142 | // default: break
143 | }
144 | }
145 |
146 | // MARK: Private
147 | private func _applyImmediateValueOfAnimatedView() {
148 | defer {
149 | animatedView.layer.removeAllAnimations()
150 | }
151 | guard let animationKeys = animatedView.layer.animationKeys() else { return }
152 | for key in animationKeys {
153 | guard let animation = animatedView.layer.animation(forKey: key) as? AXDecayAnimation else { continue }
154 |
155 | let beginTime = animation.beginTime
156 | // let timeOffset = animation.timeOffset
157 |
158 | // print("begin time: \(beginTime), time offset: \(timeOffset)")
159 | // print("current time: \(CACurrentMediaTime())")
160 |
161 | let time = CACurrentMediaTime()-beginTime
162 | guard let immediateValue = try? animation.immediateValue(atTime: time) else { continue }
163 |
164 | animatedView.layer.setValue(immediateValue, forKeyPath: animation.keyPath!)
165 | }
166 | }
167 |
168 | // MARK: UIGestureRecognizerDelegate.
169 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWith otherGestureRecognizer: UIGestureRecognizer) -> Bool {
170 | if gestureRecognizer.isKind(of: UITapGestureRecognizer.self) {
171 | return false
172 | }
173 | return false
174 | }
175 |
176 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldRequireFailureOf otherGestureRecognizer: UIGestureRecognizer) -> Bool {
177 | if gestureRecognizer == longPressGesture && otherGestureRecognizer == panGesture {
178 | return true
179 | }
180 | return false
181 | }
182 |
183 | func gestureRecognizer(_ gestureRecognizer: UIGestureRecognizer, shouldBeRequiredToFailBy otherGestureRecognizer: UIGestureRecognizer) -> Bool {
184 | if gestureRecognizer == panGesture && otherGestureRecognizer == longPressGesture {
185 | return true
186 | }
187 | return false
188 | }
189 | /*
190 | // MARK: - Navigation
191 |
192 | // In a storyboard-based application, you will often want to do a little preparation before navigation
193 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
194 | // Get the new view controller using segue.destinationViewController.
195 | // Pass the selected object to the new view controller.
196 | }
197 | */
198 |
199 | }
200 |
--------------------------------------------------------------------------------
/AXAnimationChain/ImageAnimationViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAnimationViewController.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/14.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ImageAnimationViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/AXAnimationChain/ImageAnimationViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ImageAnimationViewController.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/14.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 |
9 | #import "ImageAnimationViewController.h"
10 | #import "UIView+AnimationChain.h"
11 | #import "UIView+ChainAnimator.h"
12 |
13 | @interface ImageAnimationViewController ()
14 | /// Image view.
15 | @property(weak, nonatomic) IBOutlet UIImageView *imageView;
16 | @end
17 |
18 | @implementation ImageAnimationViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | // Do any additional setup after loading the view.
23 | }
24 |
25 | - (void)didReceiveMemoryWarning {
26 | [super didReceiveMemoryWarning];
27 | // Dispose of any resources that can be recreated.
28 | }
29 |
30 | - (IBAction)animate:(id)sender {
31 | [_imageView.layer removeAllAnimations];
32 | _imageView.after(0.5).imageTo([UIImage imageNamed:@"image2"]).duration(0.8).animate();
33 | }
34 |
35 | @end
36 |
--------------------------------------------------------------------------------
/AXAnimationChain/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 |
--------------------------------------------------------------------------------
/AXAnimationChain/StageAnimationsViewController.swift:
--------------------------------------------------------------------------------
1 | //
2 | // StageAnimationsViewController.swift
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/1/14.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 |
9 | import UIKit
10 | import AXAnimationChainSwift
11 |
12 | class StageAnimationsViewController: UIViewController {
13 |
14 | @IBOutlet weak var stageLabel: UILabel!
15 | @IBOutlet weak var stageView: UIView!
16 |
17 | override func viewDidLoad() {
18 | super.viewDidLoad()
19 |
20 | // Do any additional setup after loading the view.
21 | }
22 |
23 | override func viewDidAppear(_ animated: Bool) {
24 | super.viewDidAppear(animated)
25 |
26 | stageView.chainAnimator.basic.property("cornerRadius").toValue(8.0).duration(0.8).start()
27 | }
28 |
29 | override func didReceiveMemoryWarning() {
30 | super.didReceiveMemoryWarning()
31 | // Dispose of any resources that can be recreated.
32 | }
33 |
34 | @IBAction func change(_ sender: UIButton) {
35 | stageView.layer.removeAllAnimations()
36 | stageView.originY(to: 400).duration(1.0).size(to: CGSize(width: 100, height: 100)).duration(1.0).spring().animate(as: .bounce(.out)) {
37 | print("Finished chain animation.")
38 | }
39 | }
40 |
41 | @IBAction func chain(_ sender: UIButton) {
42 | let animator1 = AXChainAnimator.basic().property("position.x").byValue(50).duration(0.5)
43 | let animator2 = AXChainAnimator.spring().property("position.y").byValue(50)
44 |
45 | stageView.add(animator1)
46 | stageView.add(animator2)
47 |
48 | stageView.animateChain()
49 |
50 | let _ = stageView.managedChainAnimators.map { (animator) -> Void in
51 | animator.removeFromAnimatedView()
52 | }
53 | }
54 |
55 | @IBAction func animate(_ sender: UIButton) {
56 | stageLabel.layer.removeAllAnimations()
57 | stageView.layer.removeAllAnimations()
58 | stageLabel.layer.anchorToDefault()
59 | stageView.layer.anchorToDefault()
60 |
61 | let alert = UIAlertController(title: "Effects", message: nil, preferredStyle: .actionSheet);
62 | alert.addAction(UIAlertAction(title: "Tada", style: .default, handler: { (action :UIAlertAction) in
63 | self.stageView.tada()
64 | self.stageLabel.tada()
65 | }))
66 | alert.addAction(UIAlertAction(title: "Bonuce", style: .default, handler: { (action :UIAlertAction) in
67 | self.stageView.bonuce()
68 | self.stageLabel.bonuce()
69 | }))
70 | alert.addAction(UIAlertAction(title: "Pulse", style: .default, handler: { (action :UIAlertAction) in
71 | self.stageView.pulse()
72 | self.stageLabel.pulse()
73 | }))
74 | alert.addAction(UIAlertAction(title: "Shake", style: .default, handler: { (action :UIAlertAction) in
75 | self.stageView.shake()
76 | self.stageLabel.shake()
77 | }))
78 | alert.addAction(UIAlertAction(title: "Swing", style: .default, handler: { [unowned self](action) in
79 | self.stageLabel.swing()
80 | self.stageView.swing()
81 | }))
82 | alert.addAction(UIAlertAction(title: "Snap", style: .default, handler: { (action: UIAlertAction) in
83 | self.stageView.snap()
84 | self.stageLabel.snap(from: .top)
85 | }))
86 | alert.addAction(UIAlertAction(title: "Expand", style: .default, handler: { [unowned self](action) in
87 | self.stageLabel.expand {
88 | print("Finished expand animation effect on stage label.")
89 | }
90 | self.stageView.expand()
91 | }))
92 | alert.addAction(UIAlertAction(title: "Compress", style: .default, handler: { [unowned self](action) in
93 | self.stageLabel.compress {
94 | print("Finished compress animation effect on stage label.")
95 | }
96 | self.stageView.compress()
97 | }))
98 | alert.addAction(UIAlertAction(title: "Hinge", style: .default, handler: { [unowned self](alert) in
99 | self.stageLabel.hinge()
100 | self.stageView.hinge()
101 | }))
102 | alert.addAction(UIAlertAction(title: "Drop", style: .default, handler: { [unowned self](action) in
103 | self.stageLabel.drop()
104 | self.stageView.drop()
105 | }))
106 | alert.addAction(UIAlertAction(title: "Morph", style: .default, handler: { [unowned self](action) in
107 | self.stageLabel.morph()
108 | self.stageView.morph()
109 | }))
110 | alert.addAction(UIAlertAction(title: "Cancel", style: .cancel, handler: nil))
111 | present(alert, animated: true, completion: nil)
112 | }
113 |
114 | /*
115 | // MARK: - Navigation
116 |
117 | // In a storyboard-based application, you will often want to do a little preparation before navigation
118 | override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
119 | // Get the new view controller using segue.destinationViewController.
120 | // Pass the selected object to the new view controller.
121 | }
122 | */
123 |
124 | }
125 |
--------------------------------------------------------------------------------
/AXAnimationChain/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/AXAnimationChain/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "UIView+ChainAnimator.h"
11 | #import "UIView+AnimationChain.h"
12 | #import "AXChainAnimator+Block.h"
13 |
14 | @interface ViewController ()
15 | /// Transition view.
16 | @property(weak, nonatomic) IBOutlet UIView *transitionView;
17 | /// Sublayer.
18 | @property(weak, nonatomic) CALayer *sublayer;
19 | @end
20 |
21 | @implementation ViewController
22 |
23 | - (void)viewDidLoad {
24 | [super viewDidLoad];
25 | // Do any additional setup after loading the view, typically from a nib.
26 | /*
27 | CALayer *layer = [CALayer layer];
28 | layer.backgroundColor = [UIColor whiteColor].CGColor;
29 | layer.frame = CGRectMake(0, 0, 20, 20);
30 | [_transitionView.layer addSublayer:layer];
31 | _sublayer = layer;
32 | */
33 | // [[[[self.view.animationChain beginWith:[CAAnimation animation]] nextTo:[CAKeyframeAnimation animation]] nextTo:[CAAnimationGroup animation]] combineWith:[CABasicAnimation animation]];
34 |
35 |
36 | }
37 |
38 |
39 | - (void)didReceiveMemoryWarning {
40 | [super didReceiveMemoryWarning];
41 | // Dispose of any resources that can be recreated.
42 | }
43 |
44 |
45 | - (IBAction)changePositionOfLayerOfTransitionView:(id)sender {
46 | /*
47 | [CATransaction begin];
48 | [CATransaction setDisableActions:YES];
49 | CGPoint position = _sublayer.position;
50 | position.y += 10;
51 | _sublayer.position = position;
52 | [CATransaction commit];
53 | */
54 | // [[_transitionView.animationChain.basic property:@"--"] toValue:];
55 | // [[[[[_transitionView.animationChain.basic property:@"position"] toValue:[NSValue valueWithCGPoint:CGPointMake(100, 300)]] easeOut] duration:0.5] start];
56 | // [[[[[[_transitionView.animationChain.basic property:@"position"] toValue:[NSValue valueWithCGPoint:CGPointMake(100, 300)]] easeOut] duration:0.5] combineWith:[[[_transitionView.animationChain.spring property:@"bounds"] toValue:[NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]] duration:1.5]] start];
57 | [_transitionView.layer removeAllAnimations];
58 | // _transitionView.animationChain.basic.property(@"position").toValue([NSValue valueWithCGPoint:CGPointMake(100, 300)]).easeOut.duration(0.5).combineWith(_transitionView.animationChain.spring.property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(1.0).combineWith(_transitionView.animationChain.spring.property(@"transform.rotation").toValue(@(M_PI_4)).easeInOut.duration(2.0).nextTo(_transitionView.animationChain.basic.property(@"position").toValue([NSValue valueWithCGPoint:self.view.center]).duration(2.0)))).animate();
59 | // _transitionView.animationChain.basic.property(@"position").toValue([NSValue valueWithCGPoint:CGPointMake(100, 300)]).easeOut.duration(0.5).combineWith(_transitionView.animationChain.spring.property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(1.0).combineWith(_transitionView.animationChain.basic.property(@"transform.rotation").toValue(@(M_PI_4)).easeInOut.duration(1.5))).animate();
60 |
61 | // _transitionView.animationChain.basic.property(@"position").toValue([NSValue valueWithCGPoint:CGPointMake(100, 300)]).duration(0.5).nextTo(_transitionView.animationChain.basic).property(@"transform.rotation").toValue(@(M_PI_4)).easeInOut.duration(1.5).nextTo(_transitionView.animationChain.basic).property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(2.0).nextTo(_transitionView.animationChain.basic).property(@"position").toValue([NSValue valueWithCGPoint:self.view.center]).duration(2.0).animate();
62 |
63 | _transitionView.chainAnimator.basic.target(self).complete(@selector(complete:)).property(@"position").toValue([NSValue valueWithCGPoint:CGPointMake(100, self.view.center.y)]).easeInBack.duration(0.5).combineSpring.target(self).complete(@selector(complete:)).property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(0.5).repeatCount(5).autoreverses.combineSpring.target(self).complete(@selector(complete:)).property(@"transform.rotation").toValue(@(M_PI_4)).duration(0.5).repeatCount(3).beginTime(1.0).autoreverses.nextToBasic.property(@"position").toValue([NSValue valueWithCGPoint:self.view.center]).duration(0.5).combineSpring.property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(0.8).nextToBasic.property(@"transform.rotation").toValue(@(M_PI_4)).duration(1.0).animate();
64 | // self.view.spring.backgroundColorTo([UIColor colorWithRed:1.000 green:0.988 blue:0.922 alpha:1.00]).animate();
65 |
66 | // _transitionView.animationChain.basic.property(@"position").toValue([NSValue valueWithCGPoint:CGPointMake(100, 300)]).easeInOut.duration(0.5).repeatCount(2).repeatDuration(.0).autoreverses.animate();
67 |
68 | // _transitionView.animationChain.spring.property(@"bounds").duration(1.5).toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).autoreverses.animate();
69 |
70 | // _transitionView.animationChain.basic.property(@"position").easeInOut.byValue([NSValue valueWithCGPoint:CGPointMake(0, 300)]).duration(1.0).combineWith(_transitionView.animationChain.spring.property(@"transform.scale")).beginTime(0.5).duration(1.0).toValue(@(0.5)).animate();
71 | }
72 |
73 | - (void)complete:(AXChainAnimator *)sender {
74 | NSLog(@"%@", sender);
75 | }
76 |
77 | - (IBAction)simpleHandler:(id)sender {
78 | [_transitionView.layer removeAllAnimations];
79 | _transitionView.spring.sizeTo(CGSizeMake(100, 100)).animate();
80 | UIAlertController *alert = [UIAlertController alertControllerWithTitle:@"Animation chains." message:nil preferredStyle:UIAlertControllerStyleActionSheet];
81 | [alert addAction:[UIAlertAction actionWithTitle:@"centerBy.sizeBy.cornerRadiusBy" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
82 | [_transitionView.layer removeAllAnimations];
83 | _transitionView.spring.centerBy(CGPointMake(0, 100)).easeOut.spring.sizeBy(CGSizeMake(100, 100)).spring.cornerRadiusBy(4).animate();
84 | }]];
85 | [alert addAction:[UIAlertAction actionWithTitle:@"centerYBy.rotateTo\n" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
86 | _transitionView.centerYBy(100.0).duration(1.0).rotateTo(M_PI*4).duration(1.0).animate();
87 | }]];
88 | [alert addAction:[UIAlertAction actionWithTitle:@"opacityTo.after.opacityTo" style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
89 | _transitionView.opacityTo(.0).after(0.1).opacityTo(1.0).duration(1.0).animate();
90 | _transitionView.chainAnimator.basic.property(@"opacity").fromValue(@0).toValue(@1).duration(1.0).animate();
91 | }]];
92 | [alert addAction:[UIAlertAction actionWithTitle:@"Cancel" style:UIAlertActionStyleCancel handler:^(UIAlertAction * _Nonnull action) {
93 | [CATransaction begin];
94 | [_transitionView.layer removeAllAnimations];
95 | [CATransaction setAnimationDuration:0.4];
96 | [CATransaction commit];
97 | }]];
98 | [self presentViewController:alert animated:YES completion:NULL];
99 | }
100 | @end
101 |
--------------------------------------------------------------------------------
/AXAnimationChain/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 | #import "AppDelegate.h"
11 |
12 | int main(int argc, char * argv[]) {
13 | @autoreleasepool {
14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class]));
15 | }
16 | }
17 |
--------------------------------------------------------------------------------
/AXAnimationChainSwift.podspec:
--------------------------------------------------------------------------------
1 |
2 | Pod::Spec.new do |s|
3 |
4 | s.name = "AXAnimationChainSwift"
5 | s.version = "0.4.1"
6 | s.summary = "`AXAnimationChainSwift` is an iOS chain animation hooker for `AXAnimationChain-Swift` using objc."
7 |
8 | s.description = <<-DESC
9 | `AXAnimationChain-Swift` is an iOS chain animation hooker for `AXAnimationChain-Swift` using objc which is easy to use.
10 | DESC
11 | s.homepage = "https://github.com/devedbox/AXAnimationChain"
12 | s.license = { :type => "MIT", :file => "LICENSE" }
13 | s.author = { "devedbox" => "devedbox@qq.com" }
14 | s.platform = :ios, "8.0"
15 | s.source = { :git => "https://github.com/devedbox/AXAnimationChain.git", :tag => s.version }
16 | s.source_files = 'AXAnimationChain/Classes/UIView+ChainAnimator.{h,m}', 'AXAnimationChain/Classes/AXChainAnimator.{h,m}', 'AXAnimationChain/Classes/CALayer+AnchorPoint.{h,m}', 'AXAnimationChain/Classes/CoreAnimation/*.{h,m}'
17 |
18 | s.frameworks = "UIKit", "Foundation", "QuartzCore"
19 | s.requires_arc = true
20 |
21 | end
22 |
--------------------------------------------------------------------------------
/AXAnimationChainTests/AXAnimationChainTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // AXAnimationChainTests.m
3 | // AXAnimationChainTests
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AXAnimationChainTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation AXAnimationChainTests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 | // Put setup code here. This method is called before the invocation of each test method in the class.
20 | }
21 |
22 | - (void)tearDown {
23 | // Put teardown code here. This method is called after the invocation of each test method in the class.
24 | [super tearDown];
25 | }
26 |
27 | - (void)testExample {
28 | // This is an example of a functional test case.
29 | // Use XCTAssert and related functions to verify your tests produce the correct results.
30 | }
31 |
32 | - (void)testPerformanceExample {
33 | // This is an example of a performance test case.
34 | [self measureBlock:^{
35 | // Put the code you want to measure the time of here.
36 | }];
37 | }
38 |
39 | @end
40 |
--------------------------------------------------------------------------------
/AXAnimationChainTests/ImmediateValueTests.swift:
--------------------------------------------------------------------------------
1 | //
2 | // ImmediateValueTests.swift
3 | // AXAnimationChain
4 | //
5 | // Created by devedbox on 2017/5/23.
6 | // Copyright © 2017年 devedbox. All rights reserved.
7 | //
8 |
9 | import XCTest
10 | import AXAnimationChain_App
11 |
12 | class ImmediateValueTests: XCTestCase {
13 |
14 | override func setUp() {
15 | super.setUp()
16 | // Put setup code here. This method is called before the invocation of each test method in the class.
17 | }
18 |
19 | override func tearDown() {
20 | // Put teardown code here. This method is called after the invocation of each test method in the class.
21 | super.tearDown()
22 | }
23 | /*
24 | func testExample() {
25 | // This is an example of a functional test case.
26 | // Use XCTAssert and related functions to verify your tests produce the correct results.
27 | }
28 |
29 | func testPerformanceExample() {
30 | // This is an example of a performance test case.
31 | self.measure {
32 | // Put the code you want to measure the time of here.
33 | }
34 | } */
35 |
36 | func testGetImmediateValueOfCAAnimation() {
37 | let anim = CAAnimation()
38 | // let value = anim.immediateValue(atTime: 0.5)
39 | do {
40 | let _ = try anim.immediateValue(atTime: 0.5)
41 | } catch let exp {
42 | XCTAssertNotNil(exp, "Test passed.")
43 | }
44 | }
45 | }
46 |
--------------------------------------------------------------------------------
/AXAnimationChainTests/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 |
--------------------------------------------------------------------------------
/AXAnimationChainUITests/AXAnimationChainUITests.m:
--------------------------------------------------------------------------------
1 | //
2 | // AXAnimationChainUITests.m
3 | // AXAnimationChainUITests
4 | //
5 | // Created by devedbox on 2016/12/10.
6 | // Copyright © 2016年 devedbox. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface AXAnimationChainUITests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation AXAnimationChainUITests
16 |
17 | - (void)setUp {
18 | [super setUp];
19 |
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 |
22 | // In UI tests it is usually best to stop immediately when a failure occurs.
23 | self.continueAfterFailure = NO;
24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method.
25 | [[[XCUIApplication alloc] init] launch];
26 |
27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this.
28 | }
29 |
30 | - (void)tearDown {
31 | // Put teardown code here. This method is called after the invocation of each test method in the class.
32 | [super tearDown];
33 | }
34 |
35 | - (void)testExample {
36 | // Use recording to get started writing UI tests.
37 | // Use XCTAssert and related functions to verify your tests produce the correct results.
38 | }
39 |
40 | @end
41 |
--------------------------------------------------------------------------------
/AXAnimationChainUITests/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 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2016 aixing
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 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | 
2 |
3 | 
4 |
5 | ## Summary
6 |
7 | [AXAnimationChain](https://github.com/devedbox/AXAnimationChain)是一个**`链式动画库`**,可以用来轻松的创建基于`CAAnimation`的链式动画。**链**的组合方式有两种,一种是**组合**,另一种则是**链接**,通过以上两种方式创建的动画,既可以同时进行,也可以按时间先后进行,可以使用较少的代码创建出丰富复杂的动画效果:
8 |
9 | **简单使用**:
10 |
11 | ```objective-c
12 | _transitionView.spring.centerBy(CGPointMake(0, 100)).easeOut.spring.sizeBy(CGSizeMake(100, 100)).spring.cornerRadiusBy(4).animate();
13 | ```
14 |
15 | 
16 |
17 | **高级使用**:
18 |
19 | ```objective-c
20 | _transitionView.chainAnimator.basic.target(self).complete(@selector(complete:)).property(@"position").toValue([NSValue valueWithCGPoint:CGPointMake(100, self.view.center.y)]).easeInBack.duration(0.5).combineSpring.target(self).complete(@selector(complete:)).property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(0.5).repeatCount(5).autoreverses.combineSpring.target(self).complete(@selector(complete:)).property(@"transform.rotation").toValue(@(M_PI_4)).duration(0.5).repeatCount(3).beginTime(1.0).autoreverses.nextToBasic.property(@"position").toValue([NSValue valueWithCGPoint:self.view.center]).duration(0.5).combineSpring.property(@"bounds").toValue([NSValue valueWithCGRect:CGRectMake(0, 0, 100, 100)]).duration(0.8).nextToBasic.property(@"transform.rotation").toValue(@(M_PI_4)).duration(1.0).completeWithBlock(nil).animate();
21 | ```
22 |
23 | 看起来比较冗余,但是细读会发现,其实就只有**一行代码**.
24 |
25 | 
26 |
27 | **链接**和**组合**在协议`AXAnimatorChainDelegate`中进行定义,分别是:`nextTo:`和`combineWith:`,在使用的过程中应当予以区分.
28 |
29 | `AXAnimationChain`基于`CoreAnimation`定义了几种`Animator`,`AXChainAnimator`是基类,预定义了一系列`Animate`操作,可以**链接**、**组合**并且控制动画完成的**回调**:
30 |
31 | ```objective-c
32 | AXChainAnimator
33 | --AXBasicChainAnimator ==CABasicAnimation
34 | --AXSpringChainAnimator ==CASpringAnimation
35 | --AXKeyframeChainAnimator ==CAKeyframeAnimation
36 | --AXTransitionChainAnimator==CATransitionAnimation
37 | ```
38 |
39 |
40 |
41 | ### Next-To
42 |
43 | 通过链接的方式处理两个`animator`,**被链接**的`animator`将会在前者动画(包含*`组合`*的动画)完成之后进行动画, 大概的示例如下:
44 |
45 | ```objective-c
46 | [former nextTo:nexter];
47 | ```
48 |
49 | `Next-To`方法的原型如下:
50 |
51 | ```objective-c
52 | - (instancetype)nextTo:(id)animator;
53 | ```
54 |
55 | 当向`former aniamtor`发送`nextTo:`消息之后,返回的是`nexter animator`作为下次**链接**或者**组合**操作的对象,因此`AXAnimationChain`定义了几种常用的操作:
56 |
57 | ```objective-c
58 | /// 链接到Basic动画并且返回链接的Basic动画.
59 | - (AXBasicChainAnimator *)nextToBasic;
60 | /// 链接到Spring动画并且放回链接的Spring动画.
61 | - (AXSpringChainAnimator *)nextToSpring;
62 | /// 链接到Keyframe动画并且放回链接的Keyframe动画.
63 | - (AXKeyframeChainAnimator *)nextToKeyframe;
64 | /// 链接到Transition动画并且返回链接的Transition动画.
65 | - (AXTransitionChainAnimator *)nextToTransition;
66 | ```
67 |
68 | 在发送消息之后分别返回对应类型的**可操作对象**.
69 |
70 | ### Combine-With
71 |
72 | 通过组合的方式处理两个`animator`,被组合的`animator`将会与前者动画同时进行,完成的时间以时间最长的为准, 示例如下:
73 |
74 | ```objective-c
75 | [former combineWith:combiner];
76 | ```
77 |
78 | `Combine-With`方法原型如下:
79 |
80 | ```objective-c
81 | - (instancetype)combineWith:(nonnull AXChainAnimator *)animator;
82 | ```
83 |
84 | 当向`former animator`发送`combineWith:`消息之后,返回的是`combiner animator`作为下次**链接**或者**组合**操作的对象,在`AXAnimationChain`中,默认一下几种组合方式:
85 |
86 | ```objective-c
87 | /// 组合到Basic动画并且返回组合的Basic动画.
88 | - (AXBasicChainAnimator *)combineBasic;
89 | /// 组合到Spring动画并且放回组合的Spring动画.
90 | - (AXSpringChainAnimator *)combineSpring;
91 | /// 组合到Keyframe动画并且放回组合的Keyframe动画.
92 | - (AXKeyframeChainAnimator *)combineKeyframe;
93 | /// 组合到Transition动画并且返回组合的Transition动画.
94 | - (AXTransitionChainAnimator *)combineTransition;
95 | ```
96 |
97 | 同样的,在向某一操作对象`animator`发送以上消息之后,将会分别返回对应类型的**可操作对象**.
98 |
99 | ### Relationship
100 |
101 | 在`AXAnimationChain`中,关系的管理采用的是二叉树的理论. 某一个`animator`对应的类结构中,包含了指向**父节点**的`superAnimator`用于表示`父animator`, 表示此`animator`为`superAnimator`所链接的`animator`, 此时,`superAnimator`的`childAnimator`即指向此`animator`作为一个**闭环链**将两者的关系锁定起来; 同样的,某一个`animator`还拥有一个指向**兄弟节点**的`NSArray`结构:`combinedAnimators`用于管理所组合的`animators`,并且,被组合的`animator`的父节点`superAnimator`则指向当前`animator`.
102 |
103 | ```objective-c
104 | - (void)start {
105 | NSAssert(_animatedView, @"Animation chain cannot be created because animated view is null.");
106 | AXChainAnimator *superAnimator = _superAnimator;
107 | AXChainAnimator *superSuperAnimator = _superAnimator;
108 | while (superAnimator) {
109 | superAnimator = superAnimator.superAnimator;
110 | if (superAnimator) {
111 | superSuperAnimator = superAnimator;
112 | }
113 | }
114 | if (superSuperAnimator) {
115 | [superSuperAnimator start];
116 | } else {
117 | [self _beginAnimating];
118 | if (!_childAnimator) [self _clear];
119 | }
120 | }
121 | ```
122 |
123 | `AXAnimatioChain`就是通过这样的关系把所有**链接**和**组合**的`animator`管理起来的,在完成关系的链接或组合之后,需要向最后一个`animator`发送`-start`消息动画才能正常进行. `animator`在接收到`-start`消息之后,会逐级遍历`superAnimator`直至`superAnimator.superAnimator==nil`, 此时获取到`superSuperAnimator`, 从`superSuperAnimator`自祖先往下逐级进行动画,**组合**的动画会**同时**进行,**链接**的动画则按**顺序**进行.
124 |
125 | ## Features
126 |
127 | * 轻量级解决方案
128 | * 基于CoreAnimation的封装,安全、高效!
129 | * 一行代码搞定复杂的动画管理,提高代码维护效
130 |
131 | #### TimingControl
132 |
133 | 时间曲线,时间曲线用于描述动画随时间进行的速度,`AXAnimationChain`除了包含系统默认的时间曲线之外,还提供了如下的曲线以呈现更漂亮的动画:
134 |
135 | 
136 |
137 | #### AXSpringAnimation
138 |
139 | `CoreAnimation`自`iOS2.0`就为iOS平台提供了核心动画的支持,但是在iOS9.0之前,一直没有`Spring`动画,要使用`Spring`动画要么使用第三方动画库,要么使用系统提供的方法:
140 |
141 | ```objective-c
142 | + (void)animateWithDuration:(NSTimeInterval)duration delay:(NSTimeInterval)delay usingSpringWithDamping:(CGFloat)dampingRatio initialSpringVelocity:(CGFloat)velocity options:(UIViewAnimationOptions)options animations:(void (^)(void))animations completion:(void (^ __nullable)(BOOL finished))completion NS_AVAILABLE_IOS(7_0);
143 | ```
144 |
145 | 但是系统提供的这个方法也是`iOS7.0`以后才能使用了,并且在控制上并非那么容易.
146 |
147 | `AXSpringAnimation`是基于**阻尼震动**运动模型的`Spring`动画类,能够完美与`CASpringAnimation`相通用:
148 |
149 | 
150 |
151 | 动画中,左边正方形使用的是`CASpringAnimation`类,右边的则使用的是`AXSpringAnimation`,两者的动画曲线是一致的.
152 |
153 | 同样地,`AXSpringAnimation`的API和`CASpringAnimation`也是一致的:
154 |
155 | ```objective-c
156 | @interface AXSpringAnimation : CAKeyframeAnimation
157 | /* The mass of the object attached to the end of the spring. Must be greater
158 | than 0. Defaults to one. */
159 |
160 | @property(assign, nonatomic) CGFloat mass;
161 |
162 | /* The spring stiffness coefficient. Must be greater than 0.
163 | * Defaults to 100. */
164 |
165 | @property(assign, nonatomic) CGFloat stiffness;
166 |
167 | /* The damping coefficient. Must be greater than or equal to 0.
168 | * Defaults to 10. */
169 |
170 | @property(assign, nonatomic) CGFloat damping;
171 |
172 | /* The initial velocity of the object attached to the spring. Defaults
173 | * to zero, which represents an unmoving object. Negative values
174 | * represent the object moving away from the spring attachment point,
175 | * positive values represent the object moving towards the spring
176 | * attachment point. */
177 |
178 | @property(assign, nonatomic) CGFloat initialVelocity;
179 |
180 | /* Returns the estimated duration required for the spring system to be
181 | * considered at rest. The duration is evaluated for the current animation
182 | * parameters. */
183 |
184 | @property(readonly, nonatomic) CFTimeInterval settlingDuration;
185 |
186 | /* The objects defining the property values being interpolated between.
187 | * All are optional, and no more than two should be non-nil. The object
188 | * type should match the type of the property being animated (using the
189 | * standard rules described in CALayer.h). The supported modes of
190 | * animation are:
191 | *
192 | * - both `fromValue' and `toValue' non-nil. Interpolates between
193 | * `fromValue' and `toValue'.
194 | *
195 | * - `fromValue' and `byValue' non-nil. Interpolates between
196 | * `fromValue' and `fromValue' plus `byValue'.
197 | *
198 | * - `byValue' and `toValue' non-nil. Interpolates between `toValue'
199 | * minus `byValue' and `toValue'. */
200 |
201 | @property(nullable, strong, nonatomic) id fromValue;
202 | @property(nullable, strong, nonatomic) id toValue;
203 | @property(nullable, strong, nonatomic) id byValue;
204 | @end
205 | ```
206 |
207 |
208 |
209 | #### Convertable
210 |
211 | `AXAnimationChain`框架还提供了将`CABasicAnimation`无缝转换为`CAKeyframeAnimation`的功能:
212 |
213 | 
214 |
215 | 动画中,左边是`CABasicAnimation`,右边是`CAKeyframeAnimation`,两者对应的动画曲线是一致的.
216 |
217 | 要使用动画转换,请参考:
218 |
219 | ```objective-c
220 | #import
221 | #import
222 | #import "CAMediaTimingFunction+Extends.h"
223 |
224 | @interface CAAnimation (Convertable)
225 | @end
226 |
227 | @interface CAKeyframeAnimation (Convertable)
228 | + (instancetype)animationWithBasic:(CABasicAnimation *)basicAnimation;
229 | + (instancetype)animationWithBasic:(CABasicAnimation *)basicAnimation usingValuesFunction:(double (^)(double t, double b, double c, double d))valuesFunction;
230 | @end
231 | ```
232 |
233 |
234 |
235 | ## Requirements
236 |
237 | `AXAnimationChain` 对系统版本支持到`iOS8.0`,需要使用到的框架:
238 |
239 | * Foundation.framework
240 |
241 | - UIKit.framework
242 | - QuartzCore.framework
243 |
244 | 使用的时候最好使用最新版Xcode.
245 |
246 | ## Adding `AXAimationChain` To Your Project
247 |
248 | ### CocoaPods
249 |
250 | [CocoaPods]([http://cocoapods.org](http://cocoapods.org)) is the recommended way to add AXAimationChain to your project.
251 |
252 | 1. Add a pod entry for AXAimationChain to your Podfile `pod 'AXAimationChain', '~> 0.2.3'`
253 | 2. Install the pod(s) by running `pod install`.
254 | 3. Include AXAimationChain wherever you need it with `#import "AXAimationChain.h"`.
255 | 4. 若需要单独使用`AXSpringAnimation`或者`Convertable`以及`TimingControl`等特性的话,只需要将podfile里边`AXAnimationChain`替换为`AXAnimationChain/CoreAnimation`即可,即:`pod 'AXAimationChain/CoreAnimation', '~> 0.2.3'`.
256 | 5. 若要使用`Swift`作为变成语言,请使用Swift版的依赖包:`pod 'AXAimationChain-Swift', '~> 0.2.3'`
257 |
258 | ### Source files
259 |
260 | Alternatively you can directly add all the source files to your project.
261 |
262 | 1. Download the [latest code version]([https://github.com/devedbox/AXAimationChain/archive/master.zip](https://github.com/devedbox/AXAimationChain/archive/master.zip)) or add the repository as a git submodule to your git-tracked project.
263 | 2. Open your project in Xcode, then drag and drop the source group onto your project (use the "Product Navigator view"). Make sure to select Copy items when asked if you extracted the code archive outside of your project.
264 | 3. Include AXAnimationChain wherever you need it with `#import "AXAimationChain.h"`.
265 | 4. 如单独使用`AXSpringAnimation`或者`Convertable`以及`TimingControl`等特性,只需要导入`#import "AXCoreAnimation.h"`即可.
266 |
267 | ## License
268 |
269 | This code is distributed under the terms and conditions of the [MIT license](LICENSE).
270 |
271 | ## 使用
272 |
273 | 请参考示例工程代码以及API.
274 |
275 | ## 不足
276 |
277 | 此项目在开展的时候比较庞大,基础的核心类已经构建好了,基本目标已经达成,但是还有很多需要完善的地方,后边会逐步完善并发布Release版本.
278 |
279 | ## 声明
280 |
281 | 转载需注明出处:`http://devedbox.com/AXAnimationChain/`
282 |
--------------------------------------------------------------------------------
/_config.yml:
--------------------------------------------------------------------------------
1 | theme: jekyll-theme-minimal
--------------------------------------------------------------------------------
/docs/.d:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devedbox/AXAnimationChain/222c7aef6e5d413a42a790b36c2ff9763884454e/docs/.d
--------------------------------------------------------------------------------
/docs/AXSpringAnimation.md:
--------------------------------------------------------------------------------
1 | # 动画曲线
2 |
3 | **动画曲线**用来描述动画随时间进行的速度的快慢,优雅的动画曲线描述的动画通常都比较优美而不会显得突兀(除非有意而为之),在iOS中,通常使用`CAMediaTimingFunction`**时间函数**来描述**动画曲线**,当然,`CoreAnimation`系统已经为我们提供了5个默认的**时间函数**,他们分别是:
4 |
5 | `Default`: 先缓慢加速,再缓慢减速
6 |
7 | 
8 |
9 | `EaseIn`: 开始时缓慢减速
10 |
11 | 
12 |
13 | `EaseOut`: 结束时缓慢减速
14 |
15 | 
16 |
17 | `EaseInOut`: 开始和结束都减速
18 |
19 | 
20 |
21 | `Linear`:
22 |
23 | 
24 |
25 | 当然,也可以通过方法:
26 |
27 | ```objective-c
28 | + (instancetype)functionWithControlPoints:(float)c1x :(float)c1y :(float)c2x :(float)c2y;
29 | ```
30 |
31 | 来创建自定义的**动画曲线**,通过传入两个控制点而得到一条**三次贝塞尔曲线**,即能满足自定义的需求. [编辑贝塞尔曲线](http://netcetera.org/camtf-playground.html).
32 |
33 | **动画曲线**在使用的时候将需要设置的**时间函数**设置给`CAAnimation`的`timingFunction`即可,但是**Spring**动画却不能使用`CAMediaTimingFunction`来描述,我们可以注意到,在以上**动画曲线**里,所描述的`速度`与`时间`的关系两者都区间都是`[0,1]`,意味着动画若需要在结束时减速,则开始时也不可能同时减速. 总而言之,三次贝塞尔无法描述**Spring**动画的曲线.
34 |
35 | # 什么是Spring动画
36 |
37 | Spring:弹性、弹簧. Spring动画指的就是弹性动画,在iOS2.0以来,`CoreAnimation`就为我们提供了丰富的动画库,可以使用`CABasicAnimation`来创建基础动画,初始化CABasicAnimation之后,设置动画时间(`CAMediaTiming`协议相关的一系列属性),并设置初始值、结束值之后添加到`CALayer`上即可开始动画,想要更复杂的动画,就可以使用帧动画`CAKeyframeAnimation`,更详细的使用教程参考:[iOS开发之让你的应用“动”起来](http://www.cocoachina.com/ios/20141022/10005.html). 那么说到底,什么是Spring动画呢?计算机图形发展到现在,不管绘图也好,动画也好,都有相应的**数学模型**可以追溯. 在iOS里边,`CAAnimation`类实现了`CAMediaTiming`协议以实现对动画的时间管理,在`CAMediaTiming`里边有个属性`timingFunction`,这个属性是用来控制**动画曲线**的,**动画曲线**是用来描述动画随时间进行的**速度**的模型,在数学里,就是**斜率**. 在`CoreAnimation`进行动画的时候,会根据**动画曲线**的描述来进行动画,所以我们可以实现很多很漂亮很流畅的动画. Spring动画对应的函数模型是[阻尼震动](https://zh.wikipedia.org/zh-cn/振动#.E9.98.BB.E5.B0.BC.E6.8C.AF.E5.8A.A8). 函数曲线如下:
38 |
39 | 
40 |
41 | # 阻尼震动
42 |
43 | **阻尼震动**的详细解释可以参考:[阻尼震动](https://zh.wikipedia.org/zh-cn/振动#.E9.98.BB.E5.B0.BC.E6.8C.AF.E5.8A.A8). 根据维基百科描述,我们可以得到以下运动方程:
44 |
45 |
46 |
47 |
--------------------------------------------------------------------------------
/src/img/logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/devedbox/AXAnimationChain/222c7aef6e5d413a42a790b36c2ff9763884454e/src/img/logo.png
--------------------------------------------------------------------------------