├── README.md
├── ZFChangeAnimation.gif
├── ZFChangeAnimation.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ ├── contents.xcworkspacedata
│ └── xcuserdata
│ │ └── macOne.xcuserdatad
│ │ └── UserInterfaceState.xcuserstate
└── xcuserdata
│ └── macOne.xcuserdatad
│ ├── xcdebugger
│ └── Breakpoints_v2.xcbkptlist
│ └── xcschemes
│ ├── ZFChangeAnimation.xcscheme
│ └── xcschememanagement.plist
├── ZFChangeAnimation
├── AppDelegate.h
├── AppDelegate.m
├── Assets.xcassets
│ └── AppIcon.appiconset
│ │ └── Contents.json
├── Base.lproj
│ ├── LaunchScreen.storyboard
│ └── Main.storyboard
├── ChangeAnimationView.h
├── ChangeAnimationView.m
├── Info.plist
├── ViewController.h
├── ViewController.m
└── main.m
└── origin animation.gif
/README.md:
--------------------------------------------------------------------------------
1 | # ZFChangeAnimation
2 |
3 |
4 |
5 | ## Example:
6 |
7 |
8 |
9 |
10 |
11 |
12 | 具体详细介绍见http://www.jianshu.com/p/1e2b8ff3519e
13 |
--------------------------------------------------------------------------------
/ZFChangeAnimation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WZF-Fei/ZFChangeAnimation/cd6788bf0d7abc7120f204b2369e8242c31615e9/ZFChangeAnimation.gif
--------------------------------------------------------------------------------
/ZFChangeAnimation.xcodeproj/project.pbxproj:
--------------------------------------------------------------------------------
1 | // !$*UTF8*$!
2 | {
3 | archiveVersion = 1;
4 | classes = {
5 | };
6 | objectVersion = 46;
7 | objects = {
8 |
9 | /* Begin PBXBuildFile section */
10 | DBB94A1B1C1A635A006BE60A /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = DBB94A1A1C1A635A006BE60A /* main.m */; };
11 | DBB94A1E1C1A635A006BE60A /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = DBB94A1D1C1A635A006BE60A /* AppDelegate.m */; };
12 | DBB94A211C1A635A006BE60A /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = DBB94A201C1A635A006BE60A /* ViewController.m */; };
13 | DBB94A241C1A635A006BE60A /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DBB94A221C1A635A006BE60A /* Main.storyboard */; };
14 | DBB94A261C1A635A006BE60A /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = DBB94A251C1A635A006BE60A /* Assets.xcassets */; };
15 | DBB94A291C1A635A006BE60A /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = DBB94A271C1A635A006BE60A /* LaunchScreen.storyboard */; };
16 | DBB94A321C1A6393006BE60A /* ChangeAnimationView.m in Sources */ = {isa = PBXBuildFile; fileRef = DBB94A311C1A6393006BE60A /* ChangeAnimationView.m */; settings = {ASSET_TAGS = (); }; };
17 | /* End PBXBuildFile section */
18 |
19 | /* Begin PBXFileReference section */
20 | DBB94A161C1A635A006BE60A /* ZFChangeAnimation.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = ZFChangeAnimation.app; sourceTree = BUILT_PRODUCTS_DIR; };
21 | DBB94A1A1C1A635A006BE60A /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; };
22 | DBB94A1C1C1A635A006BE60A /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; };
23 | DBB94A1D1C1A635A006BE60A /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; };
24 | DBB94A1F1C1A635A006BE60A /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; };
25 | DBB94A201C1A635A006BE60A /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; };
26 | DBB94A231C1A635A006BE60A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; };
27 | DBB94A251C1A635A006BE60A /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; };
28 | DBB94A281C1A635A006BE60A /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; };
29 | DBB94A2A1C1A635A006BE60A /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; };
30 | DBB94A301C1A6393006BE60A /* ChangeAnimationView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ChangeAnimationView.h; sourceTree = ""; };
31 | DBB94A311C1A6393006BE60A /* ChangeAnimationView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ChangeAnimationView.m; sourceTree = ""; };
32 | /* End PBXFileReference section */
33 |
34 | /* Begin PBXFrameworksBuildPhase section */
35 | DBB94A131C1A635A006BE60A /* Frameworks */ = {
36 | isa = PBXFrameworksBuildPhase;
37 | buildActionMask = 2147483647;
38 | files = (
39 | );
40 | runOnlyForDeploymentPostprocessing = 0;
41 | };
42 | /* End PBXFrameworksBuildPhase section */
43 |
44 | /* Begin PBXGroup section */
45 | DBB94A0D1C1A635A006BE60A = {
46 | isa = PBXGroup;
47 | children = (
48 | DBB94A181C1A635A006BE60A /* ZFChangeAnimation */,
49 | DBB94A171C1A635A006BE60A /* Products */,
50 | );
51 | sourceTree = "";
52 | };
53 | DBB94A171C1A635A006BE60A /* Products */ = {
54 | isa = PBXGroup;
55 | children = (
56 | DBB94A161C1A635A006BE60A /* ZFChangeAnimation.app */,
57 | );
58 | name = Products;
59 | sourceTree = "";
60 | };
61 | DBB94A181C1A635A006BE60A /* ZFChangeAnimation */ = {
62 | isa = PBXGroup;
63 | children = (
64 | DBB94A1C1C1A635A006BE60A /* AppDelegate.h */,
65 | DBB94A1D1C1A635A006BE60A /* AppDelegate.m */,
66 | DBB94A1F1C1A635A006BE60A /* ViewController.h */,
67 | DBB94A201C1A635A006BE60A /* ViewController.m */,
68 | DBB94A221C1A635A006BE60A /* Main.storyboard */,
69 | DBB94A251C1A635A006BE60A /* Assets.xcassets */,
70 | DBB94A271C1A635A006BE60A /* LaunchScreen.storyboard */,
71 | DBB94A2A1C1A635A006BE60A /* Info.plist */,
72 | DBB94A191C1A635A006BE60A /* Supporting Files */,
73 | DBB94A301C1A6393006BE60A /* ChangeAnimationView.h */,
74 | DBB94A311C1A6393006BE60A /* ChangeAnimationView.m */,
75 | );
76 | path = ZFChangeAnimation;
77 | sourceTree = "";
78 | };
79 | DBB94A191C1A635A006BE60A /* Supporting Files */ = {
80 | isa = PBXGroup;
81 | children = (
82 | DBB94A1A1C1A635A006BE60A /* main.m */,
83 | );
84 | name = "Supporting Files";
85 | sourceTree = "";
86 | };
87 | /* End PBXGroup section */
88 |
89 | /* Begin PBXNativeTarget section */
90 | DBB94A151C1A635A006BE60A /* ZFChangeAnimation */ = {
91 | isa = PBXNativeTarget;
92 | buildConfigurationList = DBB94A2D1C1A635A006BE60A /* Build configuration list for PBXNativeTarget "ZFChangeAnimation" */;
93 | buildPhases = (
94 | DBB94A121C1A635A006BE60A /* Sources */,
95 | DBB94A131C1A635A006BE60A /* Frameworks */,
96 | DBB94A141C1A635A006BE60A /* Resources */,
97 | );
98 | buildRules = (
99 | );
100 | dependencies = (
101 | );
102 | name = ZFChangeAnimation;
103 | productName = ZFChangeAnimation;
104 | productReference = DBB94A161C1A635A006BE60A /* ZFChangeAnimation.app */;
105 | productType = "com.apple.product-type.application";
106 | };
107 | /* End PBXNativeTarget section */
108 |
109 | /* Begin PBXProject section */
110 | DBB94A0E1C1A635A006BE60A /* Project object */ = {
111 | isa = PBXProject;
112 | attributes = {
113 | LastUpgradeCheck = 0700;
114 | ORGANIZATIONNAME = WZF;
115 | TargetAttributes = {
116 | DBB94A151C1A635A006BE60A = {
117 | CreatedOnToolsVersion = 7.0;
118 | };
119 | };
120 | };
121 | buildConfigurationList = DBB94A111C1A635A006BE60A /* Build configuration list for PBXProject "ZFChangeAnimation" */;
122 | compatibilityVersion = "Xcode 3.2";
123 | developmentRegion = English;
124 | hasScannedForEncodings = 0;
125 | knownRegions = (
126 | en,
127 | Base,
128 | );
129 | mainGroup = DBB94A0D1C1A635A006BE60A;
130 | productRefGroup = DBB94A171C1A635A006BE60A /* Products */;
131 | projectDirPath = "";
132 | projectRoot = "";
133 | targets = (
134 | DBB94A151C1A635A006BE60A /* ZFChangeAnimation */,
135 | );
136 | };
137 | /* End PBXProject section */
138 |
139 | /* Begin PBXResourcesBuildPhase section */
140 | DBB94A141C1A635A006BE60A /* Resources */ = {
141 | isa = PBXResourcesBuildPhase;
142 | buildActionMask = 2147483647;
143 | files = (
144 | DBB94A291C1A635A006BE60A /* LaunchScreen.storyboard in Resources */,
145 | DBB94A261C1A635A006BE60A /* Assets.xcassets in Resources */,
146 | DBB94A241C1A635A006BE60A /* Main.storyboard in Resources */,
147 | );
148 | runOnlyForDeploymentPostprocessing = 0;
149 | };
150 | /* End PBXResourcesBuildPhase section */
151 |
152 | /* Begin PBXSourcesBuildPhase section */
153 | DBB94A121C1A635A006BE60A /* Sources */ = {
154 | isa = PBXSourcesBuildPhase;
155 | buildActionMask = 2147483647;
156 | files = (
157 | DBB94A211C1A635A006BE60A /* ViewController.m in Sources */,
158 | DBB94A1E1C1A635A006BE60A /* AppDelegate.m in Sources */,
159 | DBB94A321C1A6393006BE60A /* ChangeAnimationView.m in Sources */,
160 | DBB94A1B1C1A635A006BE60A /* main.m in Sources */,
161 | );
162 | runOnlyForDeploymentPostprocessing = 0;
163 | };
164 | /* End PBXSourcesBuildPhase section */
165 |
166 | /* Begin PBXVariantGroup section */
167 | DBB94A221C1A635A006BE60A /* Main.storyboard */ = {
168 | isa = PBXVariantGroup;
169 | children = (
170 | DBB94A231C1A635A006BE60A /* Base */,
171 | );
172 | name = Main.storyboard;
173 | sourceTree = "";
174 | };
175 | DBB94A271C1A635A006BE60A /* LaunchScreen.storyboard */ = {
176 | isa = PBXVariantGroup;
177 | children = (
178 | DBB94A281C1A635A006BE60A /* Base */,
179 | );
180 | name = LaunchScreen.storyboard;
181 | sourceTree = "";
182 | };
183 | /* End PBXVariantGroup section */
184 |
185 | /* Begin XCBuildConfiguration section */
186 | DBB94A2B1C1A635A006BE60A /* Debug */ = {
187 | isa = XCBuildConfiguration;
188 | buildSettings = {
189 | ALWAYS_SEARCH_USER_PATHS = NO;
190 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
191 | CLANG_CXX_LIBRARY = "libc++";
192 | CLANG_ENABLE_MODULES = YES;
193 | CLANG_ENABLE_OBJC_ARC = YES;
194 | CLANG_WARN_BOOL_CONVERSION = YES;
195 | CLANG_WARN_CONSTANT_CONVERSION = YES;
196 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
197 | CLANG_WARN_EMPTY_BODY = YES;
198 | CLANG_WARN_ENUM_CONVERSION = YES;
199 | CLANG_WARN_INT_CONVERSION = YES;
200 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
201 | CLANG_WARN_UNREACHABLE_CODE = YES;
202 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
203 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
204 | COPY_PHASE_STRIP = NO;
205 | DEBUG_INFORMATION_FORMAT = dwarf;
206 | ENABLE_STRICT_OBJC_MSGSEND = YES;
207 | ENABLE_TESTABILITY = YES;
208 | GCC_C_LANGUAGE_STANDARD = gnu99;
209 | GCC_DYNAMIC_NO_PIC = NO;
210 | GCC_NO_COMMON_BLOCKS = YES;
211 | GCC_OPTIMIZATION_LEVEL = 0;
212 | GCC_PREPROCESSOR_DEFINITIONS = (
213 | "DEBUG=1",
214 | "$(inherited)",
215 | );
216 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
217 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
218 | GCC_WARN_UNDECLARED_SELECTOR = YES;
219 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
220 | GCC_WARN_UNUSED_FUNCTION = YES;
221 | GCC_WARN_UNUSED_VARIABLE = YES;
222 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
223 | MTL_ENABLE_DEBUG_INFO = YES;
224 | ONLY_ACTIVE_ARCH = YES;
225 | SDKROOT = iphoneos;
226 | TARGETED_DEVICE_FAMILY = "1,2";
227 | };
228 | name = Debug;
229 | };
230 | DBB94A2C1C1A635A006BE60A /* Release */ = {
231 | isa = XCBuildConfiguration;
232 | buildSettings = {
233 | ALWAYS_SEARCH_USER_PATHS = NO;
234 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x";
235 | CLANG_CXX_LIBRARY = "libc++";
236 | CLANG_ENABLE_MODULES = YES;
237 | CLANG_ENABLE_OBJC_ARC = YES;
238 | CLANG_WARN_BOOL_CONVERSION = YES;
239 | CLANG_WARN_CONSTANT_CONVERSION = YES;
240 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR;
241 | CLANG_WARN_EMPTY_BODY = YES;
242 | CLANG_WARN_ENUM_CONVERSION = YES;
243 | CLANG_WARN_INT_CONVERSION = YES;
244 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR;
245 | CLANG_WARN_UNREACHABLE_CODE = YES;
246 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES;
247 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer";
248 | COPY_PHASE_STRIP = NO;
249 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym";
250 | ENABLE_NS_ASSERTIONS = NO;
251 | ENABLE_STRICT_OBJC_MSGSEND = YES;
252 | GCC_C_LANGUAGE_STANDARD = gnu99;
253 | GCC_NO_COMMON_BLOCKS = YES;
254 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES;
255 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR;
256 | GCC_WARN_UNDECLARED_SELECTOR = YES;
257 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE;
258 | GCC_WARN_UNUSED_FUNCTION = YES;
259 | GCC_WARN_UNUSED_VARIABLE = YES;
260 | IPHONEOS_DEPLOYMENT_TARGET = 9.0;
261 | MTL_ENABLE_DEBUG_INFO = NO;
262 | SDKROOT = iphoneos;
263 | TARGETED_DEVICE_FAMILY = "1,2";
264 | VALIDATE_PRODUCT = YES;
265 | };
266 | name = Release;
267 | };
268 | DBB94A2E1C1A635A006BE60A /* Debug */ = {
269 | isa = XCBuildConfiguration;
270 | buildSettings = {
271 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
272 | INFOPLIST_FILE = ZFChangeAnimation/Info.plist;
273 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
274 | PRODUCT_BUNDLE_IDENTIFIER = WZF.ZFChangeAnimation;
275 | PRODUCT_NAME = "$(TARGET_NAME)";
276 | };
277 | name = Debug;
278 | };
279 | DBB94A2F1C1A635A006BE60A /* Release */ = {
280 | isa = XCBuildConfiguration;
281 | buildSettings = {
282 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon;
283 | INFOPLIST_FILE = ZFChangeAnimation/Info.plist;
284 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks";
285 | PRODUCT_BUNDLE_IDENTIFIER = WZF.ZFChangeAnimation;
286 | PRODUCT_NAME = "$(TARGET_NAME)";
287 | };
288 | name = Release;
289 | };
290 | /* End XCBuildConfiguration section */
291 |
292 | /* Begin XCConfigurationList section */
293 | DBB94A111C1A635A006BE60A /* Build configuration list for PBXProject "ZFChangeAnimation" */ = {
294 | isa = XCConfigurationList;
295 | buildConfigurations = (
296 | DBB94A2B1C1A635A006BE60A /* Debug */,
297 | DBB94A2C1C1A635A006BE60A /* Release */,
298 | );
299 | defaultConfigurationIsVisible = 0;
300 | defaultConfigurationName = Release;
301 | };
302 | DBB94A2D1C1A635A006BE60A /* Build configuration list for PBXNativeTarget "ZFChangeAnimation" */ = {
303 | isa = XCConfigurationList;
304 | buildConfigurations = (
305 | DBB94A2E1C1A635A006BE60A /* Debug */,
306 | DBB94A2F1C1A635A006BE60A /* Release */,
307 | );
308 | defaultConfigurationIsVisible = 0;
309 | };
310 | /* End XCConfigurationList section */
311 | };
312 | rootObject = DBB94A0E1C1A635A006BE60A /* Project object */;
313 | }
314 |
--------------------------------------------------------------------------------
/ZFChangeAnimation.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/ZFChangeAnimation.xcodeproj/project.xcworkspace/xcuserdata/macOne.xcuserdatad/UserInterfaceState.xcuserstate:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WZF-Fei/ZFChangeAnimation/cd6788bf0d7abc7120f204b2369e8242c31615e9/ZFChangeAnimation.xcodeproj/project.xcworkspace/xcuserdata/macOne.xcuserdatad/UserInterfaceState.xcuserstate
--------------------------------------------------------------------------------
/ZFChangeAnimation.xcodeproj/xcuserdata/macOne.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
8 |
14 |
15 |
16 |
18 |
30 |
31 |
32 |
33 |
34 |
--------------------------------------------------------------------------------
/ZFChangeAnimation.xcodeproj/xcuserdata/macOne.xcuserdatad/xcschemes/ZFChangeAnimation.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
32 |
33 |
39 |
40 |
41 |
42 |
43 |
44 |
54 |
56 |
62 |
63 |
64 |
65 |
66 |
67 |
73 |
75 |
81 |
82 |
83 |
84 |
86 |
87 |
90 |
91 |
92 |
--------------------------------------------------------------------------------
/ZFChangeAnimation.xcodeproj/xcuserdata/macOne.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | ZFChangeAnimation.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | DBB94A151C1A635A006BE60A
16 |
17 | primary
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/AppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.h
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. 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 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/AppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // AppDelegate.m
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. 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 | - (void)applicationWillResignActive:(UIApplication *)application {
24 | // 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.
25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
26 | }
27 |
28 | - (void)applicationDidEnterBackground:(UIApplication *)application {
29 | // 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.
30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
31 | }
32 |
33 | - (void)applicationWillEnterForeground:(UIApplication *)application {
34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background.
35 | }
36 |
37 | - (void)applicationDidBecomeActive:(UIApplication *)application {
38 | // 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.
39 | }
40 |
41 | - (void)applicationWillTerminate:(UIApplication *)application {
42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
43 | }
44 |
45 | @end
46 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/Assets.xcassets/AppIcon.appiconset/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "idiom" : "iphone",
5 | "size" : "29x29",
6 | "scale" : "2x"
7 | },
8 | {
9 | "idiom" : "iphone",
10 | "size" : "29x29",
11 | "scale" : "3x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "40x40",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "iphone",
20 | "size" : "40x40",
21 | "scale" : "3x"
22 | },
23 | {
24 | "idiom" : "iphone",
25 | "size" : "60x60",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "iphone",
30 | "size" : "60x60",
31 | "scale" : "3x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "29x29",
36 | "scale" : "1x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "29x29",
41 | "scale" : "2x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "40x40",
46 | "scale" : "1x"
47 | },
48 | {
49 | "idiom" : "ipad",
50 | "size" : "40x40",
51 | "scale" : "2x"
52 | },
53 | {
54 | "idiom" : "ipad",
55 | "size" : "76x76",
56 | "scale" : "1x"
57 | },
58 | {
59 | "idiom" : "ipad",
60 | "size" : "76x76",
61 | "scale" : "2x"
62 | }
63 | ],
64 | "info" : {
65 | "version" : 1,
66 | "author" : "xcode"
67 | }
68 | }
--------------------------------------------------------------------------------
/ZFChangeAnimation/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 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/Base.lproj/Main.storyboard:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/ChangeAnimationView.h:
--------------------------------------------------------------------------------
1 | //
2 | // ChangeAnimationView.h
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ChangeAnimationView : UIView
12 |
13 |
14 | -(void)startAnimation;
15 |
16 | -(void)stopAnimation;
17 |
18 | -(void)resumeAnimation;
19 |
20 |
21 | @end
22 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/ChangeAnimationView.m:
--------------------------------------------------------------------------------
1 | //
2 | // ChangeAnimationView.m
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. All rights reserved.
7 | //
8 |
9 | #import "ChangeAnimationView.h"
10 |
11 | @interface ChangeAnimationView ()
12 |
13 | @property (strong,nonatomic) CAShapeLayer *topLineLayer;
14 |
15 | @property (strong,nonatomic) CAShapeLayer *bottomLineLayer;
16 |
17 | @property (strong,nonatomic) CAShapeLayer *changedLayer;
18 |
19 | @end
20 |
21 | //small
22 | //static const CGFloat Raduis = 20;
23 | //static const CGFloat lineWidth = 20.0f;
24 | //static const CGFloat lineGapHeight = 5.0f;
25 | //static const CGFloat lineHeight = 2.0f;
26 |
27 | //big
28 | static const CGFloat Raduis = 50.0f;
29 | static const CGFloat lineWidth = 50.0f;
30 | static const CGFloat lineGapHeight = 10.0f;
31 | static const CGFloat lineHeight = 8.0f;
32 |
33 | static const CGFloat kStep1Duration = 0.5;
34 | static const CGFloat kStep2Duration = 0.5;
35 | static const CGFloat kStep3Duration = 5.0;
36 | static const CGFloat kStep4Duration = 5.0;
37 |
38 | #define kTopY Raduis - lineGapHeight
39 | #define kCenterY kTopY + lineGapHeight + lineHeight
40 | #define kBottomY kCenterY + lineGapHeight + lineHeight
41 | #define Radians(x) (M_PI * (x) / 180.0)
42 |
43 |
44 | @implementation ChangeAnimationView
45 |
46 | -(instancetype)initWithFrame:(CGRect)frame{
47 |
48 | self = [super initWithFrame:frame];
49 | if (self) {
50 |
51 | self.frame = frame;
52 | self.backgroundColor = [UIColor orangeColor];
53 |
54 | }
55 | return self;
56 | }
57 |
58 | -(void)startAnimation{
59 |
60 | [_changedLayer removeAllAnimations];
61 | [_changedLayer removeFromSuperlayer];
62 | [_topLineLayer removeFromSuperlayer];
63 | [_bottomLineLayer removeFromSuperlayer];
64 |
65 | [self initLayers];
66 |
67 | [self animationStep1];
68 |
69 | }
70 |
71 | -(void)resumeAnimation{
72 |
73 | [self resumeLayer:_topLineLayer];
74 | [self resumeLayer:_bottomLineLayer];
75 | [self resumeLayer:_changedLayer];
76 | }
77 |
78 | -(void)stopAnimation{
79 |
80 |
81 | [self pauseLayer:_topLineLayer];
82 | [self pauseLayer:_bottomLineLayer];
83 | [self pauseLayer:_changedLayer];
84 | }
85 |
86 | -(void)pauseLayer:(CALayer*)layer
87 | {
88 | CFTimeInterval pausedTime = [layer convertTime:CACurrentMediaTime() fromLayer:nil];
89 | layer.speed = 0.0;
90 | layer.timeOffset = pausedTime;
91 | }
92 |
93 | -(void)resumeLayer:(CALayer*)layer
94 | {
95 | CFTimeInterval pausedTime = [layer timeOffset];
96 | layer.speed = 1.0;
97 | layer.timeOffset = 0.0;
98 | layer.beginTime = 0.0;
99 | CFTimeInterval timeSincePause = [layer convertTime:CACurrentMediaTime() fromLayer:nil] - pausedTime;
100 | layer.beginTime = timeSincePause;
101 | }
102 |
103 | -(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag
104 | {
105 |
106 | if ([[anim valueForKey:@"animationName"] isEqualToString:@"animationStep1"]) {
107 |
108 | [self animationStep2];
109 |
110 | }
111 | else if([[anim valueForKey:@"animationName"] isEqualToString:@"animationStep2"]){
112 | [_changedLayer removeFromSuperlayer];
113 | [self animationStep3];
114 | }
115 | else if ([[anim valueForKey:@"animationName"] isEqualToString:@"animationStep3"]){
116 | [self cancelAnimation];
117 | }
118 | else if ([[anim valueForKey:@"animationName"] isEqualToString:@"animationStep4"]){
119 |
120 | _changedLayer.affineTransform = CGAffineTransformMakeTranslation(5, 0);
121 | //平移x
122 | CABasicAnimation *translationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
123 | translationAnimation.fromValue = [NSNumber numberWithFloat:0];
124 | translationAnimation.toValue = [NSNumber numberWithFloat:5];
125 |
126 | translationAnimation.duration = 0.5;
127 | translationAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
128 | [_changedLayer addAnimation:translationAnimation forKey:nil];
129 | }
130 | }
131 |
132 | - (void) animationStep1{
133 |
134 | _changedLayer.strokeEnd = 0.4;
135 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
136 | strokeAnimation.fromValue = [NSNumber numberWithFloat:1.0f];
137 | strokeAnimation.toValue = [NSNumber numberWithFloat:0.4f];
138 |
139 | CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"position.x"];
140 | pathAnimation.fromValue = [NSNumber numberWithFloat:0.0];
141 | pathAnimation.toValue = [NSNumber numberWithFloat:-10];
142 |
143 | CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
144 | animationGroup.animations = [NSArray arrayWithObjects:strokeAnimation,pathAnimation, nil];
145 | animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
146 | animationGroup.duration = kStep1Duration;
147 | animationGroup.delegate = self;
148 | animationGroup.removedOnCompletion = YES;
149 | [animationGroup setValue:@"animationStep1" forKey:@"animationName"];
150 | [_changedLayer addAnimation:animationGroup forKey:nil];
151 | }
152 |
153 | -(void)animationStep2
154 | {
155 | CABasicAnimation *translationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
156 | translationAnimation.fromValue = [NSNumber numberWithFloat:-10];
157 | //strokeEnd:0.8 剩余的距离toValue = lineWidth * (1 - 0.8);
158 | translationAnimation.toValue = [NSNumber numberWithFloat:0.2 * lineWidth];
159 |
160 | _changedLayer.strokeEnd = 0.8;
161 | CABasicAnimation *strokeAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
162 | strokeAnimation.fromValue = [NSNumber numberWithFloat:0.4f];
163 | strokeAnimation.toValue = [NSNumber numberWithFloat:0.8f];
164 |
165 | CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
166 | animationGroup.animations = [NSArray arrayWithObjects:strokeAnimation,translationAnimation, nil];
167 | animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
168 | animationGroup.duration = kStep2Duration;
169 | animationGroup.delegate = self;
170 | animationGroup.removedOnCompletion = YES;
171 | [animationGroup setValue:@"animationStep2" forKey:@"animationName"];
172 | [_changedLayer addAnimation:animationGroup forKey:nil];
173 | }
174 |
175 | -(void)animationStep3{
176 |
177 | _changedLayer = [CAShapeLayer layer];
178 | _changedLayer.fillColor = [UIColor clearColor].CGColor;
179 | _changedLayer.strokeColor = [UIColor whiteColor].CGColor;
180 | _changedLayer.contentsScale = [UIScreen mainScreen].scale;
181 | _changedLayer.lineWidth = lineHeight ;
182 | _changedLayer.lineCap = kCALineCapRound;
183 | [self.layer addSublayer:_changedLayer];
184 |
185 |
186 | UIBezierPath *path = [UIBezierPath bezierPath];
187 |
188 | // 画贝塞尔曲线 圆弧
189 | [path moveToPoint:CGPointMake(self.center.x + lineWidth/2.0 , kCenterY)];
190 |
191 | //30度,经过反复测试,效果最好
192 | CGFloat angle = Radians(30);
193 |
194 | CGFloat endPointX = self.center.x + Raduis * cos(angle);
195 | CGFloat endPointY = kCenterY - Raduis * sin(angle);
196 |
197 | CGFloat startPointX = self.center.x + lineWidth/2.0;
198 | CGFloat startPointY = kCenterY;
199 |
200 | CGFloat controlPointX = self.center.x + Raduis *acos(angle);
201 | CGFloat controlPointY = kCenterY;
202 |
203 | //三点曲线
204 | [path addCurveToPoint:CGPointMake(endPointX, endPointY)
205 | controlPoint1:CGPointMake(startPointX , startPointY)
206 | controlPoint2:CGPointMake(controlPointX , controlPointY)];
207 |
208 | //组合path 路径
209 | UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.center.x,kCenterY)
210 | radius:Raduis
211 | startAngle:2 * M_PI - angle
212 | endAngle:M_PI + angle
213 | clockwise:NO];
214 | [path appendPath:path1];
215 |
216 | UIBezierPath *path2 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.center.x,kCenterY)
217 | radius:Raduis
218 | startAngle:M_PI *3/2 - (M_PI_2 -angle)
219 | endAngle:-M_PI_2 - (M_PI_2 -angle)
220 | clockwise:NO];
221 |
222 |
223 | [path appendPath:path2];
224 |
225 | _changedLayer.path = path.CGPath;
226 |
227 |
228 |
229 | //平移量
230 | CGFloat toValue = lineWidth *(1- cos(M_PI_4)) /2.0;
231 | //finished 最终状态
232 | CGAffineTransform transform1 = CGAffineTransformMakeRotation(-M_PI_4);
233 | CGAffineTransform transform2 = CGAffineTransformMakeTranslation(-toValue, 0);
234 | CGAffineTransform transform3 = CGAffineTransformMakeRotation(M_PI_4);
235 |
236 | CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
237 | _topLineLayer.affineTransform = transform;
238 | transform = CGAffineTransformConcat(transform3, transform2);
239 | _bottomLineLayer.affineTransform = transform;
240 |
241 |
242 |
243 | CGFloat orignPercent = [self calculateCurveLength] / [self calculateTotalLength];
244 | CGFloat endPercent =([self calculateCurveLength] + Radians(120) *Raduis ) / [self calculateTotalLength];
245 |
246 | _changedLayer.strokeStart = endPercent;
247 |
248 | CAKeyframeAnimation *startAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeStart"];
249 | startAnimation.values = @[@0.0,@(endPercent)];
250 |
251 | CAKeyframeAnimation *EndAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
252 | EndAnimation.values = @[@(orignPercent),@1.0];
253 |
254 |
255 | CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
256 | animationGroup.animations = [NSArray arrayWithObjects:startAnimation,EndAnimation, nil];
257 | animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
258 | animationGroup.duration = kStep3Duration;
259 | animationGroup.delegate = self;
260 | animationGroup.removedOnCompletion = YES;
261 | [animationGroup setValue:@"animationStep3" forKey:@"animationName"];
262 | [_changedLayer addAnimation:animationGroup forKey:nil];
263 |
264 | //平移x
265 | CABasicAnimation *translationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
266 | translationAnimation.fromValue = [NSNumber numberWithFloat:0];
267 | translationAnimation.toValue = [NSNumber numberWithFloat:-toValue];
268 |
269 | //角度关键帧 上横线的关键帧 0 - 10° - (-55°) - (-45°)
270 | CAKeyframeAnimation *rotationAnimation1 = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
271 | rotationAnimation1.values = @[[NSNumber numberWithFloat:0],
272 | [NSNumber numberWithFloat:Radians(10) ],
273 | [NSNumber numberWithFloat:Radians(-10) - M_PI_4 ],
274 | [NSNumber numberWithFloat:- M_PI_4 ]
275 | ];
276 |
277 |
278 | CAAnimationGroup *transformGroup1 = [CAAnimationGroup animation];
279 | transformGroup1.animations = [NSArray arrayWithObjects:rotationAnimation1,translationAnimation, nil];
280 | transformGroup1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
281 | transformGroup1.duration = kStep3Duration;
282 | transformGroup1.removedOnCompletion = YES;
283 | [_topLineLayer addAnimation:transformGroup1 forKey:nil];
284 |
285 | //角度关键帧 下横线的关键帧 0 - (-10°) - (55°) - (45°)
286 | CAKeyframeAnimation *rotationAnimation2 = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
287 | rotationAnimation2.values = @[[NSNumber numberWithFloat:0],
288 | [NSNumber numberWithFloat:Radians(-10) ],
289 | [NSNumber numberWithFloat:Radians(10) + M_PI_4 ],
290 | [NSNumber numberWithFloat: M_PI_4 ]
291 | ];
292 |
293 |
294 | CAAnimationGroup *transformGroup2 = [CAAnimationGroup animation];
295 | transformGroup2.animations = [NSArray arrayWithObjects:rotationAnimation2,translationAnimation, nil];
296 | transformGroup2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
297 | transformGroup2.duration = kStep3Duration ;
298 | transformGroup2.delegate = self;
299 | transformGroup2.removedOnCompletion = YES;
300 | [_bottomLineLayer addAnimation:transformGroup2 forKey:nil];
301 |
302 | }
303 |
304 | -(void)cancelAnimation
305 | {
306 | //最关键是path路径
307 |
308 | UIBezierPath *path = [UIBezierPath bezierPath];
309 | //30度,经过反复测试,效果最好
310 | CGFloat angle = Radians(30);
311 |
312 | CGFloat startPointX = self.center.x + Raduis * cos(angle);
313 | CGFloat startPointY = kCenterY - Raduis * sin(angle);
314 |
315 | CGFloat controlPointX = self.center.x + Raduis *acos(angle);
316 | CGFloat controlPointY = kCenterY;
317 |
318 | CGFloat endPointX = self.center.x + lineWidth /2;
319 | CGFloat endPointY = kCenterY;
320 |
321 | //组合path 路径 起点 -150° 顺时针的圆
322 | path = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.center.x,kCenterY)
323 | radius:Raduis
324 | startAngle:-M_PI + angle
325 | endAngle:M_PI + angle
326 | clockwise:YES];
327 |
328 | //起点为 180°-> (360°-30°)
329 | UIBezierPath *path1 = [UIBezierPath bezierPathWithArcCenter:CGPointMake(self.center.x,kCenterY)
330 | radius:Raduis
331 | startAngle:M_PI + angle
332 | endAngle:2 * M_PI - angle
333 | clockwise:YES];
334 | [path appendPath:path1];
335 |
336 | //三点曲线
337 | UIBezierPath *path2 = [UIBezierPath bezierPath];
338 |
339 | [path2 moveToPoint:CGPointMake(startPointX, startPointY)];
340 |
341 | [path2 addCurveToPoint:CGPointMake(endPointX,endPointY)
342 | controlPoint1:CGPointMake(startPointX, startPointY)
343 | controlPoint2:CGPointMake(controlPointX, controlPointY)];
344 |
345 | [path appendPath:path2];
346 |
347 | //比原始状态向左偏移5个像素
348 | UIBezierPath *path3 = [UIBezierPath bezierPath];
349 | [path3 moveToPoint:CGPointMake(endPointX,endPointY)];
350 | [path3 addLineToPoint:CGPointMake(self.center.x - lineWidth/2 -5,endPointY)];
351 | [path appendPath:path3];
352 |
353 | _changedLayer.path = path.CGPath;
354 |
355 | //平移量
356 | CGFloat toValue = lineWidth *(1- cos(M_PI_4)) /2.0;
357 | //finished 最终状态
358 | CGAffineTransform transform1 = CGAffineTransformMakeRotation(0);
359 | CGAffineTransform transform2 = CGAffineTransformMakeTranslation(0, 0);
360 | CGAffineTransform transform3 = CGAffineTransformMakeRotation(0);
361 |
362 | CGAffineTransform transform = CGAffineTransformConcat(transform1, transform2);
363 | _topLineLayer.affineTransform = transform;
364 | transform = CGAffineTransformConcat(transform3, transform2);
365 | _bottomLineLayer.affineTransform = transform;
366 |
367 | //一个圆的长度比
368 | CGFloat endPercent = 2* M_PI *Raduis / ([self calculateTotalLength] + lineWidth);
369 |
370 |
371 | //横线占总path的长度比
372 | CGFloat percent = lineWidth / ([self calculateTotalLength] + lineWidth);
373 |
374 | _changedLayer.strokeStart = 1.0 -percent;
375 |
376 | CAKeyframeAnimation *startAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeStart"];
377 | startAnimation.values = @[@0.0,@0.3,@(1.0 -percent)];
378 |
379 | //在π+ angle
380 | CAKeyframeAnimation *EndAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
381 | EndAnimation.values = @[@(endPercent),@(endPercent),@1.0];
382 |
383 |
384 | CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
385 | animationGroup.animations = [NSArray arrayWithObjects:startAnimation,EndAnimation, nil];
386 | animationGroup.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
387 | animationGroup.duration = kStep4Duration;
388 | animationGroup.delegate = self;
389 | animationGroup.removedOnCompletion = YES;
390 | [animationGroup setValue:@"animationStep4" forKey:@"animationName"];
391 | [_changedLayer addAnimation:animationGroup forKey:nil];
392 |
393 | //平移x
394 | CABasicAnimation *translationAnimation = [CABasicAnimation animationWithKeyPath:@"transform.translation.x"];
395 | translationAnimation.fromValue = [NSNumber numberWithFloat:-toValue];
396 | translationAnimation.toValue = [NSNumber numberWithFloat:0];
397 |
398 | //角度关键帧 上横线的关键帧 (-45°) -> (-55°)-> 10° -> 0
399 | CAKeyframeAnimation *rotationAnimation1 = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
400 | rotationAnimation1.values = @[[NSNumber numberWithFloat:- M_PI_4 ],
401 | [NSNumber numberWithFloat:- Radians(10) - M_PI_4 ],
402 | [NSNumber numberWithFloat:Radians(10) ],
403 | [NSNumber numberWithFloat:0]
404 | ];
405 |
406 |
407 | CAAnimationGroup *transformGroup1 = [CAAnimationGroup animation];
408 | transformGroup1.animations = [NSArray arrayWithObjects:rotationAnimation1,translationAnimation, nil];
409 | transformGroup1.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
410 | transformGroup1.duration = kStep4Duration;
411 | transformGroup1.removedOnCompletion = YES;
412 | [_topLineLayer addAnimation:transformGroup1 forKey:nil];
413 |
414 | //角度关键帧 下横线的关键帧 (45°)-> (55°)- >(-10°)-> 0
415 | CAKeyframeAnimation *rotationAnimation2 = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
416 | rotationAnimation2.values = @[[NSNumber numberWithFloat: M_PI_4 ],
417 | [NSNumber numberWithFloat:Radians(10) + M_PI_4 ],
418 | [NSNumber numberWithFloat:-Radians(10) ],
419 | [NSNumber numberWithFloat:0]
420 | ];
421 |
422 | CAAnimationGroup *transformGroup2 = [CAAnimationGroup animation];
423 | transformGroup2.animations = [NSArray arrayWithObjects:rotationAnimation2,translationAnimation, nil];
424 | transformGroup2.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
425 | transformGroup2.duration = kStep4Duration;
426 | transformGroup2.delegate = self;
427 | transformGroup2.removedOnCompletion = YES;
428 | [_bottomLineLayer addAnimation:transformGroup2 forKey:nil];
429 |
430 | }
431 |
432 | //画上下两条横线
433 | -(void)initLayers
434 | {
435 | _topLineLayer = [CAShapeLayer layer];
436 | _bottomLineLayer = [CAShapeLayer layer];
437 | _changedLayer = [CAShapeLayer layer];
438 |
439 | CALayer *Toplayer = [CALayer layer];
440 | Toplayer.frame = CGRectMake((self.bounds.size.width + lineWidth)/2, kTopY, lineWidth, lineHeight);
441 | [self.layer addSublayer:Toplayer];
442 |
443 | CALayer *BottomLayer = [CALayer layer];
444 | BottomLayer.frame = CGRectMake((self.bounds.size.width + lineWidth)/2, kBottomY, lineWidth, lineHeight);
445 | [self.layer addSublayer:BottomLayer];
446 |
447 | // CALayer *centerLayer = [CALayer layer];
448 | // centerLayer.frame = CGRectMake((self.bounds.size.width + lineWidth)/2, kCenterY, lineWidth, lineHeight);
449 | // [self.layer addSublayer:centerLayer];
450 |
451 | CGFloat startOriginX = self.center.x - lineWidth /2.0;
452 | CGFloat endOriginX = self.center.x + lineWidth /2.0;
453 |
454 | [_topLineLayer setStrokeColor:[[UIColor whiteColor] CGColor]];
455 | _topLineLayer.contentsScale = [UIScreen mainScreen].scale;
456 | _topLineLayer.lineWidth = lineHeight ;
457 | _topLineLayer.lineCap = kCALineCapRound;
458 | _topLineLayer.position = CGPointMake(0,0);
459 |
460 |
461 | [_bottomLineLayer setStrokeColor:[[UIColor whiteColor] CGColor]];
462 | _bottomLineLayer.contentsScale = [UIScreen mainScreen].scale;
463 | _bottomLineLayer.lineWidth = lineHeight ;
464 | _bottomLineLayer.lineCap = kCALineCapRound;
465 |
466 | [_changedLayer setStrokeColor:[[UIColor whiteColor] CGColor]];
467 | _changedLayer.fillColor = [UIColor clearColor].CGColor;
468 | _changedLayer.contentsScale = [UIScreen mainScreen].scale;
469 | _changedLayer.lineWidth = lineHeight ;
470 | _changedLayer.lineCap = kCALineCapRound;
471 |
472 | UIBezierPath *path = [UIBezierPath bezierPath];
473 | [path moveToPoint:CGPointMake(0,0)];
474 | [path addLineToPoint:CGPointMake(-lineWidth,0)];
475 | _topLineLayer.path = path.CGPath;
476 |
477 | CGMutablePathRef solidChangedLinePath = CGPathCreateMutable();
478 | //被改变的layer实线
479 | CGPathMoveToPoint(solidChangedLinePath, NULL, startOriginX, kCenterY);
480 | CGPathAddLineToPoint(solidChangedLinePath, NULL, endOriginX, kCenterY);
481 | [_changedLayer setPath:solidChangedLinePath];
482 | CGPathRelease(solidChangedLinePath);
483 |
484 | // [path moveToPoint:CGPointMake(0,0)];
485 | // [path addLineToPoint:CGPointMake(-lineWidth,0)];
486 | // _changedLayer.path = path.CGPath;
487 |
488 | [path moveToPoint:CGPointMake(0,0)];
489 | [path addLineToPoint:CGPointMake(-lineWidth,0)];
490 | _bottomLineLayer.path = path.CGPath;
491 |
492 | [Toplayer addSublayer:_topLineLayer];
493 | [BottomLayer addSublayer:_bottomLineLayer];
494 | [self.layer addSublayer:_changedLayer];
495 |
496 | }
497 |
498 | -(CGFloat)calculateTotalLength
499 | {
500 |
501 | CGFloat curveLength = [self calculateCurveLength];
502 |
503 | //一个圆 + 120度弧长的 总长度
504 | CGFloat length = (Radians(120) + 2 * M_PI) * Raduis;
505 | CGFloat totalLength = curveLength + length;
506 |
507 | return totalLength;
508 | }
509 |
510 | -(CGFloat)calculateCurveLength{
511 |
512 | CGFloat angle = Radians(30);
513 |
514 | CGFloat endPointX = self.center.x + Raduis * cos(angle);
515 | CGFloat endPointY = kCenterY - Raduis * sin(angle);
516 |
517 | CGFloat startPointX = self.center.x + lineWidth/2.0;
518 | CGFloat startPointY = kCenterY;
519 |
520 | CGFloat controlPointX = self.center.x + Raduis *acos(angle);
521 | CGFloat controlPointY = kCenterY;
522 |
523 | CGFloat curveLength = [self bezierCurveLengthFromStartPoint:CGPointMake(startPointX, startPointY)
524 | toEndPoint:CGPointMake(endPointX,endPointY)
525 | withControlPoint:CGPointMake(controlPointX, controlPointY)];
526 |
527 | return curveLength;
528 | }
529 | //求贝塞尔曲线长度
530 | -(CGFloat) bezierCurveLengthFromStartPoint:(CGPoint)start toEndPoint:(CGPoint) end withControlPoint:(CGPoint) control
531 | {
532 | const int kSubdivisions = 50;
533 | const float step = 1.0f/(float)kSubdivisions;
534 |
535 | float totalLength = 0.0f;
536 | CGPoint prevPoint = start;
537 |
538 | // starting from i = 1, since for i = 0 calulated point is equal to start point
539 | for (int i = 1; i <= kSubdivisions; i++)
540 | {
541 | float t = i*step;
542 |
543 | float x = (1.0 - t)*(1.0 - t)*start.x + 2.0*(1.0 - t)*t*control.x + t*t*end.x;
544 | float y = (1.0 - t)*(1.0 - t)*start.y + 2.0*(1.0 - t)*t*control.y + t*t*end.y;
545 |
546 | CGPoint diff = CGPointMake(x - prevPoint.x, y - prevPoint.y);
547 |
548 | totalLength += sqrtf(diff.x*diff.x + diff.y*diff.y); // Pythagorean
549 |
550 | prevPoint = CGPointMake(x, y);
551 | }
552 |
553 | return totalLength;
554 | }
555 |
556 | -(void)dealloc
557 | {
558 | NSLog(@"dealloc");
559 | }
560 | @end
561 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/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 | CFBundleSignature
20 | ????
21 | CFBundleVersion
22 | 1
23 | LSRequiresIPhoneOS
24 |
25 | UILaunchStoryboardName
26 | LaunchScreen
27 | UIMainStoryboardFile
28 | Main
29 | UIRequiredDeviceCapabilities
30 |
31 | armv7
32 |
33 | UISupportedInterfaceOrientations
34 |
35 | UIInterfaceOrientationPortrait
36 | UIInterfaceOrientationLandscapeLeft
37 | UIInterfaceOrientationLandscapeRight
38 |
39 | UISupportedInterfaceOrientations~ipad
40 |
41 | UIInterfaceOrientationPortrait
42 | UIInterfaceOrientationPortraitUpsideDown
43 | UIInterfaceOrientationLandscapeLeft
44 | UIInterfaceOrientationLandscapeRight
45 |
46 |
47 |
48 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/ViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.h
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface ViewController : UIViewController
12 |
13 |
14 | @end
15 |
16 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/ViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // ViewController.m
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. All rights reserved.
7 | //
8 |
9 | #import "ViewController.h"
10 | #import "ChangeAnimationView.h"
11 |
12 | @interface ViewController ()
13 |
14 | @property (strong , nonatomic) ChangeAnimationView *animationView;
15 |
16 | @end
17 |
18 | @implementation ViewController
19 |
20 | - (void)viewDidLoad {
21 | [super viewDidLoad];
22 | // Do any additional setup after loading the view, typically from a nib.
23 |
24 | _animationView = [[ChangeAnimationView alloc] initWithFrame:CGRectMake(0, 150, self.view.bounds.size.width, 120)];
25 | [self.view addSubview:_animationView];
26 |
27 |
28 |
29 | UIButton *startButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
30 | startButton.frame = CGRectMake(10, 300, 100, 50);
31 | [startButton addTarget:self action:@selector(startAnimation:) forControlEvents:UIControlEventTouchUpInside];
32 | [startButton setTitle:@"启动动画" forState:UIControlStateNormal];
33 | [self.view addSubview:startButton];
34 |
35 | UIButton *stopButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
36 | stopButton.frame = CGRectMake(110, 300, 100, 50);
37 | [stopButton addTarget:self action:@selector(stopAnimation:) forControlEvents:UIControlEventTouchUpInside];
38 | [stopButton setTitle:@"暂停动画" forState:UIControlStateNormal];
39 | [self.view addSubview:stopButton];
40 |
41 | UIButton *resumeButton = [UIButton buttonWithType:UIButtonTypeRoundedRect];
42 | resumeButton.frame = CGRectMake(210, 300, 100, 50);
43 | [resumeButton addTarget:self action:@selector(resumeAnimation:) forControlEvents:UIControlEventTouchUpInside];
44 | [resumeButton setTitle:@"恢复动画" forState:UIControlStateNormal];
45 | [self.view addSubview:resumeButton];
46 |
47 |
48 | }
49 |
50 | -(void)startAnimation:(UIButton *)sender
51 | {
52 | [_animationView startAnimation];
53 | }
54 |
55 |
56 | -(void)stopAnimation:(UIButton *)sender
57 | {
58 | [_animationView stopAnimation];
59 | }
60 |
61 | -(void)resumeAnimation:(UIButton *)sender
62 | {
63 | [_animationView resumeAnimation];
64 | }
65 | @end
66 |
--------------------------------------------------------------------------------
/ZFChangeAnimation/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // ZFChangeAnimation
4 | //
5 | // Created by macOne on 15/12/11.
6 | // Copyright © 2015年 WZF. 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 |
--------------------------------------------------------------------------------
/origin animation.gif:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/WZF-Fei/ZFChangeAnimation/cd6788bf0d7abc7120f204b2369e8242c31615e9/origin animation.gif
--------------------------------------------------------------------------------