├── FeSpinner.xcodeproj
├── project.pbxproj
├── project.xcworkspace
│ └── contents.xcworkspacedata
└── xcuserdata
│ └── nghiatran.xcuserdatad
│ └── xcschemes
│ ├── FeSpinner.xcscheme
│ └── xcschememanagement.plist
├── FeSpinner
├── Base.lproj
│ ├── Main_iPad.storyboard
│ └── Main_iPhone.storyboard
├── CabinCondensed-Bold.ttf
├── FXBlurView.h
├── FXBlurView.m
├── FeAppDelegate.h
├── FeAppDelegate.m
├── FeEqualize.h
├── FeEqualize.m
├── FeEqualizerViewController.h
├── FeEqualizerViewController.m
├── FeHandwriting.h
├── FeHandwriting.m
├── FeHandwritingViewController.h
├── FeHandwritingViewController.m
├── FeHourGlass.h
├── FeHourGlass.m
├── FeHourGlassViewController.h
├── FeHourGlassViewController.m
├── FeLoadingBoxViewController.h
├── FeLoadingBoxViewController.m
├── FeLoadingIcon.h
├── FeLoadingIcon.m
├── FeLoadingIconBox.h
├── FeLoadingIconBox.m
├── FeRollingLoader.h
├── FeRollingLoader.m
├── FeRollingViewController.h
├── FeRollingViewController.m
├── FeSpinner-Info.plist
├── FeSpinner-Prefix.pch
├── FeSpinnerTenDot.h
├── FeSpinnerTenDot.m
├── FeSpinnerTenDotViewController.h
├── FeSpinnerTenDotViewController.m
├── FeTenDot.h
├── FeTenDot.m
├── FeThreeDotGlow.h
├── FeThreeDotGlow.m
├── FeThreeDotGlowViewController.h
├── FeThreeDotGlowViewController.m
├── FeVietNamBar.h
├── FeVietNamBar.m
├── FeVietNamLoader.h
├── FeVietNamLoader.m
├── FeVietNamLoaderViewController.h
├── FeVietNamLoaderViewController.m
├── FeViewController.h
├── FeViewController.m
├── FeWifiManHub.h
├── FeWifiManHub.m
├── FeWifiManHub.xib
├── FeWifiManViewController.h
├── FeWifiManViewController.m
├── FeZeroLoader.h
├── FeZeroLoader.m
├── FeZeroLoaderViewController.h
├── FeZeroLoaderViewController.m
├── Feasd.h
├── Feasd.m
├── Images.xcassets
│ ├── AppIcon.appiconset
│ │ └── Contents.json
│ └── LaunchImage.launchimage
│ │ └── Contents.json
├── Neou-Thin.ttf
├── UIColor+flat.h
├── UIColor+flat.m
├── WifiMan_Sign_1@2x.png
├── WifiMan_Sign_2@2x.png
├── WifiMan_Sign_3@2x.png
├── WifiMan_Sign_4@2x.png
├── en.lproj
│ └── InfoPlist.strings
├── main.m
├── wifimanhub@2x.png
└── wifimanhub_grayscale@2x.png
├── FeSpinnerTests
├── FeSpinnerTests-Info.plist
├── FeSpinnerTests.m
└── en.lproj
│ └── InfoPlist.strings
└── README.md
/FeSpinner.xcodeproj/project.xcworkspace/contents.xcworkspacedata:
--------------------------------------------------------------------------------
1 |
2 |
4 |
6 |
7 |
8 |
--------------------------------------------------------------------------------
/FeSpinner.xcodeproj/xcuserdata/nghiatran.xcuserdatad/xcschemes/FeSpinner.xcscheme:
--------------------------------------------------------------------------------
1 |
2 |
5 |
8 |
9 |
15 |
21 |
22 |
23 |
24 |
25 |
30 |
31 |
33 |
39 |
40 |
41 |
42 |
43 |
49 |
50 |
51 |
52 |
61 |
62 |
68 |
69 |
70 |
71 |
72 |
73 |
79 |
80 |
86 |
87 |
88 |
89 |
91 |
92 |
95 |
96 |
97 |
--------------------------------------------------------------------------------
/FeSpinner.xcodeproj/xcuserdata/nghiatran.xcuserdatad/xcschemes/xcschememanagement.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | SchemeUserState
6 |
7 | FeSpinner.xcscheme
8 |
9 | orderHint
10 | 0
11 |
12 |
13 | SuppressBuildableAutocreation
14 |
15 | BAE086FF183CE85100B12AB6
16 |
17 | primary
18 |
19 |
20 | BAE08723183CE85100B12AB6
21 |
22 | primary
23 |
24 |
25 |
26 |
27 |
28 |
--------------------------------------------------------------------------------
/FeSpinner/Base.lproj/Main_iPad.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 |
--------------------------------------------------------------------------------
/FeSpinner/CabinCondensed-Bold.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/CabinCondensed-Bold.ttf
--------------------------------------------------------------------------------
/FeSpinner/FXBlurView.h:
--------------------------------------------------------------------------------
1 | //
2 | // FXBlurView.h
3 | //
4 | // Version 1.4.3
5 | //
6 | // Created by Nick Lockwood on 25/08/2013.
7 | // Copyright (c) 2013 Charcoal Design
8 | //
9 | // Distributed under the permissive zlib License
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/nicklockwood/FXBlurView
13 | //
14 | // This software is provided 'as-is', without any express or implied
15 | // warranty. In no event will the authors be held liable for any damages
16 | // arising from the use of this software.
17 | //
18 | // Permission is granted to anyone to use this software for any purpose,
19 | // including commercial applications, and to alter it and redistribute it
20 | // freely, subject to the following restrictions:
21 | //
22 | // 1. The origin of this software must not be misrepresented; you must not
23 | // claim that you wrote the original software. If you use this software
24 | // in a product, an acknowledgment in the product documentation would be
25 | // appreciated but is not required.
26 | //
27 | // 2. Altered source versions must be plainly marked as such, and must not be
28 | // misrepresented as being the original software.
29 | //
30 | // 3. This notice may not be removed or altered from any source distribution.
31 | //
32 |
33 |
34 | #import
35 | #import
36 |
37 |
38 | @interface UIImage (FXBlurView)
39 |
40 | - (UIImage *)blurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor *)tintColor;
41 |
42 | @end
43 |
44 |
45 | @interface FXBlurView : UIView
46 |
47 | + (void)setBlurEnabled:(BOOL)blurEnabled;
48 | + (void)setUpdatesEnabled;
49 | + (void)setUpdatesDisabled;
50 |
51 | @property (nonatomic, getter = isBlurEnabled) BOOL blurEnabled;
52 | @property (nonatomic, getter = isDynamic) BOOL dynamic;
53 | @property (nonatomic, assign) NSUInteger iterations;
54 | @property (nonatomic, assign) NSTimeInterval updateInterval;
55 | @property (nonatomic, assign) CGFloat blurRadius;
56 | @property (nonatomic, strong) UIColor *tintColor;
57 |
58 | @end
59 |
--------------------------------------------------------------------------------
/FeSpinner/FXBlurView.m:
--------------------------------------------------------------------------------
1 | //
2 | // FXBlurView.m
3 | //
4 | // Version 1.4.3
5 | //
6 | // Created by Nick Lockwood on 25/08/2013.
7 | // Copyright (c) 2013 Charcoal Design
8 | //
9 | // Distributed under the permissive zlib License
10 | // Get the latest version from here:
11 | //
12 | // https://github.com/nicklockwood/FXBlurView
13 | //
14 | // This software is provided 'as-is', without any express or implied
15 | // warranty. In no event will the authors be held liable for any damages
16 | // arising from the use of this software.
17 | //
18 | // Permission is granted to anyone to use this software for any purpose,
19 | // including commercial applications, and to alter it and redistribute it
20 | // freely, subject to the following restrictions:
21 | //
22 | // 1. The origin of this software must not be misrepresented; you must not
23 | // claim that you wrote the original software. If you use this software
24 | // in a product, an acknowledgment in the product documentation would be
25 | // appreciated but is not required.
26 | //
27 | // 2. Altered source versions must be plainly marked as such, and must not be
28 | // misrepresented as being the original software.
29 | //
30 | // 3. This notice may not be removed or altered from any source distribution.
31 | //
32 |
33 |
34 | #import "FXBlurView.h"
35 | #import
36 | #import
37 | #import
38 |
39 |
40 | #import
41 | #if !__has_feature(objc_arc)
42 | #error This class requires automatic reference counting
43 | #endif
44 |
45 |
46 | @implementation UIImage (FXBlurView)
47 |
48 | - (UIImage *)blurredImageWithRadius:(CGFloat)radius iterations:(NSUInteger)iterations tintColor:(UIColor *)tintColor
49 | {
50 | //image must be nonzero size
51 | if (floorf(self.size.width) * floorf(self.size.height) <= 0.0f) return self;
52 |
53 | //boxsize must be an odd integer
54 | uint32_t boxSize = radius * self.scale;
55 | if (boxSize % 2 == 0) boxSize ++;
56 |
57 | //create image buffers
58 | CGImageRef imageRef = self.CGImage;
59 | vImage_Buffer buffer1, buffer2;
60 | buffer1.width = buffer2.width = CGImageGetWidth(imageRef);
61 | buffer1.height = buffer2.height = CGImageGetHeight(imageRef);
62 | buffer1.rowBytes = buffer2.rowBytes = CGImageGetBytesPerRow(imageRef);
63 | CFIndex bytes = buffer1.rowBytes * buffer1.height;
64 | buffer1.data = malloc(bytes);
65 | buffer2.data = malloc(bytes);
66 |
67 | //create temp buffer
68 | void *tempBuffer = malloc(vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, NULL, 0, 0, boxSize, boxSize,
69 | NULL, kvImageEdgeExtend + kvImageGetTempBufferSize));
70 |
71 | //copy image data
72 | CFDataRef dataSource = CGDataProviderCopyData(CGImageGetDataProvider(imageRef));
73 | memcpy(buffer1.data, CFDataGetBytePtr(dataSource), bytes);
74 | CFRelease(dataSource);
75 |
76 | for (NSUInteger i = 0; i < iterations; i++)
77 | {
78 | //perform blur
79 | vImageBoxConvolve_ARGB8888(&buffer1, &buffer2, tempBuffer, 0, 0, boxSize, boxSize, NULL, kvImageEdgeExtend);
80 |
81 | //swap buffers
82 | void *temp = buffer1.data;
83 | buffer1.data = buffer2.data;
84 | buffer2.data = temp;
85 | }
86 |
87 | //free buffers
88 | free(buffer2.data);
89 | free(tempBuffer);
90 |
91 | //create image context from buffer
92 | CGContextRef ctx = CGBitmapContextCreate(buffer1.data, buffer1.width, buffer1.height,
93 | 8, buffer1.rowBytes, CGImageGetColorSpace(imageRef),
94 | CGImageGetBitmapInfo(imageRef));
95 |
96 | //apply tint
97 | if (tintColor && CGColorGetAlpha(tintColor.CGColor) > 0.0f)
98 | {
99 | CGContextSetFillColorWithColor(ctx, [tintColor colorWithAlphaComponent:0.25].CGColor);
100 | CGContextSetBlendMode(ctx, kCGBlendModePlusLighter);
101 | CGContextFillRect(ctx, CGRectMake(0, 0, buffer1.width, buffer1.height));
102 | }
103 |
104 | //create image from context
105 | imageRef = CGBitmapContextCreateImage(ctx);
106 | UIImage *image = [UIImage imageWithCGImage:imageRef scale:self.scale orientation:self.imageOrientation];
107 | CGImageRelease(imageRef);
108 | CGContextRelease(ctx);
109 | free(buffer1.data);
110 | return image;
111 | }
112 |
113 | @end
114 |
115 |
116 | @interface FXBlurScheduler : NSObject
117 |
118 | @property (nonatomic, strong) NSMutableArray *views;
119 | @property (nonatomic, assign) NSInteger viewIndex;
120 | @property (nonatomic, assign) NSInteger updatesEnabled;
121 | @property (nonatomic, assign) BOOL blurEnabled;
122 | @property (nonatomic, assign) BOOL updating;
123 |
124 | @end
125 |
126 |
127 | @interface FXBlurView ()
128 |
129 | @property (nonatomic, assign) BOOL iterationsSet;
130 | @property (nonatomic, assign) BOOL blurRadiusSet;
131 | @property (nonatomic, assign) BOOL dynamicSet;
132 | @property (nonatomic, assign) BOOL blurEnabledSet;
133 | @property (nonatomic, strong) NSDate *lastUpdate;
134 |
135 | - (UIImage *)snapshotOfSuperview:(UIView *)superview;
136 |
137 | @end
138 |
139 |
140 | @implementation FXBlurScheduler
141 |
142 | + (instancetype)sharedInstance
143 | {
144 | static FXBlurScheduler *sharedInstance = nil;
145 | if (!sharedInstance)
146 | {
147 | sharedInstance = [[FXBlurScheduler alloc] init];
148 | }
149 | return sharedInstance;
150 | }
151 |
152 | - (instancetype)init
153 | {
154 | if (self = [super init])
155 | {
156 | _updatesEnabled = 1;
157 | _blurEnabled = YES;
158 | _views = [[NSMutableArray alloc] init];
159 | }
160 | return self;
161 | }
162 |
163 | - (void)setBlurEnabled:(BOOL)blurEnabled
164 | {
165 | _blurEnabled = blurEnabled;
166 | if (blurEnabled)
167 | {
168 | for (FXBlurView *view in self.views)
169 | {
170 | [view setNeedsDisplay];
171 | }
172 | [self updateAsynchronously];
173 | }
174 | }
175 |
176 | - (void)setUpdatesEnabled
177 | {
178 | _updatesEnabled ++;
179 | [self updateAsynchronously];
180 | }
181 |
182 | - (void)setUpdatesDisabled
183 | {
184 | _updatesEnabled --;
185 | }
186 |
187 | - (void)addView:(FXBlurView *)view
188 | {
189 | if (![self.views containsObject:view])
190 | {
191 | [self.views addObject:view];
192 | [self updateAsynchronously];
193 | }
194 | }
195 |
196 | - (void)removeView:(FXBlurView *)view
197 | {
198 | NSInteger index = [self.views indexOfObject:view];
199 | if (index != NSNotFound)
200 | {
201 | if (index <= self.viewIndex)
202 | {
203 | self.viewIndex --;
204 | }
205 | [self.views removeObjectAtIndex:index];
206 | }
207 | }
208 |
209 | - (void)updateAsynchronously
210 | {
211 | if (self.blurEnabled && !self.updating && self.updatesEnabled > 0 && [self.views count])
212 | {
213 | //loop through until we find a view that's ready to be drawn
214 | self.viewIndex = self.viewIndex % [self.views count];
215 | for (NSUInteger i = self.viewIndex; i < [self.views count]; i++)
216 | {
217 | FXBlurView *view = self.views[i];
218 | if (view.blurEnabled && view.dynamic && view.window &&
219 | (!view.lastUpdate || [view.lastUpdate timeIntervalSinceNow] < -view.updateInterval) &&
220 | !CGRectIsEmpty(view.bounds) && !CGRectIsEmpty(view.superview.bounds))
221 | {
222 | self.updating = YES;
223 | UIImage *snapshot = [view snapshotOfSuperview:view.superview];
224 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_LOW, 0), ^{
225 |
226 | UIImage *blurredImage = [snapshot blurredImageWithRadius:view.blurRadius
227 | iterations:view.iterations
228 | tintColor:view.tintColor];
229 | dispatch_sync(dispatch_get_main_queue(), ^{
230 |
231 | //set image
232 | self.updating = NO;
233 | if (view.dynamic)
234 | {
235 | view.layer.contents = (id)blurredImage.CGImage;
236 | view.layer.contentsScale = blurredImage.scale;
237 | }
238 |
239 | //render next view
240 | self.viewIndex = i + 1;
241 | [self performSelectorOnMainThread:@selector(updateAsynchronously) withObject:nil
242 | waitUntilDone:NO modes:@[NSDefaultRunLoopMode, UITrackingRunLoopMode]];
243 | });
244 | });
245 | return;
246 | }
247 | }
248 |
249 | //try again
250 | self.viewIndex = 0;
251 | [self performSelectorOnMainThread:@selector(updateAsynchronously) withObject:nil
252 | waitUntilDone:NO modes:@[NSDefaultRunLoopMode, UITrackingRunLoopMode]];
253 | }
254 | }
255 |
256 | @end
257 |
258 |
259 | @implementation FXBlurView
260 |
261 | + (void)setBlurEnabled:(BOOL)blurEnabled
262 | {
263 | [FXBlurScheduler sharedInstance].blurEnabled = blurEnabled;
264 | }
265 |
266 | + (void)setUpdatesEnabled
267 | {
268 | [[FXBlurScheduler sharedInstance] setUpdatesEnabled];
269 | }
270 |
271 | + (void)setUpdatesDisabled
272 | {
273 | [[FXBlurScheduler sharedInstance] setUpdatesDisabled];
274 | }
275 |
276 | - (void)setUp
277 | {
278 | if (!_iterationsSet) _iterations = 3;
279 | if (!_blurRadiusSet) _blurRadius = 40.0f;
280 | if (!_dynamicSet) _dynamic = YES;
281 | if (!_blurEnabledSet) _blurEnabled = YES;
282 | self.updateInterval = _updateInterval;
283 |
284 | unsigned int numberOfMethods;
285 | Method *methods = class_copyMethodList([UIView class], &numberOfMethods);
286 | for (unsigned int i = 0; i < numberOfMethods; i++)
287 | {
288 | Method method = methods[i];
289 | SEL selector = method_getName(method);
290 | if (selector == @selector(tintColor))
291 | {
292 | _tintColor = ((id (*)(id,SEL))method_getImplementation(method))(self, selector);
293 | break;
294 | }
295 | }
296 | free(methods);
297 | }
298 |
299 | - (id)initWithFrame:(CGRect)frame
300 | {
301 | if ((self = [super initWithFrame:frame]))
302 | {
303 | [self setUp];
304 | self.clipsToBounds = YES;
305 | }
306 | return self;
307 | }
308 |
309 | - (id)initWithCoder:(NSCoder *)aDecoder
310 | {
311 | if ((self = [super initWithCoder:aDecoder]))
312 | {
313 | [self setUp];
314 | }
315 | return self;
316 | }
317 |
318 | - (void)dealloc
319 | {
320 | [[NSNotificationCenter defaultCenter] removeObserver:self];
321 | }
322 |
323 | - (void)setIterations:(NSUInteger)iterations
324 | {
325 | _iterationsSet = YES;
326 | _iterations = iterations;
327 | [self setNeedsDisplay];
328 | }
329 |
330 | - (void)setBlurRadius:(CGFloat)blurRadius
331 | {
332 | _blurRadiusSet = YES;
333 | _blurRadius = blurRadius;
334 | [self setNeedsDisplay];
335 | }
336 |
337 | - (void)setBlurEnabled:(BOOL)blurEnabled
338 | {
339 | _blurEnabledSet = YES;
340 | if (_blurEnabled != blurEnabled)
341 | {
342 | _blurEnabled = blurEnabled;
343 | [self schedule];
344 | if (_blurEnabled)
345 | {
346 | [self setNeedsDisplay];
347 | }
348 | }
349 | }
350 |
351 | - (void)setDynamic:(BOOL)dynamic
352 | {
353 | _dynamicSet = YES;
354 | if (_dynamic != dynamic)
355 | {
356 | _dynamic = dynamic;
357 | [self schedule];
358 | if (!dynamic)
359 | {
360 | [self setNeedsDisplay];
361 | }
362 | }
363 | }
364 |
365 | - (void)setUpdateInterval:(NSTimeInterval)updateInterval
366 | {
367 | _updateInterval = updateInterval;
368 | if (_updateInterval <= 0) _updateInterval = 1.0/60;
369 | }
370 |
371 | - (void)setTintColor:(UIColor *)tintColor
372 | {
373 | _tintColor = tintColor;
374 | [self setNeedsDisplay];
375 | }
376 |
377 | - (void)didMoveToSuperview
378 | {
379 | [super didMoveToSuperview];
380 | [self.layer setNeedsDisplay];
381 | }
382 |
383 | - (void)didMoveToWindow
384 | {
385 | [super didMoveToWindow];
386 | [self schedule];
387 | }
388 |
389 | - (void)schedule
390 | {
391 | if (self.window && self.dynamic && self.blurEnabled)
392 | {
393 | [[FXBlurScheduler sharedInstance] addView:self];
394 | }
395 | else
396 | {
397 | [[FXBlurScheduler sharedInstance] removeView:self];
398 | }
399 | }
400 |
401 | - (void)setNeedsDisplay
402 | {
403 | [super setNeedsDisplay];
404 | [self.layer setNeedsDisplay];
405 | }
406 |
407 | - (void)displayLayer:(__unused CALayer *)layer
408 | {
409 | if ([FXBlurScheduler sharedInstance].blurEnabled && self.blurEnabled && self.superview &&
410 | !CGRectIsEmpty(self.bounds) && !CGRectIsEmpty(self.superview.bounds))
411 | {
412 | UIImage *snapshot = [self snapshotOfSuperview:self.superview];
413 | UIImage *blurredImage = [snapshot blurredImageWithRadius:self.blurRadius
414 | iterations:self.iterations
415 | tintColor:self.tintColor];
416 | self.layer.contents = (id)blurredImage.CGImage;
417 | self.layer.contentsScale = blurredImage.scale;
418 | }
419 | }
420 |
421 | - (UIImage *)snapshotOfSuperview:(UIView *)superview
422 | {
423 | self.lastUpdate = [NSDate date];
424 | CGFloat scale = 0.5;
425 | if (self.iterations > 0 && ([UIScreen mainScreen].scale > 1 || self.contentMode == UIViewContentModeScaleAspectFill))
426 | {
427 | CGFloat blockSize = 12.0f/self.iterations;
428 | scale = blockSize/MAX(blockSize * 2, floor(self.blurRadius));
429 | }
430 | CGSize size = self.bounds.size;
431 | size.width = ceilf(size.width * scale) / scale;
432 | size.height = ceilf(size.height * scale) / scale;
433 | UIGraphicsBeginImageContextWithOptions(self.bounds.size, YES, scale);
434 | CGContextRef context = UIGraphicsGetCurrentContext();
435 | CGContextTranslateCTM(context, -self.frame.origin.x, -self.frame.origin.y);
436 | CGContextScaleCTM(context, size.width / self.bounds.size.width, size.height / self.bounds.size.height);
437 | NSArray *hiddenViews = [self prepareSuperviewForSnapshot:superview];
438 | [superview.layer renderInContext:context];
439 | [self restoreSuperviewAfterSnapshot:hiddenViews];
440 | UIImage *snapshot = UIGraphicsGetImageFromCurrentImageContext();
441 | UIGraphicsEndImageContext();
442 | return snapshot;
443 | }
444 |
445 | - (NSArray *)prepareSuperviewForSnapshot:(UIView *)superview
446 | {
447 | NSMutableArray *views = [NSMutableArray array];
448 | NSInteger index = [superview.subviews indexOfObject:self];
449 | if (index != NSNotFound)
450 | {
451 | for (NSUInteger i = index; i < [superview.subviews count]; i++)
452 | {
453 | UIView *view = superview.subviews[i];
454 | if (!view.hidden)
455 | {
456 | view.hidden = YES;
457 | [views addObject:view];
458 | }
459 | }
460 | }
461 | return views;
462 | }
463 |
464 | - (void)restoreSuperviewAfterSnapshot:(NSArray *)hiddenViews
465 | {
466 | for (UIView *view in hiddenViews)
467 | {
468 | view.hidden = NO;
469 | }
470 | }
471 |
472 | @end
473 |
--------------------------------------------------------------------------------
/FeSpinner/FeAppDelegate.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeAppDelegate.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/20/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeAppDelegate : UIResponder
12 |
13 | @property (strong, nonatomic) UIWindow *window;
14 |
15 | @end
16 |
--------------------------------------------------------------------------------
/FeSpinner/FeAppDelegate.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeAppDelegate.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/20/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeAppDelegate.h"
10 |
11 | @implementation FeAppDelegate
12 |
13 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
14 | {
15 | // Override point for customization after application launch.
16 |
17 | /*
18 | NSArray *fontFamilies = [UIFont familyNames];
19 |
20 | for (int i = 0; i < [fontFamilies count]; i++)
21 | {
22 | NSString *fontFamily = [fontFamilies objectAtIndex:i];
23 | NSArray *fontNames = [UIFont fontNamesForFamilyName:[fontFamilies objectAtIndex:i]];
24 | NSLog (@"%@: %@", fontFamily, fontNames);
25 | }
26 | */
27 | return YES;
28 | }
29 |
30 | - (void)applicationWillResignActive:(UIApplication *)application
31 | {
32 | // 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.
33 | // 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.
34 | }
35 |
36 | - (void)applicationDidEnterBackground:(UIApplication *)application
37 | {
38 | // 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.
39 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits.
40 | }
41 |
42 | - (void)applicationWillEnterForeground:(UIApplication *)application
43 | {
44 | // 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.
45 | }
46 |
47 | - (void)applicationDidBecomeActive:(UIApplication *)application
48 | {
49 | // 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.
50 | }
51 |
52 | - (void)applicationWillTerminate:(UIApplication *)application
53 | {
54 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:.
55 | }
56 |
57 | @end
58 |
--------------------------------------------------------------------------------
/FeSpinner/FeEqualize.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeEqualize.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeEqualize : UIView
12 | // is running
13 | @property (assign, readonly, nonatomic) BOOL isShowing;
14 |
15 | -(instancetype) initWithView:(UIView *) view title:(NSString *) title;
16 |
17 | -(void) show;
18 |
19 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
20 |
21 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
22 |
23 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
24 |
25 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
26 |
27 | -(void) dismiss;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/FeSpinner/FeEqualize.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeEqualize.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeEqualize.h"
10 | #import "UIColor+flat.h"
11 | #import
12 |
13 | #define kFe_Equalize_Width 100.0f
14 | #define kFe_Equalize_Height 50.0f
15 |
16 | #define kFe_Equalize_Bar_Width 20.0f
17 | #define kFe_Equalize_Bar_Height 50.0f
18 |
19 | @interface FeEqualize ()
20 | {
21 | NSString *_title;
22 |
23 | // Target, method, object and block
24 | id targetForExecuting;
25 | SEL methodForExecuting;
26 | id objectForExecuting;
27 | dispatch_block_t completionBlock;
28 | }
29 | // Container View
30 | @property (strong, nonatomic) UIView *containerView;
31 | @property (strong, nonatomic) CALayer *containerLayer;
32 |
33 | // Bars
34 | @property (strong, nonatomic) CAShapeLayer *firstBar;
35 | @property (strong, nonatomic) CAShapeLayer *secondBar;
36 | @property (strong, nonatomic) CAShapeLayer *thirdBar;
37 | @property (strong, nonatomic) CAShapeLayer *fourthBar;
38 | @property (strong, nonatomic) CAShapeLayer *fifthBar;
39 |
40 | // Bezier path
41 | @property (strong, nonatomic) UIBezierPath *originalBezierPath;
42 | @property (strong, nonatomic) UIBezierPath *endBezierPath;
43 |
44 | // Animation
45 | @property (strong, nonatomic) CABasicAnimation *firstAnimation;
46 | @property (strong, nonatomic) CABasicAnimation *secondAnimation;
47 | @property (strong, nonatomic) CABasicAnimation *thirdAnimation;
48 | @property (strong, nonatomic) CABasicAnimation *fourthAnimation;
49 | @property (strong, nonatomic) CABasicAnimation *fifthAnimation;
50 |
51 | // Title
52 | @property (strong, nonatomic) UILabel *titleLbl;
53 | /////////
54 | -(void) initCommon;
55 | -(void) initContainerLayer;
56 | -(void) initBars;
57 | -(void) initBezierPath;
58 | -(void) initTitle;
59 | -(void) initAnimation;
60 | @end
61 |
62 | @implementation FeEqualize
63 |
64 | -(instancetype) initWithView:(UIView *)view title:(NSString *)title
65 | {
66 | self = [super init];
67 | if (self)
68 | {
69 | _title = title;
70 |
71 | _containerView = view;
72 |
73 | [self initCommon];
74 |
75 | [self initContainerLayer];
76 |
77 | [self initBezierPath];
78 |
79 | [self initBars];
80 |
81 | [self initTitle];
82 |
83 | [self initAnimation];
84 | }
85 | return self;
86 | }
87 | -(void) initCommon
88 | {
89 | _isShowing = NO;
90 |
91 | self.frame = CGRectMake(0, 0, _containerView.bounds.size.width, _containerView.bounds.size.height);
92 | self.backgroundColor = [UIColor colorWithHexCode:@"#141517"];
93 | }
94 |
95 | -(void) initContainerLayer
96 | {
97 | _containerLayer = [CALayer layer];
98 | _containerLayer.backgroundColor = [UIColor clearColor].CGColor;
99 | _containerLayer.frame = CGRectMake(0, 0, kFe_Equalize_Width, kFe_Equalize_Height);
100 | _containerLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
101 | _containerLayer.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
102 |
103 | [self.layer addSublayer:_containerLayer];
104 | }
105 | -(void) initBars
106 | {
107 | for (NSInteger i = 0; i < 5 ; i++)
108 | {
109 | CGPoint origin = CGPointMake(kFe_Equalize_Bar_Width * i, 0);
110 | if (i == 0)
111 | {
112 | _firstBar = [CAShapeLayer layer];
113 | _firstBar.frame = CGRectMake(origin.x, origin.y, kFe_Equalize_Width, kFe_Equalize_Width);
114 | _firstBar.path = _originalBezierPath.CGPath;
115 | _firstBar.fillColor = [UIColor colorWithHexCode:@"#0B486B"].CGColor;
116 |
117 |
118 | [_containerLayer addSublayer:_firstBar];
119 | }
120 | if (i == 1)
121 | {
122 | _secondBar = [CAShapeLayer layer];
123 | _secondBar.frame = CGRectMake(origin.x, origin.y, kFe_Equalize_Bar_Width, kFe_Equalize_Bar_Height);
124 | _secondBar.fillColor = [UIColor colorWithHexCode:@"#3B8686"].CGColor;
125 | _secondBar.path = _originalBezierPath.CGPath;
126 |
127 | [_containerLayer addSublayer:_secondBar];
128 | }
129 | if (i == 2)
130 | {
131 | _thirdBar = [CAShapeLayer layer];
132 | _thirdBar.frame = CGRectMake(origin.x, origin.y, kFe_Equalize_Bar_Width, kFe_Equalize_Bar_Height);
133 | _thirdBar.fillColor = [UIColor colorWithHexCode:@"#79BD9A"].CGColor;
134 | _thirdBar.path = _originalBezierPath.CGPath;
135 |
136 | [_containerLayer addSublayer:_thirdBar];
137 | }
138 | if (i == 3)
139 | {
140 | _fourthBar = [CAShapeLayer layer];
141 | _fourthBar.frame = CGRectMake(origin.x, origin.y, kFe_Equalize_Bar_Width, kFe_Equalize_Bar_Height);
142 | _fourthBar.fillColor = [UIColor colorWithHexCode:@"#A8DBA8"].CGColor;
143 | _fourthBar.path = _originalBezierPath.CGPath;
144 |
145 | [_containerLayer addSublayer:_fourthBar];
146 | }
147 | if (i == 4)
148 | {
149 | _fifthBar = [CAShapeLayer layer];
150 | _fifthBar.frame = CGRectMake(origin.x, origin.y, kFe_Equalize_Bar_Width, kFe_Equalize_Bar_Height);
151 | _fifthBar.fillColor = [UIColor colorWithHexCode:@"#CFF09E"].CGColor;
152 | _fifthBar.path = _originalBezierPath.CGPath;
153 |
154 | [_containerLayer addSublayer:_fifthBar];
155 | }
156 | }
157 | }
158 | -(void) initBezierPath
159 | {
160 | // Original Path
161 | _originalBezierPath = [UIBezierPath bezierPath];
162 | [_originalBezierPath moveToPoint:CGPointMake(0, kFe_Equalize_Bar_Height)];
163 | [_originalBezierPath addLineToPoint:CGPointMake(kFe_Equalize_Bar_Width / 2.0f, kFe_Equalize_Bar_Height - 2.0f)];
164 | [_originalBezierPath addLineToPoint:CGPointMake(kFe_Equalize_Bar_Width, kFe_Equalize_Bar_Height)];
165 | [_originalBezierPath addLineToPoint:CGPointMake(0, kFe_Equalize_Bar_Height)];
166 | [_originalBezierPath closePath];
167 |
168 | // end Path
169 | _endBezierPath = [UIBezierPath bezierPath];
170 | [_endBezierPath moveToPoint:CGPointMake(0, kFe_Equalize_Bar_Height)];
171 | [_endBezierPath addLineToPoint:CGPointMake(kFe_Equalize_Bar_Width / 2.0f, 0)];
172 | [_endBezierPath addLineToPoint:CGPointMake(kFe_Equalize_Bar_Width, kFe_Equalize_Bar_Height)];
173 | [_endBezierPath addLineToPoint:CGPointMake(0, kFe_Equalize_Bar_Height)];
174 | [_endBezierPath closePath];
175 |
176 | }
177 | -(void) initAnimation
178 | {
179 | // First
180 | _firstAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
181 | _firstAnimation.fromValue = (id) _originalBezierPath.CGPath;
182 | _firstAnimation.toValue = (id) _endBezierPath.CGPath;
183 | _firstAnimation.autoreverses = YES;
184 | _firstAnimation.duration = 0.5f;
185 | _firstAnimation.repeatCount = MAXFLOAT;
186 | _firstAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.77 :0 :0.175 :1];
187 |
188 | _secondAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
189 | _secondAnimation.fromValue = (id) _originalBezierPath.CGPath;
190 | _secondAnimation.toValue = (id) _endBezierPath.CGPath;
191 | _secondAnimation.autoreverses = YES;
192 | _secondAnimation.duration = 0.5f;
193 | _secondAnimation.repeatCount = MAXFLOAT;
194 | _secondAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.77 :0 :0.175 :1];
195 |
196 | _thirdAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
197 | _thirdAnimation.fromValue = (id) _originalBezierPath.CGPath;
198 | _thirdAnimation.toValue = (id) _endBezierPath.CGPath;
199 | _thirdAnimation.autoreverses = YES;
200 | _thirdAnimation.duration = 0.5f;
201 | _thirdAnimation.repeatCount = MAXFLOAT;
202 | _thirdAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.77 :0 :0.175 :1];
203 |
204 | _fourthAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
205 | _fourthAnimation.fromValue = (id) _originalBezierPath.CGPath;
206 | _fourthAnimation.toValue = (id) _endBezierPath.CGPath;
207 | _fourthAnimation.autoreverses = YES;
208 | _fourthAnimation.duration = 0.5f;
209 | _fourthAnimation.repeatCount = MAXFLOAT;
210 | _fourthAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.77 :0 :0.175 :1];
211 |
212 | _fifthAnimation = [CABasicAnimation animationWithKeyPath:@"path"];
213 | _fifthAnimation.fromValue = (id) _originalBezierPath.CGPath;
214 | _fifthAnimation.toValue = (id) _endBezierPath.CGPath;
215 | _fifthAnimation.autoreverses = YES;
216 | _fifthAnimation.duration = 0.5f;
217 | _fifthAnimation.repeatCount = MAXFLOAT;
218 | _fifthAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.77 :0 :0.175 :1];
219 | }
220 | -(void) initTitle
221 | {
222 | _titleLbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
223 | _titleLbl.text = _title;
224 | _titleLbl.textAlignment = NSTextAlignmentCenter;
225 | _titleLbl.textColor = [UIColor colorWithHexCode:@"#CFF09E"];
226 | _titleLbl.font = [UIFont boldSystemFontOfSize:20];
227 | [_titleLbl sizeToFit];
228 | _titleLbl.center = CGPointMake(self.bounds.size.width / 2.0f, _containerLayer.frame.origin.y + _containerLayer.frame.size.height + 16);
229 |
230 | [self addSubview:_titleLbl];
231 | }
232 |
233 | #pragma mark - Action
234 | -(void) show
235 | {
236 | if (_isShowing)
237 | return;
238 |
239 | _isShowing = YES;
240 |
241 | [self performSelector:@selector(addFirstAniamtion) withObject:nil afterDelay:0];
242 | [self performSelector:@selector(addSecondAnimation) withObject:nil afterDelay:0.1f];
243 | [self performSelector:@selector(addThirdAnimation) withObject:nil afterDelay:0.2f];
244 | [self performSelector:@selector(addFourthAnimation) withObject:nil afterDelay:0.3f];
245 | [self performSelector:@selector(addFifthAnimation) withObject:nil afterDelay:0.4f];
246 | }
247 |
248 | -(void) dismiss
249 | {
250 | if (!_isShowing)
251 | return;
252 |
253 | _isShowing = NO;
254 |
255 | }
256 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
257 | {
258 | [self showWhileExecutingBlock:block completion:nil];
259 | }
260 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
261 | {
262 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
263 |
264 | }
265 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
266 | {
267 | // Check block != nil
268 | if (block != nil)
269 | {
270 | [self show];
271 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
272 | {
273 | block();
274 |
275 | // Update UI
276 | dispatch_async(dispatch_get_main_queue(), ^{
277 | completion();
278 | [self dismiss];
279 | });
280 | });
281 | }
282 | }
283 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
284 | {
285 | // Check Selector is responded
286 | if ([target respondsToSelector:selector])
287 | {
288 | methodForExecuting = selector;
289 | targetForExecuting = target;
290 | objectForExecuting = object;
291 | completionBlock = completion;
292 |
293 | [self show];
294 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
295 | }
296 | }
297 | #pragma mark Helper method
298 | -(void) executingMethod
299 | {
300 | @autoreleasepool {
301 | #pragma clang diagnostic push
302 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
303 | // Start executing the requested task
304 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
305 | #pragma clang diagnostic pop
306 | // Task completed, update view in main thread (note: view operations should
307 | // be done only in the main thread)
308 | dispatch_async(dispatch_get_main_queue(), ^{
309 | completionBlock();
310 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
311 | });
312 |
313 | }
314 | }
315 | -(void) cleanUp
316 | {
317 | NSLog(@"Clean up");
318 | if (objectForExecuting)
319 | objectForExecuting = nil;
320 | if (methodForExecuting)
321 | methodForExecuting = nil;
322 | if (targetForExecuting)
323 | targetForExecuting = nil;
324 | if (completionBlock)
325 | completionBlock = nil;
326 | [self dismiss];
327 | }
328 | #pragma mark - Private
329 | -(void) addFirstAniamtion
330 | {
331 | [_firstBar addAnimation:_firstAnimation forKey:@"firstAnimation"];
332 | }
333 | -(void) addSecondAnimation
334 | {
335 | [_secondBar addAnimation:_secondAnimation forKey:@"secondAnimation"];
336 | }
337 | -(void) addThirdAnimation
338 | {
339 | [_thirdBar addAnimation:_thirdAnimation forKey:@"thirdAnimatin"];
340 | }
341 | -(void) addFourthAnimation
342 | {
343 | [_fourthBar addAnimation:_fourthAnimation forKey:@"fourthAnimation"];
344 | }
345 | -(void) addFifthAnimation
346 | {
347 | [_fifthBar addAnimation:_fifthAnimation forKey:@"fifthAnimation"];
348 | }
349 | @end
350 |
--------------------------------------------------------------------------------
/FeSpinner/FeEqualizerViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeEqualizerViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/15/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeEqualizerViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeEqualizerViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeEqualizerViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/15/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeEqualizerViewController.h"
10 | #import "FeEqualize.h"
11 |
12 | @interface FeEqualizerViewController ()
13 | @property (strong, nonatomic) FeEqualize *equalizer;
14 | @end
15 |
16 | @implementation FeEqualizerViewController
17 |
18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
19 | {
20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
21 | if (self) {
22 | // Custom initialization
23 | }
24 | return self;
25 | }
26 |
27 | - (void)viewDidLoad
28 | {
29 | [super viewDidLoad];
30 | // Do any additional setup after loading the view.
31 |
32 | _equalizer = [[FeEqualize alloc] initWithView:self.view title:@"LOADING"];
33 | [self.view addSubview:_equalizer];
34 |
35 | [_equalizer showWhileExecutingBlock:^{
36 | [self myTask];
37 | } completion:^{
38 | [self.navigationController popToRootViewControllerAnimated:YES];
39 | }];
40 | }
41 |
42 | - (void)didReceiveMemoryWarning
43 | {
44 | [super didReceiveMemoryWarning];
45 | // Dispose of any resources that can be recreated.
46 | }
47 |
48 | - (void)myTask
49 | {
50 | // Do something usefull in here instead of sleeping ...
51 | sleep(6);
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/FeSpinner/FeHandwriting.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeHandwriting.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/2/15.
6 | // Copyright (c) 2015 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeHandwriting : UIView
12 |
13 | // is running
14 | @property (assign, readonly, nonatomic) BOOL isShowing;
15 |
16 | -(instancetype) initWithView:(UIView *) view;
17 |
18 | -(void) show;
19 |
20 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
21 |
22 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
23 |
24 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
25 |
26 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
27 |
28 | -(void) dismiss;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/FeSpinner/FeHandwriting.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeHandwriting.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/2/15.
6 | // Copyright (c) 2015 fe. All rights reserved.
7 | //
8 |
9 | #import "FeHandwriting.h"
10 |
11 | @interface FeHandwriting ()
12 | {
13 |
14 | // Target, method, object and block
15 | id targetForExecuting;
16 | SEL methodForExecuting;
17 | id objectForExecuting;
18 | dispatch_block_t completionBlock;
19 | }
20 | // Container
21 | @property (weak, nonatomic) UIView *containerView;
22 |
23 | // Shape
24 | @property (strong, nonatomic) CAShapeLayer *loadingShapeLayer;
25 | @property (strong, nonatomic) CAShapeLayer *dotShapeLayer;
26 |
27 | // Animation
28 | @property (strong, nonatomic) CAKeyframeAnimation *loadingKeyframeAnimation;
29 | @property (strong, nonatomic) CAKeyframeAnimation *dotKeyframeAnimation;
30 |
31 | //////
32 | -(void) initCommon;
33 | -(void) initLoadingShapeLayer;
34 | -(void) initAnimation;
35 |
36 | @end
37 |
38 | @implementation FeHandwriting
39 |
40 | #pragma mark - Shapre
41 | +(UIBezierPath *) loadingShapeBezierPath
42 | {
43 | //// Color Declarations
44 |
45 | //// Bezier 2 Drawing
46 | UIBezierPath* bezier2Path = [UIBezierPath bezierPath];
47 | [bezier2Path moveToPoint: CGPointMake(12, 55.14)];
48 | [bezier2Path addCurveToPoint: CGPointMake(28.72, 13) controlPoint1: CGPointMake(43.08, 14.19) controlPoint2: CGPointMake(30.3, 13.07)];
49 | [bezier2Path addCurveToPoint: CGPointMake(24.38, 16.51) controlPoint1: CGPointMake(27.14, 12.94) controlPoint2: CGPointMake(25.83, 14.46)];
50 | [bezier2Path addCurveToPoint: CGPointMake(18.65, 46.28) controlPoint1: CGPointMake(17.66, 26.3) controlPoint2: CGPointMake(17.53, 43.17)];
51 | [bezier2Path addCurveToPoint: CGPointMake(26.35, 57.19) controlPoint1: CGPointMake(19.77, 49.39) controlPoint2: CGPointMake(21.68, 56.4)];
52 | [bezier2Path addCurveToPoint: CGPointMake(35.77, 52.3) controlPoint1: CGPointMake(29.97, 57.79) controlPoint2: CGPointMake(33.46, 55.27)];
53 | [bezier2Path addCurveToPoint: CGPointMake(42.48, 43.43) controlPoint1: CGPointMake(38.07, 49.39) controlPoint2: CGPointMake(39.72, 45.88)];
54 | [bezier2Path addCurveToPoint: CGPointMake(52.62, 42.31) controlPoint1: CGPointMake(45.25, 40.99) controlPoint2: CGPointMake(49.79, 39.86)];
55 | [bezier2Path addCurveToPoint: CGPointMake(42.81, 43.43) controlPoint1: CGPointMake(49.33, 42.04) controlPoint2: CGPointMake(45.84, 42.04)];
56 | [bezier2Path addCurveToPoint: CGPointMake(38.01, 51.44) controlPoint1: CGPointMake(39.78, 44.82) controlPoint2: CGPointMake(37.41, 48.13)];
57 | [bezier2Path addCurveToPoint: CGPointMake(47.36, 56.27) controlPoint1: CGPointMake(38.73, 55.34) controlPoint2: CGPointMake(43.6, 57.52)];
58 | [bezier2Path addCurveToPoint: CGPointMake(54.47, 47.34) controlPoint1: CGPointMake(51.11, 55.01) controlPoint2: CGPointMake(53.61, 51.24)];
59 | [bezier2Path addCurveToPoint: CGPointMake(53.35, 41.71) controlPoint1: CGPointMake(54.86, 45.35) controlPoint2: CGPointMake(54.8, 43.04)];
60 | [bezier2Path addCurveToPoint: CGPointMake(48.94, 43.23) controlPoint1: CGPointMake(51.9, 40.39) controlPoint2: CGPointMake(48.8, 41.25)];
61 | [bezier2Path addCurveToPoint: CGPointMake(51.83, 45.75) controlPoint1: CGPointMake(49.07, 44.62) controlPoint2: CGPointMake(50.52, 45.42)];
62 | [bezier2Path addCurveToPoint: CGPointMake(62.7, 43.96) controlPoint1: CGPointMake(55.45, 46.54) controlPoint2: CGPointMake(59.21, 45.29)];
63 | [bezier2Path addCurveToPoint: CGPointMake(73.56, 42.37) controlPoint1: CGPointMake(66.19, 42.71) controlPoint2: CGPointMake(69.94, 41.45)];
64 | [bezier2Path addCurveToPoint: CGPointMake(78.5, 50.84) controlPoint1: CGPointMake(77.18, 43.3) controlPoint2: CGPointMake(80.14, 47.47)];
65 | [bezier2Path addCurveToPoint: CGPointMake(68.95, 42.04) controlPoint1: CGPointMake(78.1, 46.08) controlPoint2: CGPointMake(73.69, 41.98)];
66 | [bezier2Path addCurveToPoint: CGPointMake(60.39, 51.5) controlPoint1: CGPointMake(64.21, 42.18) controlPoint2: CGPointMake(59.93, 46.74)];
67 | [bezier2Path addCurveToPoint: CGPointMake(70.66, 58.65) controlPoint1: CGPointMake(60.85, 56.27) controlPoint2: CGPointMake(66.05, 60.04)];
68 | [bezier2Path addCurveToPoint: CGPointMake(77.25, 46.01) controlPoint1: CGPointMake(75.6, 57.19) controlPoint2: CGPointMake(77.9, 51.17)];
69 | [bezier2Path addCurveToPoint: CGPointMake(77.77, 56.8) controlPoint1: CGPointMake(76.06, 48.13) controlPoint2: CGPointMake(76.26, 54.94)];
70 | [bezier2Path addCurveToPoint: CGPointMake(84.29, 58.65) controlPoint1: CGPointMake(79.29, 58.65) controlPoint2: CGPointMake(82.05, 59.44)];
71 | [bezier2Path addCurveToPoint: CGPointMake(90.55, 48.06) controlPoint1: CGPointMake(87.19, 57.66) controlPoint2: CGPointMake(88.83, 50.64)];
72 | [bezier2Path addCurveToPoint: CGPointMake(97.85, 43.3) controlPoint1: CGPointMake(92.26, 45.48) controlPoint2: CGPointMake(94.83, 42.84)];
73 | [bezier2Path addCurveToPoint: CGPointMake(103.84, 51.17) controlPoint1: CGPointMake(101.28, 43.83) controlPoint2: CGPointMake(102.86, 47.8)];
74 | [bezier2Path addCurveToPoint: CGPointMake(96.08, 43.5) controlPoint1: CGPointMake(104.04, 47.07) controlPoint2: CGPointMake(100.16, 43.23)];
75 | [bezier2Path addCurveToPoint: CGPointMake(89.36, 52.17) controlPoint1: CGPointMake(91.99, 43.76) controlPoint2: CGPointMake(88.64, 48.06)];
76 | [bezier2Path addCurveToPoint: CGPointMake(98.71, 57.92) controlPoint1: CGPointMake(90.08, 56.2) controlPoint2: CGPointMake(94.76, 59.11)];
77 | [bezier2Path addCurveToPoint: CGPointMake(106.15, 45.48) controlPoint1: CGPointMake(103.58, 56.47) controlPoint2: CGPointMake(105.49, 50.58)];
78 | [bezier2Path addCurveToPoint: CGPointMake(104.31, 16.57) controlPoint1: CGPointMake(107.4, 35.83) controlPoint2: CGPointMake(106.74, 25.97)];
79 | [bezier2Path addCurveToPoint: CGPointMake(103.71, 50.25) controlPoint1: CGPointMake(102.33, 27.69) controlPoint2: CGPointMake(102.13, 39.07)];
80 | [bezier2Path addCurveToPoint: CGPointMake(108.85, 60.04) controlPoint1: CGPointMake(104.24, 54.02) controlPoint2: CGPointMake(105.43, 58.38)];
81 | [bezier2Path addCurveToPoint: CGPointMake(119.38, 55.54) controlPoint1: CGPointMake(112.67, 61.89) controlPoint2: CGPointMake(117.34, 59.24)];
82 | [bezier2Path addCurveToPoint: CGPointMake(121.23, 43.1) controlPoint1: CGPointMake(121.36, 51.83) controlPoint2: CGPointMake(121.36, 47.34)];
83 | [bezier2Path addCurveToPoint: CGPointMake(120.3, 54.81) controlPoint1: CGPointMake(120.24, 46.94) controlPoint2: CGPointMake(119.19, 50.97)];
84 | [bezier2Path addCurveToPoint: CGPointMake(129.13, 60.7) controlPoint1: CGPointMake(121.36, 58.65) controlPoint2: CGPointMake(125.37, 61.96)];
85 | [bezier2Path addCurveToPoint: CGPointMake(134.2, 52.23) controlPoint1: CGPointMake(132.42, 59.64) controlPoint2: CGPointMake(134, 55.74)];
86 | [bezier2Path addCurveToPoint: CGPointMake(134.26, 41.78) controlPoint1: CGPointMake(134.39, 48.73) controlPoint2: CGPointMake(133.6, 45.22)];
87 | [bezier2Path addCurveToPoint: CGPointMake(135.91, 62.09) controlPoint1: CGPointMake(133.08, 48.53) controlPoint2: CGPointMake(133.67, 55.61)];
88 | [bezier2Path addCurveToPoint: CGPointMake(136.96, 47.93) controlPoint1: CGPointMake(136.24, 57.39) controlPoint2: CGPointMake(136.63, 52.63)];
89 | [bezier2Path addCurveToPoint: CGPointMake(138.54, 43.3) controlPoint1: CGPointMake(137.09, 46.28) controlPoint2: CGPointMake(137.29, 44.36)];
90 | [bezier2Path addCurveToPoint: CGPointMake(145.65, 46.74) controlPoint1: CGPointMake(140.91, 41.25) controlPoint2: CGPointMake(144.8, 43.7)];
91 | [bezier2Path addCurveToPoint: CGPointMake(145.65, 56.13) controlPoint1: CGPointMake(146.51, 49.78) controlPoint2: CGPointMake(145.59, 53.03)];
92 | [bezier2Path addCurveToPoint: CGPointMake(149.41, 62.55) controlPoint1: CGPointMake(145.72, 58.78) controlPoint2: CGPointMake(146.84, 61.89)];
93 | [bezier2Path addCurveToPoint: CGPointMake(155.46, 58.98) controlPoint1: CGPointMake(151.84, 63.21) controlPoint2: CGPointMake(154.34, 61.23)];
94 | [bezier2Path addCurveToPoint: CGPointMake(157.83, 51.7) controlPoint1: CGPointMake(156.65, 56.73) controlPoint2: CGPointMake(156.91, 54.08)];
95 | [bezier2Path addCurveToPoint: CGPointMake(164.68, 44.82) controlPoint1: CGPointMake(159.08, 48.59) controlPoint2: CGPointMake(161.52, 45.88)];
96 | [bezier2Path addCurveToPoint: CGPointMake(173.77, 47.27) controlPoint1: CGPointMake(167.84, 43.76) controlPoint2: CGPointMake(171.66, 44.62)];
97 | [bezier2Path addCurveToPoint: CGPointMake(173.04, 56.27) controlPoint1: CGPointMake(175.87, 49.92) controlPoint2: CGPointMake(175.67, 54.15)];
98 | [bezier2Path addCurveToPoint: CGPointMake(173.11, 44.69) controlPoint1: CGPointMake(175.94, 53.22) controlPoint2: CGPointMake(175.94, 47.87)];
99 | [bezier2Path addCurveToPoint: CGPointMake(161.59, 43.43) controlPoint1: CGPointMake(170.28, 41.51) controlPoint2: CGPointMake(165.07, 41.05)];
100 | [bezier2Path addCurveToPoint: CGPointMake(158.43, 54.75) controlPoint1: CGPointMake(158.1, 45.81) controlPoint2: CGPointMake(156.78, 50.84)];
101 | [bezier2Path addCurveToPoint: CGPointMake(171.4, 59.57) controlPoint1: CGPointMake(160.47, 59.51) controlPoint2: CGPointMake(166.79, 61.89)];
102 | [bezier2Path addCurveToPoint: CGPointMake(175.48, 46.28) controlPoint1: CGPointMake(176, 57.26) controlPoint2: CGPointMake(178.05, 50.78)];
103 | [bezier2Path addCurveToPoint: CGPointMake(177.65, 85.97) controlPoint1: CGPointMake(176.2, 59.51) controlPoint2: CGPointMake(176.93, 72.74)];
104 | [bezier2Path addCurveToPoint: CGPointMake(175.48, 92.59) controlPoint1: CGPointMake(177.78, 88.42) controlPoint2: CGPointMake(177.65, 91.39)];
105 | [bezier2Path addCurveToPoint: CGPointMake(168.43, 88.29) controlPoint1: CGPointMake(172.78, 94.11) controlPoint2: CGPointMake(169.62, 91.2)];
106 | [bezier2Path addCurveToPoint: CGPointMake(173.24, 66.52) controlPoint1: CGPointMake(165.4, 81.01) controlPoint2: CGPointMake(167.38, 71.88)];
107 | [bezier2Path addCurveToPoint: CGPointMake(183.64, 59.31) controlPoint1: CGPointMake(176.33, 63.68) controlPoint2: CGPointMake(180.35, 61.96)];
108 | [bezier2Path addCurveToPoint: CGPointMake(188.84, 48.46) controlPoint1: CGPointMake(186.93, 56.66) controlPoint2: CGPointMake(189.7, 52.63)];
109 |
110 | return bezier2Path;
111 | }
112 | +(UIBezierPath *) dotShapeBezierPath
113 | {
114 | UIColor* color0 = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 1];
115 |
116 | //// Bezier 4 Drawing
117 | UIBezierPath* bezier4Path = [UIBezierPath bezierPath];
118 |
119 | [bezier4Path moveToPoint: CGPointMake(124.76, 27.14)];
120 | [bezier4Path addCurveToPoint: CGPointMake(118.51, 27.69) controlPoint1: CGPointMake(123.13, 25.41) controlPoint2: CGPointMake(119.79, 25.69)];
121 | [bezier4Path addCurveToPoint: CGPointMake(120.85, 33.33) controlPoint1: CGPointMake(117.23, 29.68) controlPoint2: CGPointMake(118.51, 32.71)];
122 | [bezier4Path addCurveToPoint: CGPointMake(125.26, 31.68) controlPoint1: CGPointMake(122.49, 33.74) controlPoint2: CGPointMake(124.34, 33.06)];
123 | [bezier4Path addCurveToPoint: CGPointMake(124.76, 27.14) controlPoint1: CGPointMake(126.18, 30.3) controlPoint2: CGPointMake(125.9, 28.37)];
124 |
125 |
126 |
127 | return bezier4Path;
128 | }
129 |
130 | #pragma marl - Init
131 | -(instancetype) initWithView:(UIView *)view
132 | {
133 | self = [super init];
134 | if (self)
135 | {
136 | self.frame = CGRectMake(0, 0, 200, 100);
137 | self.center = CGPointMake(view.bounds.size.width / 2, view.bounds.size.height /2);
138 |
139 | _containerView = view;
140 |
141 | [self initCommon];
142 |
143 | [self initLoadingShapeLayer];
144 |
145 | [self initAnimation];
146 | }
147 | return self;
148 | }
149 | -(void) initCommon
150 | {
151 | _isShowing = NO;
152 | self.backgroundColor = [UIColor clearColor];
153 | }
154 | -(void) initLoadingShapeLayer
155 | {
156 | // Loading Shape
157 | UIBezierPath *loadingBezierpath = [FeHandwriting loadingShapeBezierPath];
158 | _loadingShapeLayer = [CAShapeLayer layer];
159 | _loadingShapeLayer.frame = self.bounds;
160 | _loadingShapeLayer.path = loadingBezierpath.CGPath;
161 | _loadingShapeLayer.strokeEnd = 0;
162 | _loadingShapeLayer.strokeColor = [UIColor blackColor].CGColor;
163 | _loadingShapeLayer.fillColor = [UIColor clearColor].CGColor;
164 | _loadingShapeLayer.lineWidth = 2.5f;
165 | _loadingShapeLayer.lineCap = kCALineCapRound;
166 | _loadingShapeLayer.lineJoin = kCALineJoinRound;
167 |
168 |
169 | // Dot Shape
170 | UIBezierPath *dotBezierPath = [FeHandwriting dotShapeBezierPath];
171 | _dotShapeLayer = [CAShapeLayer layer];
172 | _dotShapeLayer.frame = self.bounds;
173 | _dotShapeLayer.path = dotBezierPath.CGPath;
174 | _dotShapeLayer.strokeEnd = 0;
175 | _dotShapeLayer.strokeColor = [UIColor blackColor].CGColor;
176 | _dotShapeLayer.fillColor = [UIColor clearColor].CGColor;
177 | _dotShapeLayer.lineWidth = 2.5f;
178 | _dotShapeLayer.lineCap = kCALineCapRound;
179 | _dotShapeLayer.lineJoin = kCALineJoinRound;
180 |
181 | // Add
182 | [self.layer addSublayer:_loadingShapeLayer];
183 | [self.layer addSublayer:_dotShapeLayer];
184 | }
185 | -(void) initAnimation
186 | {
187 | // Loading
188 | _loadingKeyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
189 | _loadingKeyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
190 | _loadingKeyframeAnimation.keyTimes = @[@0.0f, @0.6f, @1.0f];
191 | _loadingKeyframeAnimation.values = @[@0.0f, @1.0f, @1.0f];
192 | _loadingKeyframeAnimation.duration = 4.0f;
193 | _loadingKeyframeAnimation.repeatCount = CGFLOAT_MAX;
194 |
195 | // Dot
196 | _dotKeyframeAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
197 | _dotKeyframeAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
198 | _dotKeyframeAnimation.keyTimes = @[@0.0f, @0.6f, @0.65f, @1.0f];
199 | _dotKeyframeAnimation.values = @[@0.0f, @0.0f, @1.0f, @1.0f];
200 | _dotKeyframeAnimation.duration = 4.0f;
201 | _dotKeyframeAnimation.repeatCount = CGFLOAT_MAX;
202 | }
203 |
204 | #pragma mark - ACtion
205 | -(void) show
206 | {
207 | if (_isShowing)
208 | {
209 | return;
210 | }
211 |
212 | _isShowing = YES;
213 |
214 | [_loadingShapeLayer addAnimation:_loadingKeyframeAnimation forKey:@"stoke"];
215 | [_dotShapeLayer addAnimation:_dotKeyframeAnimation forKey:@"stoke"];
216 | }
217 | -(void) dismiss
218 | {
219 | if (!_isShowing)
220 | return;
221 |
222 | _isShowing = NO;
223 |
224 | }
225 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
226 | {
227 | [self showWhileExecutingBlock:block completion:nil];
228 | }
229 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
230 | {
231 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
232 |
233 | }
234 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
235 | {
236 | // Check block != nil
237 | if (block != nil)
238 | {
239 | [self show];
240 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
241 | {
242 | block();
243 |
244 | // Update UI
245 | dispatch_async(dispatch_get_main_queue(), ^{
246 | completion();
247 | [self dismiss];
248 | });
249 | });
250 | }
251 | }
252 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
253 | {
254 | // Check Selector is responded
255 | if ([target respondsToSelector:selector])
256 | {
257 | methodForExecuting = selector;
258 | targetForExecuting = target;
259 | objectForExecuting = object;
260 | completionBlock = completion;
261 |
262 | [self show];
263 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
264 | }
265 | }
266 | #pragma mark Helper method
267 | -(void) executingMethod
268 | {
269 | @autoreleasepool {
270 | #pragma clang diagnostic push
271 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
272 | // Start executing the requested task
273 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
274 | #pragma clang diagnostic pop
275 | // Task completed, update view in main thread (note: view operations should
276 | // be done only in the main thread)
277 | dispatch_async(dispatch_get_main_queue(), ^{
278 | completionBlock();
279 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
280 | });
281 |
282 | }
283 | }
284 | -(void) cleanUp
285 | {
286 | NSLog(@"Clean up");
287 | if (objectForExecuting)
288 | objectForExecuting = nil;
289 | if (methodForExecuting)
290 | methodForExecuting = nil;
291 | if (targetForExecuting)
292 | targetForExecuting = nil;
293 | if (completionBlock)
294 | completionBlock = nil;
295 | [self dismiss];
296 | }
297 | @end
298 |
--------------------------------------------------------------------------------
/FeSpinner/FeHandwritingViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeHandwritingViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/2/15.
6 | // Copyright (c) 2015 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeHandwritingViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeHandwritingViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeHandwritingViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/2/15.
6 | // Copyright (c) 2015 fe. All rights reserved.
7 | //
8 |
9 | #import "FeHandwritingViewController.h"
10 | #import "FeHandwriting.h"
11 | #import "UIColor+flat.h"
12 |
13 | @interface FeHandwritingViewController ()
14 | @property (strong, nonatomic) FeHandwriting *handwritingLoader;
15 |
16 | @end
17 |
18 | @implementation FeHandwritingViewController
19 |
20 | - (void)viewDidLoad
21 | {
22 | [super viewDidLoad];
23 | // Do any additional setup after loading the view.
24 |
25 | self.view.backgroundColor = [UIColor colorWithHexCode:@"#ffe200"];
26 |
27 | _handwritingLoader = [[FeHandwriting alloc] initWithView:self.view];
28 | [self.view addSubview:_handwritingLoader];
29 |
30 | [_handwritingLoader showWhileExecutingBlock:^{
31 | [self myTask];
32 | } completion:^{
33 | [self.navigationController popToRootViewControllerAnimated:YES];
34 | }];
35 | }
36 | - (void)myTask
37 | {
38 | // Do something usefull in here instead of sleeping ...
39 | sleep(12);
40 | }
41 |
42 | @end
43 |
--------------------------------------------------------------------------------
/FeSpinner/FeHourGlass.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeCandyLoader.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeHourGlass : UIView
12 |
13 | // is running
14 | @property (assign, readonly, nonatomic) BOOL isShowing;
15 |
16 | -(instancetype) initWithView:(UIView *) view;
17 |
18 | -(void) show;
19 |
20 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
21 |
22 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
23 |
24 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
25 |
26 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
27 |
28 | -(void) dismiss;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/FeSpinner/FeHourGlass.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeCandyLoader.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeHourGlass.h"
10 | #import "UIColor+flat.h"
11 | #import
12 |
13 | #define kFe_HourGlass_Length 30.0f
14 | #define kFe_HourGlass_Duration 3.5f
15 |
16 | @interface FeHourGlass ()
17 | {
18 | CGFloat width;
19 | CGFloat height;
20 |
21 | // Target, method, object and block
22 | id targetForExecuting;
23 | SEL methodForExecuting;
24 | id objectForExecuting;
25 | dispatch_block_t completionBlock;
26 | }
27 | // Top
28 | @property (strong, nonatomic) CAShapeLayer *topLayer;
29 |
30 | // Bottom
31 | @property (strong, nonatomic) CAShapeLayer *bottomLayer;
32 |
33 | // Dash line
34 | @property (strong, nonatomic) CAShapeLayer *lineLayer;
35 |
36 | // container Layer
37 | @property (strong, nonatomic) CALayer *containerLayer;
38 |
39 | // Container view
40 | @property (weak, nonatomic) UIView *containerView;
41 |
42 | // Animaiton
43 | @property (strong, nonatomic) CAKeyframeAnimation *topAnimation;
44 |
45 | @property (strong, nonatomic) CAKeyframeAnimation *bottomAnimation;
46 |
47 | @property (strong, nonatomic) CAKeyframeAnimation *lineAnimation;
48 |
49 | @property(strong, nonatomic) CAKeyframeAnimation *containerAnimation;
50 |
51 | ///////////
52 | // Init
53 | -(void) initCommon;
54 | -(void) initContainer;
55 | -(void) initTop;
56 | -(void) initBottom;
57 | -(void) initLine;
58 | -(void) initAnimation;
59 | @end
60 |
61 | @implementation FeHourGlass
62 |
63 | -(instancetype) initWithView:(UIView *)view
64 | {
65 | self = [super init];
66 | if (self)
67 | {
68 | _containerView = view;
69 |
70 | [self initCommon];
71 |
72 | [self initContainer];
73 |
74 | [self initTop];
75 |
76 | [self initBottom];
77 |
78 | [self initLine];
79 |
80 | [self initAnimation];
81 | }
82 | return self;
83 | }
84 | -(void) initCommon
85 | {
86 | _isShowing = NO;
87 |
88 | self.frame = CGRectMake(0, 0, _containerView.bounds.size.width, _containerView.bounds.size.height);
89 | self.backgroundColor = [UIColor colorWithHexCode:@"#DB7769"];
90 |
91 | width = sqrtf(kFe_HourGlass_Length * kFe_HourGlass_Length + kFe_HourGlass_Length * kFe_HourGlass_Length);
92 | height = sqrtf((kFe_HourGlass_Length * kFe_HourGlass_Length) - ((width / 2.0f) * (width / 2.0f)));
93 | }
94 | -(void) initContainer
95 | {
96 | _containerLayer = [CALayer layer];
97 | _containerLayer.backgroundColor = [UIColor clearColor].CGColor;
98 | _containerLayer.frame = CGRectMake(0, 0, width, height * 2);
99 | _containerLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
100 | _containerLayer.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
101 |
102 | [self.layer addSublayer:_containerLayer];
103 | }
104 | -(void) initTop
105 | {
106 | // BezierPath
107 | UIBezierPath *path = [UIBezierPath bezierPath];
108 | [path moveToPoint:CGPointMake(0, 0)];
109 | [path addLineToPoint:CGPointMake(width, 0)];
110 | [path addLineToPoint:CGPointMake(width / 2.0f, height)];
111 | [path addLineToPoint:CGPointMake(0, 0)];
112 |
113 | [path closePath];
114 |
115 | // Top Layer
116 | _topLayer = [CAShapeLayer layer];
117 | _topLayer.frame = CGRectMake(0, 0, width, height);
118 | _topLayer.path = path.CGPath;
119 | _topLayer.fillColor = [UIColor whiteColor].CGColor;
120 | _topLayer.strokeColor = [UIColor whiteColor].CGColor;
121 | _topLayer.lineWidth = 0.0f;
122 | _topLayer.anchorPoint = CGPointMake(0.5f, 1);
123 | _topLayer.position = CGPointMake(width / 2.0f, height);
124 |
125 | [_containerLayer addSublayer:_topLayer];
126 | }
127 | -(void) initBottom
128 | {
129 | // BezierPath
130 | UIBezierPath *path = [UIBezierPath bezierPath];
131 | [path moveToPoint:CGPointMake(width / 2, 0)];
132 | [path addLineToPoint:CGPointMake(width, height)];
133 | [path addLineToPoint:CGPointMake(0, height )];
134 | [path addLineToPoint:CGPointMake(width / 2, 0)];
135 |
136 | [path closePath];
137 |
138 | // Top Layer
139 | _bottomLayer = [CAShapeLayer layer];
140 | _bottomLayer.frame = CGRectMake(0, height, width, height);
141 | _bottomLayer.path = path.CGPath;
142 | _bottomLayer.fillColor = [UIColor whiteColor].CGColor;
143 | _bottomLayer.strokeColor = [UIColor whiteColor].CGColor;
144 | _bottomLayer.lineWidth = 0.0f;
145 | _bottomLayer.anchorPoint = CGPointMake(0.5f, 1.0f);
146 | _bottomLayer.position = CGPointMake(width / 2.0f, height * 2.0f);
147 | _bottomLayer.transform = CATransform3DMakeScale(0, 0, 0);
148 |
149 | [_containerLayer addSublayer:_bottomLayer];
150 | }
151 | -(void) initLine
152 | {
153 | // BezierPath
154 | UIBezierPath *path = [UIBezierPath bezierPath];
155 | [path moveToPoint:CGPointMake(width / 2, 0)];
156 | [path addLineToPoint:CGPointMake(width / 2, height)];
157 |
158 | // Line Layer
159 | _lineLayer = [CAShapeLayer layer];
160 | _lineLayer.frame = CGRectMake(0, height, width, height);
161 | _lineLayer.strokeColor = [UIColor whiteColor].CGColor;
162 | _lineLayer.lineWidth = 1.0;
163 | _lineLayer.lineJoin = kCALineJoinMiter;
164 | _lineLayer.lineDashPattern = [NSArray arrayWithObjects:[NSNumber numberWithInt:1],[NSNumber numberWithInt:1], nil];
165 | _lineLayer.lineDashPhase = 3.0f;
166 | _lineLayer.path = path.CGPath;
167 | _lineLayer.strokeEnd = 0.0f;
168 |
169 | [_containerLayer addSublayer:_lineLayer];
170 | }
171 | -(void) initAnimation
172 | {
173 | if (YES) // Top Animation
174 | {
175 | _topAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
176 | _topAnimation.duration = kFe_HourGlass_Duration;
177 | _topAnimation.repeatCount = HUGE_VAL;
178 | _topAnimation.keyTimes = @[@0.0f, @0.9f, @1.0f];
179 | _topAnimation.values = @[@1.0f, @0.0f, @0.0f];
180 | }
181 | if (YES) // Bottom Animation
182 | {
183 | _bottomAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.scale"];
184 | _bottomAnimation.duration = kFe_HourGlass_Duration;
185 | _bottomAnimation.repeatCount = HUGE_VAL;
186 | _bottomAnimation.keyTimes = @[@0.1f, @0.9f, @1.0f];
187 | _bottomAnimation.values = @[@0.0f, @1.0f, @1.0f];
188 | }
189 | if (YES) // Bottom Animation
190 | {
191 | _lineAnimation = [CAKeyframeAnimation animationWithKeyPath:@"strokeEnd"];
192 | _lineAnimation.duration = kFe_HourGlass_Duration;
193 | _lineAnimation.repeatCount = HUGE_VAL;
194 | _lineAnimation.keyTimes = @[@0.0f, @0.1f, @0.9f, @1.0f];
195 | _lineAnimation.values = @[@0.0f, @1.0f, @1.0f, @1.0f];
196 | }
197 | if (YES) // Container Animation
198 | {
199 | _containerAnimation = [CAKeyframeAnimation animationWithKeyPath:@"transform.rotation.z"];
200 | _containerAnimation.timingFunction = [CAMediaTimingFunction functionWithControlPoints:0.2f :1 :0.8f :0.0f];
201 | _containerAnimation.duration = kFe_HourGlass_Duration;
202 | _containerAnimation.repeatCount = HUGE_VAL;
203 | _containerAnimation.keyTimes = @[@0.8f, @1.0f];
204 | _containerAnimation.values = @[[NSNumber numberWithFloat:0.0f], [NSNumber numberWithFloat:M_PI]];
205 | //_containerAnimation.calculationMode = kCAAnimationCubic;
206 | }
207 | }
208 | #pragma mark - Action
209 | -(void) show
210 | {
211 | if (_isShowing)
212 | return;
213 |
214 | _isShowing = YES;
215 |
216 | [_topLayer addAnimation:_topAnimation forKey:@"TopAnimatin"];
217 | [_bottomLayer addAnimation:_bottomAnimation forKey:@"BottomAnimation"];
218 | [_lineLayer addAnimation:_lineAnimation forKey:@"LineAnimation"];
219 | [_containerLayer addAnimation:_containerAnimation forKey:@"ContainerAnimation"];
220 | }
221 | -(void) dismiss
222 | {
223 | if (!_isShowing)
224 | return;
225 |
226 | _isShowing = NO;
227 |
228 | }
229 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
230 | {
231 | [self showWhileExecutingBlock:block completion:nil];
232 | }
233 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
234 | {
235 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
236 |
237 | }
238 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
239 | {
240 | // Check block != nil
241 | if (block != nil)
242 | {
243 | [self show];
244 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
245 | {
246 | block();
247 |
248 | // Update UI
249 | dispatch_async(dispatch_get_main_queue(), ^{
250 | completion();
251 | [self dismiss];
252 | });
253 | });
254 | }
255 | }
256 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
257 | {
258 | // Check Selector is responded
259 | if ([target respondsToSelector:selector])
260 | {
261 | methodForExecuting = selector;
262 | targetForExecuting = target;
263 | objectForExecuting = object;
264 | completionBlock = completion;
265 |
266 | [self show];
267 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
268 | }
269 | }
270 | #pragma mark Helper method
271 | -(void) executingMethod
272 | {
273 | @autoreleasepool {
274 | #pragma clang diagnostic push
275 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
276 | // Start executing the requested task
277 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
278 | #pragma clang diagnostic pop
279 | // Task completed, update view in main thread (note: view operations should
280 | // be done only in the main thread)
281 | dispatch_async(dispatch_get_main_queue(), ^{
282 | completionBlock();
283 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
284 | });
285 |
286 | }
287 | }
288 | -(void) cleanUp
289 | {
290 | NSLog(@"Clean up");
291 | if (objectForExecuting)
292 | objectForExecuting = nil;
293 | if (methodForExecuting)
294 | methodForExecuting = nil;
295 | if (targetForExecuting)
296 | targetForExecuting = nil;
297 | if (completionBlock)
298 | completionBlock = nil;
299 | [self dismiss];
300 | }
301 |
302 | @end
303 |
--------------------------------------------------------------------------------
/FeSpinner/FeHourGlassViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeHourGlassViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeHourGlassViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeHourGlassViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeHourGlassViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeHourGlassViewController.h"
10 | #import "FeHourGlass.h"
11 |
12 | @interface FeHourGlassViewController ()
13 | @property (strong, nonatomic) FeHourGlass *hourGlass;
14 |
15 | @end
16 |
17 | @implementation FeHourGlassViewController
18 |
19 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
20 | {
21 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
22 | if (self) {
23 | // Custom initialization
24 | }
25 | return self;
26 | }
27 |
28 | - (void)viewDidLoad
29 | {
30 | [super viewDidLoad];
31 | // Do any additional setup after loading the view.
32 |
33 | _hourGlass = [[FeHourGlass alloc] initWithView:self.view];
34 | [self.view addSubview:_hourGlass];
35 |
36 | [_hourGlass showWhileExecutingBlock:^{
37 | [self myTask];
38 | } completion:^{
39 | [self.navigationController popToRootViewControllerAnimated:YES];
40 | }];
41 | }
42 | - (void)myTask
43 | {
44 | // Do something usefull in here instead of sleeping ...
45 | sleep(12);
46 | }
47 | @end
48 |
--------------------------------------------------------------------------------
/FeSpinner/FeLoadingBoxViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeLoadingBoxViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/19/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeLoadingBoxViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeLoadingBoxViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeLoadingBoxViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/19/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeLoadingBoxViewController.h"
10 | #import "FeLoadingIcon.h"
11 |
12 | @interface FeLoadingBoxViewController ()
13 | @property (strong, nonatomic) FeLoadingIcon *loadingIcon;
14 | @end
15 |
16 | @implementation FeLoadingBoxViewController
17 |
18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
19 | {
20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
21 | if (self) {
22 | // Custom initialization
23 | }
24 | return self;
25 | }
26 |
27 | - (void)viewDidLoad
28 | {
29 | [super viewDidLoad];
30 | // Do any additional setup after loading the view.
31 |
32 | _loadingIcon = [[FeLoadingIcon alloc] initWithView:self.navigationController.view blur:NO backgroundColors:nil];
33 | [self.view addSubview:_loadingIcon];
34 |
35 | // Show
36 | [_loadingIcon showWhileExecutingBlock:^{
37 | [self myTask];
38 | } completion:^{
39 | [self.navigationController popToRootViewControllerAnimated:YES];
40 | }];
41 | }
42 |
43 | - (void)didReceiveMemoryWarning
44 | {
45 | [super didReceiveMemoryWarning];
46 | // Dispose of any resources that can be recreated.
47 | }
48 |
49 | - (void)myTask
50 | {
51 | // Do something usefull in here instead of sleeping ...
52 | sleep(6);
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/FeSpinner/FeLoadingIcon.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeLoadingIcon.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/19/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 | @protocol FeLoadingIconDelegate;
11 |
12 | @interface FeLoadingIcon : UIView
13 | // Delegate
14 | @property (weak, nonatomic) id delegate;
15 |
16 | // Determine FeloadingIcon is animating;
17 | @property (assign, nonatomic, readonly) BOOL isAnimating;
18 |
19 | // Determine background is Blur;
20 | @property (assign, nonatomic, readonly) BOOL isBlur;
21 |
22 | -(id) initWithView:(UIView *) view blur:(BOOL) blur backgroundColors:(NSArray *) arrColor;
23 |
24 | -(void) show;
25 |
26 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
27 |
28 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
29 |
30 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
31 |
32 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
33 |
34 | -(void) dismiss;
35 | @end
36 |
37 | @protocol FeLoadingIconDelegate
38 | @optional
39 | -(void) FeLoadingIconWillShow:(FeLoadingIcon *) sender;
40 | -(void) FeLoadingIconDidShow:(FeLoadingIcon *) sender;
41 | -(void) FeLoadingIconDidDismiss:(FeLoadingIcon *)sender;
42 |
43 | @end
--------------------------------------------------------------------------------
/FeSpinner/FeLoadingIcon.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeLoadingIcon.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/19/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeLoadingIcon.h"
10 | #import "FeLoadingIconBox.h"
11 | #import "UIColor+flat.h"
12 | #import "FXBlurView.h"
13 |
14 | #define kDurationPerColor 2.0f
15 |
16 | @interface FeLoadingIcon ()
17 | {
18 | id targetForExecuting;
19 | SEL methodForExecuting;
20 | id objectForExecuting;
21 | dispatch_block_t completionBlock;
22 | }
23 | @property (weak, nonatomic) UIView *containerView;
24 | @property (strong, nonatomic) UIView *bigBoxView;
25 |
26 | @property (strong, nonatomic) UIView *backgroundStatic;
27 | @property (strong, nonatomic) FXBlurView *backgroundBlur;
28 |
29 | @property (strong, nonatomic) NSMutableArray *arrBox;
30 | @property (strong, nonatomic) NSArray *arrColor;
31 | @property (strong, nonatomic) NSTimer *timer;
32 |
33 | // ***********
34 | -(void) commonInit;
35 | -(void) initBackgroundWithBlur:(BOOL) blur;
36 | -(void) initBox;
37 | -(void) initColor;
38 | -(void) animteColor;
39 | -(void) cleanUp;
40 | -(void) executeSelector;
41 | @end
42 | @implementation FeLoadingIcon
43 |
44 | - (id)initWithFrame:(CGRect)frame
45 | {
46 | self = [super initWithFrame:frame];
47 | if (self) {
48 | // Initialization code
49 | }
50 | return self;
51 | }
52 |
53 | -(id) initWithView:(UIView *)view blur:(BOOL)blur backgroundColors:(NSArray *)arrColor
54 | {
55 | CGRect frame = CGRectMake(0, 0, view.bounds.size.width, view.bounds.size.height);
56 | self = [super initWithFrame:frame];
57 | if (self)
58 | {
59 | _containerView = view;
60 | _isAnimating = NO;
61 |
62 | [self commonInit];
63 | [self initBackgroundWithBlur:blur];
64 |
65 | // init color as default
66 | if (!arrColor)
67 | [self initColor];
68 | else
69 | _arrColor = arrColor;
70 |
71 | // init small Box
72 | [self initBox];
73 | }
74 | return self;
75 | }
76 | -(void) commonInit
77 | {
78 | self.hidden = YES;
79 | self.alpha = 0;
80 |
81 |
82 | }
83 | -(void) initBackgroundWithBlur:(BOOL)blur
84 | {
85 | _isBlur = blur;
86 |
87 | if (blur)
88 | {
89 | _backgroundBlur = [[FXBlurView alloc] initWithFrame:_containerView.bounds];
90 | _backgroundBlur.blurRadius = 40;
91 | _backgroundBlur.tintColor = [UIColor colorWithHexCode:@"#32ce55"];
92 | _backgroundBlur.dynamic = NO;
93 | [_backgroundBlur.layer displayIfNeeded];
94 |
95 | // Hide background
96 | _backgroundBlur.hidden = YES;
97 | }
98 | else
99 | {
100 | _backgroundStatic = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
101 | _backgroundStatic.userInteractionEnabled = NO;
102 | _backgroundStatic.backgroundColor = [UIColor flatCarrotColor];
103 | }
104 | }
105 | -(void) initBox
106 | {
107 | // init Big Box
108 | _bigBoxView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
109 | _bigBoxView.center = self.center;
110 | _bigBoxView.layer.cornerRadius = 40.0f;
111 | _bigBoxView.clipsToBounds = YES;
112 | _bigBoxView.alpha = 0;
113 |
114 | [self addSubview:_bigBoxView];
115 |
116 | // init small box
117 | _arrBox = [[NSMutableArray alloc ]initWithCapacity:16];
118 | for (NSInteger i = 1; i <= 16; i++)
119 | {
120 | FeLoadingIconBox *box = [[FeLoadingIconBox alloc] initBoxAtIndex:i];
121 | [_bigBoxView addSubview:box];
122 |
123 | // add small to big box
124 | [_arrBox addObject:box];
125 | }
126 | }
127 | -(void) initColor
128 | {
129 | _arrColor = @[[UIColor flatWisteriaColor],[UIColor flatSunFlowerColor],[UIColor flatPumpkinColor],[UIColor flatGreenSeaColor],[UIColor flatMidNightColor],[UIColor flatWisteriaColor]];
130 | }
131 | #pragma mark Action
132 | -(void) show
133 | {
134 | if (_isAnimating)
135 | return;
136 |
137 | self.hidden = NO;
138 | self.alpha = 0;
139 |
140 | // Add background
141 | if (_isBlur)
142 | {
143 | _backgroundBlur.alpha = 0;
144 | _backgroundBlur.hidden = NO;
145 | [_containerView insertSubview:_backgroundBlur belowSubview:self];
146 | }
147 | else
148 | {
149 | [self insertSubview:_backgroundStatic atIndex:0];
150 | }
151 | // call delegate
152 | if ([_delegate respondsToSelector:@selector(FeLoadingIconWillShow:)])
153 | {
154 | [_delegate FeLoadingIconWillShow:self];
155 | }
156 |
157 | // animatin
158 | [UIView animateWithDuration:0.5f delay:0 options:UIViewAnimationOptionCurveEaseIn
159 | animations:^{
160 | self.alpha = 1;
161 |
162 | if (_isBlur)
163 | {
164 | _backgroundBlur.alpha = 1;
165 | }
166 | } completion:^(BOOL finished) {
167 |
168 | _isAnimating = YES;
169 |
170 | // Call delgate method
171 | if ([_delegate respondsToSelector:@selector(FeLoadingIconDidShow:)])
172 | {
173 | [_delegate FeLoadingIconDidShow:self];
174 | }
175 |
176 | // animate color
177 | [self animteColor];
178 |
179 | // animate Big Box
180 | [UIView animateWithDuration:[self delayAtIndex:0] animations:^{
181 | _bigBoxView.alpha = 1;
182 | } completion:^(BOOL finished) {
183 |
184 | }];
185 |
186 | // animate small Box
187 | for (NSInteger i = 1; i <= 16; i++)
188 | {
189 | FeLoadingIconBox *box = _arrBox[i-1];
190 | CGFloat delay = [self delayAtIndex:i];
191 |
192 | [box performSelector:@selector(playAnimate) withObject:nil afterDelay:delay];
193 | }
194 |
195 |
196 |
197 | }];
198 |
199 |
200 | }
201 | -(void) animteColor
202 | {
203 | // Sum duration of each box
204 | CGFloat allDuration = kDurationPerColor * _arrColor.count;
205 |
206 | [UIView animateKeyframesWithDuration:allDuration delay:0 options:UIViewKeyframeAnimationOptionAutoreverse | UIViewKeyframeAnimationOptionRepeat | UIViewKeyframeAnimationOptionCalculationModeLinear
207 | animations:^{
208 | for (NSInteger i = 0; i < _arrColor.count; i++)
209 | {
210 | CGFloat percentStartTime = (kDurationPerColor * i) / allDuration;
211 | CGFloat percentDuration = kDurationPerColor / allDuration;
212 |
213 | // Add keyframe
214 | [UIView addKeyframeWithRelativeStartTime:percentStartTime relativeDuration:percentDuration animations:^{
215 | _bigBoxView.backgroundColor = _arrColor[i];
216 | }];
217 | }
218 |
219 |
220 | } completion:^(BOOL finished) {
221 |
222 | }];
223 | }
224 | -(CGFloat) delayAtIndex:(NSInteger) index
225 | {
226 | CGFloat delay = 0;
227 | switch (index) {
228 | case 1:
229 | {
230 | delay = 0.55f;
231 | break;
232 | }
233 | case 2:
234 | {
235 | delay = 0.5f;
236 | break;
237 | }
238 | case 3:
239 | {
240 | delay = 0.45f;
241 | break;
242 | }
243 | case 4:
244 | {
245 | delay = 0.4f;
246 | break;
247 | }
248 | case 8:
249 | {
250 | delay = 0.35f;
251 | break;
252 | }
253 | case 12:
254 | {
255 | delay = 0.3f;
256 | break;
257 | }
258 | case 16:
259 | {
260 | delay = 0.25f;
261 | break;
262 | }
263 | case 15:
264 | {
265 | delay = 0.2f;
266 | break;
267 | }
268 | case 14:
269 | {
270 | delay = 0.15f;
271 | break;
272 | }
273 | case 13:
274 | {
275 | delay = 0.1f;
276 | break;
277 | }
278 | case 9:
279 | {
280 | delay = 0.5f;
281 | break;
282 | }
283 | case 5:
284 | {
285 | delay = 0;
286 | break;
287 | }
288 | case 6:
289 | {
290 | delay = 0;
291 | break;
292 | }
293 | case 7:
294 | {
295 | delay = 0.18f;
296 | break;
297 | }
298 | case 10:
299 | {
300 | delay = 0.36f;
301 | break;
302 | }
303 | case 11:
304 | {
305 | delay = 0.55f;
306 | break;
307 | }
308 | default:
309 | break;
310 | }
311 | return delay;
312 | }
313 | -(void) dismiss
314 | {
315 | if (!_isAnimating)
316 | return;
317 | [UIView animateWithDuration:0.5f animations:^{
318 | self.alpha = 0;
319 | } completion:^(BOOL finished) {
320 |
321 | // Stop big box
322 | [_bigBoxView.layer removeAllAnimations];
323 |
324 | // Stop small Box
325 | for (NSInteger i = 1; i <= 16; i++)
326 | {
327 | FeLoadingIconBox *box = _arrBox[i-1];
328 |
329 | [box stopAnimate];
330 | }
331 |
332 | // Call delgate method
333 | if ([_delegate respondsToSelector:@selector(FeLoadingIconDidDismiss:)])
334 | {
335 | [_delegate FeLoadingIconDidDismiss:self];
336 | }
337 |
338 | [self removeFromSuperview];
339 |
340 | _isAnimating = NO;
341 |
342 | }];
343 |
344 |
345 | }
346 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
347 | {
348 | [self showWhileExecutingBlock:block completion:nil];
349 | }
350 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
351 | {
352 | // Check block != nil
353 | if (block != nil)
354 | {
355 | [self show];
356 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
357 | {
358 | block();
359 |
360 | // Update UI
361 | dispatch_async(dispatch_get_main_queue(), ^{
362 | completion();
363 | [self dismiss];
364 | });
365 | });
366 | }
367 | }
368 |
369 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
370 | {
371 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
372 | }
373 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
374 | {
375 | if ([target respondsToSelector:selector])
376 | {
377 | methodForExecuting = selector;
378 | targetForExecuting = target;
379 | objectForExecuting = object;
380 | completionBlock = completion;
381 |
382 | // Run
383 | [self show];
384 |
385 | // execute selector in background thread
386 | [NSThread detachNewThreadSelector:@selector(executeSelector) toTarget:self withObject:nil];
387 | }
388 | }
389 | -(void) executeSelector
390 | {
391 | @autoreleasepool {
392 | #pragma clang diagnostic push
393 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
394 |
395 | // Start executing the requested task
396 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
397 | #pragma clang diagnostic pop
398 |
399 | // Task completed, update view in main thread (note: view operations should
400 | // be done only in the main thread)
401 | dispatch_async(dispatch_get_main_queue(), ^{
402 | completionBlock();
403 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
404 | });
405 |
406 | }
407 | }
408 | -(void) cleanUp
409 | {
410 | NSLog(@"Clean up");
411 | if (objectForExecuting)
412 | objectForExecuting = nil;
413 | if (methodForExecuting)
414 | methodForExecuting = nil;
415 | if (targetForExecuting)
416 | targetForExecuting = nil;
417 | if (completionBlock)
418 | completionBlock = nil;
419 | [self dismiss];
420 | }
421 | @end
422 |
--------------------------------------------------------------------------------
/FeSpinner/FeLoadingIconBox.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeLoadingIconBox.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/19/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeLoadingIconBox : UIView
12 | @property (assign, nonatomic, readonly) BOOL isAnimating;
13 | -(id) initBoxAtIndex:(NSInteger) index;
14 |
15 | -(void) playAnimate;
16 | -(void) stopAnimate;
17 | @end
18 |
--------------------------------------------------------------------------------
/FeSpinner/FeLoadingIconBox.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeLoadingIconBox.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/19/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeLoadingIconBox.h"
10 | #define kBoxHeight 25
11 |
12 | @interface FeLoadingIconBox ()
13 | @property (strong, nonatomic) NSTimer *timer;
14 |
15 | -(CGRect) frameAtIndex:(NSInteger) index;
16 | -(void) animate;
17 |
18 | @end
19 | @implementation FeLoadingIconBox
20 |
21 | - (id)initWithFrame:(CGRect)frame
22 | {
23 | self = [super initWithFrame:frame];
24 | if (self) {
25 | // Initialization code
26 | }
27 | return self;
28 | }
29 | -(id) initBoxAtIndex:(NSInteger)index
30 | {
31 | CGRect frame = [self frameAtIndex:index];
32 | self = [super initWithFrame:frame];
33 |
34 | if (self)
35 | {
36 | _isAnimating = NO;
37 | self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2f];
38 | self.userInteractionEnabled = NO;
39 | }
40 | return self;
41 | }
42 | -(void) setupAlphaBoxAtIndex:(NSInteger) index
43 | {
44 | switch (index) {
45 | case 6:
46 | {
47 | self.alpha = 0.5f;
48 | break;
49 | }
50 | case 7:
51 | {
52 | self.alpha = 0.5f;
53 | break;
54 | }
55 | case 10:
56 | {
57 | self.alpha = 0.5f;
58 | break;
59 | }
60 | case 11:
61 | {
62 | self.alpha = 0.5f;
63 | break;
64 | }
65 | default:
66 | break;
67 | }
68 | }
69 | -(CGRect) frameAtIndex:(NSInteger)index
70 | {
71 | CGRect frame;
72 | switch (index) {
73 | case 1:
74 | {
75 | frame = CGRectMake(0, 0, kBoxHeight, kBoxHeight);
76 | break;
77 | }
78 | case 2:
79 | {
80 | frame = CGRectMake(25, 0, kBoxHeight, kBoxHeight);
81 | break;
82 | }
83 | case 3:
84 | {
85 | frame = CGRectMake(50, 0, kBoxHeight, kBoxHeight);
86 | break;
87 | }
88 | case 4:
89 | {
90 | frame = CGRectMake(75, 0, kBoxHeight, kBoxHeight);
91 | break;
92 | }
93 | case 5:
94 | {
95 | frame = CGRectMake(0, 25, kBoxHeight, kBoxHeight);
96 | break;
97 | }
98 | case 6:
99 | {
100 | frame = CGRectMake(25, 25, kBoxHeight, kBoxHeight);
101 | break;
102 | }
103 | case 7:
104 | {
105 | frame = CGRectMake(50, 25, kBoxHeight, kBoxHeight);
106 | break;
107 | }
108 | case 8:
109 | {
110 | frame = CGRectMake(75, 25, kBoxHeight, kBoxHeight);
111 | break;
112 | }
113 | case 9:
114 | {
115 | frame = CGRectMake(0, 50, kBoxHeight, kBoxHeight);
116 | break;
117 | }
118 | case 10:
119 | {
120 | frame = CGRectMake(25, 50, kBoxHeight, kBoxHeight);
121 | break;
122 | }
123 | case 11:
124 | {
125 | frame = CGRectMake(50, 50, kBoxHeight, kBoxHeight);
126 | break;
127 | }
128 | case 12:
129 | {
130 | frame = CGRectMake(75, 50, kBoxHeight, kBoxHeight);
131 | break;
132 | }
133 | case 13:
134 | {
135 | frame = CGRectMake(0, 75, kBoxHeight, kBoxHeight);
136 | break;
137 | }
138 | case 14:
139 | {
140 | frame = CGRectMake(25, 75, kBoxHeight, kBoxHeight);
141 | break;
142 | }
143 | case 15:
144 | {
145 | frame = CGRectMake(50, 75, kBoxHeight, kBoxHeight);
146 | break;
147 | }
148 | case 16:
149 | {
150 | frame = CGRectMake(75, 75, kBoxHeight, kBoxHeight);
151 | break;
152 | }
153 | default:
154 | break;
155 | }
156 | return frame;
157 | }
158 |
159 | #pragma mark Action
160 | -(void) playAnimate
161 | {
162 | if (_isAnimating) {
163 | return;
164 | }
165 |
166 | [self animate];
167 | _timer = [NSTimer scheduledTimerWithTimeInterval:0.55f target:self selector:@selector(animate) userInfo:nil repeats:YES];
168 | NSLog(@"animating");
169 |
170 | }
171 | -(void) stopAnimate
172 | {
173 | if (!_isAnimating)
174 | return;
175 |
176 | [_timer invalidate];
177 | }
178 | -(void) animate
179 | {
180 | [UIView animateWithDuration:0.275f delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
181 | self.backgroundColor = [UIColor colorWithRed:1 green:1 blue:1 alpha:0.2f];
182 | } completion:^(BOOL finished) {
183 | [UIView animateWithDuration:0.275f delay:0 options:UIViewAnimationOptionCurveLinear animations:^{
184 | self.backgroundColor = [UIColor colorWithRed:0 green:0 blue:0 alpha:0.2f];
185 | } completion:^(BOOL finished) {
186 |
187 | }];
188 | }];
189 | }
190 | @end
191 |
--------------------------------------------------------------------------------
/FeSpinner/FeRollingLoader.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeRollingLoader.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/18/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeRollingLoader : UIView
12 |
13 | // is running
14 | @property (assign, readonly, nonatomic) BOOL isShowing;
15 |
16 | -(instancetype) initWithView:(UIView *) view title:(NSString *) title;
17 |
18 | -(void) show;
19 |
20 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
21 |
22 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
23 |
24 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
25 |
26 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
27 |
28 | -(void) dismiss;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/FeSpinner/FeRollingLoader.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeRollingLoader.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/18/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeRollingLoader.h"
10 | #import "UIColor+flat.h"
11 |
12 | #define kFe_Color_DarkShalmon @"E9967A"
13 | #define kFe_Circle_Width 120
14 | #define kFe_Color_Salmon @"#FA8072"
15 |
16 | @interface FeRollingLoader ()
17 | {
18 | NSString *_title;
19 |
20 | // Target, method, object and block
21 | id targetForExecuting;
22 | SEL methodForExecuting;
23 | id objectForExecuting;
24 | dispatch_block_t completionBlock;
25 | }
26 | // Container
27 | @property (weak, nonatomic) UIView *containerView;
28 |
29 | // Circle
30 | @property (strong, nonatomic) CAShapeLayer *circleLayer;
31 |
32 | // Group
33 | @property (strong, nonatomic) CAKeyframeAnimation *keyframePath;
34 | @property (strong, nonatomic) CAKeyframeAnimation *keyframeBackground;
35 | @property (strong, nonatomic) CABasicAnimation *animationTransfrom;
36 |
37 | // Keyframe
38 | @property (strong, nonatomic) CAAnimationGroup *groupAnimation;
39 |
40 | //////
41 | -(void) initCommon;
42 | -(void) initCircle;
43 | -(void) initAnimation;
44 | @end
45 | @implementation FeRollingLoader
46 | -(instancetype) initWithView:(UIView *)view title:(NSString *)title
47 | {
48 | self = [super init];
49 | if (self)
50 | {
51 | _containerView = view;
52 | _title = title;
53 |
54 | [self initCommon];
55 |
56 | [self initCircle];
57 |
58 | [self initAnimation];
59 | }
60 | return self;
61 | }
62 | -(void) initCommon
63 | {
64 | _isShowing = NO;
65 | self.frame = _containerView.bounds;
66 | self.backgroundColor = [UIColor colorWithHexCode:@"#FEEADF"];
67 | }
68 | -(void) initCircle
69 | {
70 | // Circle
71 | _circleLayer = [CAShapeLayer layer];
72 | _circleLayer.frame = CGRectMake(0, 0, kFe_Circle_Width, kFe_Circle_Width);
73 | _circleLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
74 | _circleLayer.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
75 | //_circleLayer.backgroundColor = [UIColor colorWithHexCode:kFe_Color_DarkShalmon].CGColor;
76 |
77 | // Shape
78 | CGFloat length = kFe_Circle_Width / 2.0f;
79 | CGPathRef path = [self pathRefForCornerRectWithTopLeftRadius:0.85f * length topRight:0.95f * length bottomLeft:0.85f * length bottomRight:0.95f * length];
80 |
81 | // Set Path
82 | _circleLayer.path = path;
83 | _circleLayer.masksToBounds = YES;
84 | _circleLayer.fillColor = [UIColor colorWithHexCode:kFe_Color_DarkShalmon].CGColor;
85 |
86 |
87 | // Add
88 | [self.layer addSublayer:_circleLayer];
89 | }
90 |
91 | -(void) initAnimation
92 | {
93 | if (YES) // Path
94 | {
95 | // Path 0
96 | CGFloat length = kFe_Circle_Width / 2;
97 | CGPathRef path_0 = [self pathRefForCornerRectWithTopLeftRadius:0.65f * length topRight:0.85f * length bottomLeft:0.85f * length bottomRight:0.65f * length];
98 |
99 | // Path 25
100 | CGPathRef path_25 = [self pathRefForCornerRectWithTopLeftRadius:0.75f * length topRight:0.85f * length bottomLeft:0.85f * length bottomRight:0.75f * length];
101 |
102 | // Path 50
103 | CGPathRef path_50 = [self pathRefForCornerRectWithTopLeftRadius:0.95f * length topRight:0.75f * length bottomLeft:0.75f * length bottomRight:0.95f * length];
104 |
105 | // Path 75
106 | CGPathRef path_75 = [self pathRefForCornerRectWithTopLeftRadius:0.95f * length topRight:0.95f * length bottomLeft:0.95f * length bottomRight:0.95f * length];
107 |
108 | // Paht 1-00
109 | CGPathRef path_100 = [self pathRefForCornerRectWithTopLeftRadius:0.65f * length topRight:0.85f * length bottomLeft:0.85f * length bottomRight:0.65f * length];
110 |
111 | _keyframePath = [CAKeyframeAnimation animationWithKeyPath:@"path"];
112 | _keyframePath.keyTimes = @[@0.0f, @0.25f, @0.5f, @0.75f, @1.0f];
113 | _keyframePath.values = @[(__bridge id) path_0, (__bridge id) path_25, (__bridge id) path_50, (__bridge id) path_75, (__bridge id) path_100];
114 | _keyframePath.duration = 1.3f;
115 | _keyframePath.repeatCount = MAXFLOAT;
116 | }
117 |
118 | if (YES) // Background
119 | {
120 | _keyframeBackground = [CAKeyframeAnimation animationWithKeyPath:@"fillColor"];
121 | _keyframeBackground.keyTimes = @[@0.0f, @0.25f, @0.5f, @0.75f, @1.0f];
122 | _keyframeBackground.values = @[(id)[UIColor colorWithHexCode:kFe_Color_DarkShalmon].CGColor,
123 | (id)[UIColor colorWithHexCode:kFe_Color_Salmon].CGColor,
124 | (id)[UIColor colorWithHexCode:kFe_Color_DarkShalmon].CGColor,
125 | (id)[UIColor colorWithHexCode:kFe_Color_Salmon].CGColor,
126 | (id)[UIColor colorWithHexCode:kFe_Color_DarkShalmon].CGColor];
127 | _keyframeBackground.duration = 1.3f;
128 | _keyframeBackground.repeatCount = MAXFLOAT;
129 | }
130 |
131 | if (YES)// Transfrom
132 | {
133 | _animationTransfrom = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
134 | [_animationTransfrom setFromValue:[NSNumber numberWithDouble:0.0f]];
135 | [_animationTransfrom setToValue:[NSNumber numberWithDouble:(M_PI * 2.0f)]];
136 | }
137 |
138 |
139 |
140 | // Group
141 | _groupAnimation = [CAAnimationGroup animation];
142 | _groupAnimation.duration = 1.3f;
143 | _groupAnimation.repeatCount = MAXFLOAT;
144 | _groupAnimation.animations = @[_keyframePath, _keyframeBackground, _animationTransfrom];
145 |
146 | }
147 | #pragma mark - Private
148 | -(CGPathRef) pathRefForCornerRectWithTopLeftRadius:(CGFloat) topLeftRadius topRight:(CGFloat) topRightRadius bottomLeft:(CGFloat) bottomLeftRadius bottomRight:(CGFloat) bottomRightRadius
149 | {
150 |
151 |
152 | CGRect rect = CGRectMake(0, 0, kFe_Circle_Width, kFe_Circle_Width);
153 |
154 | CGFloat minx = CGRectGetMinX( rect );
155 | CGFloat midx = CGRectGetMidX( rect );
156 | CGFloat maxx = CGRectGetMaxX( rect );
157 | CGFloat miny = CGRectGetMinY( rect );
158 | CGFloat midy = CGRectGetMidY( rect );
159 | CGFloat maxy = CGRectGetMaxY( rect );
160 |
161 | CGMutablePathRef pathRef = CGPathCreateMutable();
162 | CGPathMoveToPoint(pathRef, NULL, minx, midy);
163 | CGPathAddArcToPoint(pathRef, NULL, minx, miny, midx, miny, bottomLeftRadius);
164 | CGPathAddArcToPoint(pathRef, NULL, maxx, miny, maxx, midy, bottomRightRadius);
165 | CGPathAddArcToPoint(pathRef, NULL, maxx, maxy, midx, maxy, topRightRadius);
166 | CGPathAddArcToPoint(pathRef, NULL, minx, maxy, minx, midy, topLeftRadius);
167 |
168 | return pathRef;
169 | }
170 |
171 | -(void) show
172 | {
173 | if (_isShowing)
174 | {
175 | return;
176 | }
177 |
178 | _isShowing = YES;
179 | [_circleLayer addAnimation:_groupAnimation forKey:@"rolling"];
180 | }
181 | -(void) dismiss
182 | {
183 | if (!_isShowing)
184 | return;
185 |
186 | _isShowing = NO;
187 |
188 | }
189 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
190 | {
191 | [self showWhileExecutingBlock:block completion:nil];
192 | }
193 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
194 | {
195 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
196 |
197 | }
198 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
199 | {
200 | // Check block != nil
201 | if (block != nil)
202 | {
203 | [self show];
204 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
205 | {
206 | block();
207 |
208 | // Update UI
209 | dispatch_async(dispatch_get_main_queue(), ^{
210 | completion();
211 | [self dismiss];
212 | });
213 | });
214 | }
215 | }
216 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
217 | {
218 | // Check Selector is responded
219 | if ([target respondsToSelector:selector])
220 | {
221 | methodForExecuting = selector;
222 | targetForExecuting = target;
223 | objectForExecuting = object;
224 | completionBlock = completion;
225 |
226 | [self show];
227 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
228 | }
229 | }
230 | #pragma mark Helper method
231 | -(void) executingMethod
232 | {
233 | @autoreleasepool {
234 | #pragma clang diagnostic push
235 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
236 | // Start executing the requested task
237 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
238 | #pragma clang diagnostic pop
239 | // Task completed, update view in main thread (note: view operations should
240 | // be done only in the main thread)
241 | dispatch_async(dispatch_get_main_queue(), ^{
242 | completionBlock();
243 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
244 | });
245 |
246 | }
247 | }
248 | -(void) cleanUp
249 | {
250 | NSLog(@"Clean up");
251 | if (objectForExecuting)
252 | objectForExecuting = nil;
253 | if (methodForExecuting)
254 | methodForExecuting = nil;
255 | if (targetForExecuting)
256 | targetForExecuting = nil;
257 | if (completionBlock)
258 | completionBlock = nil;
259 | [self dismiss];
260 | }
261 | @end
262 |
--------------------------------------------------------------------------------
/FeSpinner/FeRollingViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeRollingViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/18/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeRollingViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeRollingViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeRollingViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/18/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeRollingViewController.h"
10 | #import "FeRollingLoader.h"
11 |
12 | @interface FeRollingViewController ()
13 | @property (strong, nonatomic) FeRollingLoader *rollingLoader;
14 |
15 | @end
16 |
17 | @implementation FeRollingViewController
18 |
19 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
20 | {
21 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
22 | if (self) {
23 | // Custom initialization
24 | }
25 | return self;
26 | }
27 |
28 | - (void)viewDidLoad
29 | {
30 | [super viewDidLoad];
31 | // Do any additional setup after loading the view.
32 |
33 | _rollingLoader = [[FeRollingLoader alloc] initWithView:self.view title:@"LOADING"];
34 | [self.view addSubview:_rollingLoader];
35 |
36 | [_rollingLoader showWhileExecutingBlock:^{
37 | [self myTask];
38 | } completion:^{
39 | [self.navigationController popToRootViewControllerAnimated:YES];
40 | }];
41 | }
42 | - (void)myTask
43 | {
44 | // Do something usefull in here instead of sleeping ...
45 | sleep(12);
46 | }
47 | @end
48 |
--------------------------------------------------------------------------------
/FeSpinner/FeSpinner-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | UIStatusBarHidden
6 |
7 | UIViewControllerBasedStatusBarAppearance
8 |
9 | CFBundleDevelopmentRegion
10 | en
11 | CFBundleDisplayName
12 | ${PRODUCT_NAME}
13 | CFBundleExecutable
14 | ${EXECUTABLE_NAME}
15 | CFBundleIdentifier
16 | com.fe.${PRODUCT_NAME:rfc1034identifier}
17 | CFBundleInfoDictionaryVersion
18 | 6.0
19 | CFBundleName
20 | ${PRODUCT_NAME}
21 | CFBundlePackageType
22 | APPL
23 | CFBundleShortVersionString
24 | 1.0
25 | CFBundleSignature
26 | ????
27 | CFBundleVersion
28 | 1.0
29 | LSRequiresIPhoneOS
30 |
31 | UIAppFonts
32 |
33 | CabinCondensed-Bold.ttf
34 | Neou-Thin.ttf
35 |
36 | UIMainStoryboardFile
37 | Main_iPhone
38 | UIMainStoryboardFile~ipad
39 | Main_iPad
40 | UIRequiredDeviceCapabilities
41 |
42 | armv7
43 |
44 | UISupportedInterfaceOrientations
45 |
46 | UIInterfaceOrientationPortrait
47 |
48 | UISupportedInterfaceOrientations~ipad
49 |
50 | UIInterfaceOrientationPortrait
51 | UIInterfaceOrientationPortraitUpsideDown
52 | UIInterfaceOrientationLandscapeLeft
53 | UIInterfaceOrientationLandscapeRight
54 |
55 |
56 |
57 |
--------------------------------------------------------------------------------
/FeSpinner/FeSpinner-Prefix.pch:
--------------------------------------------------------------------------------
1 | //
2 | // Prefix header
3 | //
4 | // The contents of this file are implicitly included at the beginning of every source file.
5 | //
6 |
7 | #import
8 |
9 | #ifndef __IPHONE_5_0
10 | #warning "This project uses features only available in iOS SDK 5.0 and later."
11 | #endif
12 |
13 | #ifdef __OBJC__
14 | #import
15 | #import
16 | #endif
17 |
--------------------------------------------------------------------------------
/FeSpinner/FeSpinnerTenDot.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeSpinnerTenDot.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/29/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 | @protocol FeSpinnerTenDotDelegate;
11 |
12 | @interface FeSpinnerTenDot : UIView
13 |
14 | // Init Fe Spinner View Ten Dot
15 | -(id) initWithView:(UIView *) view withBlur:(BOOL) blur;
16 |
17 | // Delegate
18 | @property (weak, nonatomic) id delegate;
19 |
20 | // Title
21 | @property (strong, nonatomic) NSString *titleLabelText;
22 | @property (strong, nonatomic) UIFont *fontTitleLabel;
23 |
24 |
25 | -(void) show;
26 |
27 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
28 |
29 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
30 |
31 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
32 |
33 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
34 |
35 | -(void) dismiss;
36 | @end
37 |
38 | @protocol FeSpinnerTenDotDelegate
39 | @optional
40 | -(void) FeSpinnerTenDotWillShow:(FeSpinnerTenDot *) sender;
41 | -(void) FeSpinnerTenDotDidShow:(FeSpinnerTenDot *) sender;
42 | -(void) FeSpinnerTenDotDidDismiss:(FeSpinnerTenDot *)sender;
43 | @end
--------------------------------------------------------------------------------
/FeSpinner/FeSpinnerTenDot.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeSpinnerTenDot.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/29/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeSpinnerTenDot.h"
10 | #import "FXBlurView.h"
11 | #import "UIColor+flat.h"
12 | #import "FeTenDot.h"
13 | #define kMaxTenDot 10
14 | #define kPagingLabel 30
15 |
16 | @interface FeSpinnerTenDot ()
17 | {
18 | id targetForExecuting;
19 | SEL methodForExecuting;
20 | id objectForExecuting;
21 | dispatch_block_t completionBlock;
22 | }
23 | // Blur View
24 | @property (strong, nonatomic) FXBlurView *backgroundBlur;
25 |
26 | // Background Static for Blur View
27 | @property (strong, nonatomic) UIView *backgroundStatic;
28 |
29 | // Arr of dot
30 | @property (strong, nonatomic) NSMutableArray *arrDot;
31 |
32 | // Container View
33 | @property (weak, nonatomic) UIView *containerView;
34 |
35 | // Timer
36 | @property (strong, nonatomic) NSTimer *timer;
37 |
38 | // Label
39 | @property (strong, nonatomic) UILabel *label;
40 |
41 | // BOOL
42 | @property (assign, nonatomic) BOOL isShouldBlur;
43 | @property (assign, nonatomic) BOOL isAnimating;
44 |
45 | //****************************
46 | // Common init
47 | -(void) commonInit;
48 | -(void) initBackgroundWithBlur:(BOOL) blur;
49 | -(void) initDot;
50 | -(void) initLabel;
51 | -(void) resetLabel;
52 |
53 | // clean up method, target, object
54 | -(void) cleanUp;
55 |
56 | // Executing method
57 | -(void) executingMethod;
58 | @end
59 | @implementation FeSpinnerTenDot
60 |
61 | -(id) initWithView:(UIView *)view withBlur:(BOOL)blur
62 | {
63 | // CHeck
64 | if (view.bounds.size.height <= 100)
65 | {
66 | NSAssert(NO, @"Container View's height shouldn't less than 100");
67 | }
68 |
69 | self = [super init];
70 | if (self)
71 | {
72 | _containerView = view;
73 | _isShouldBlur = blur;
74 | _arrDot = [[NSMutableArray alloc] initWithCapacity:10];
75 |
76 | // init common
77 | [self commonInit];
78 |
79 | // BOOl
80 | _isAnimating = NO;
81 | self.hidden = YES;
82 | self.alpha = 0;
83 |
84 | }
85 | return self;
86 | }
87 |
88 | #pragma mark Common Init
89 | -(void) commonInit
90 | {
91 | // init frame as bound container
92 | self.frame = _containerView.bounds;
93 |
94 | // init Background
95 | [self initBackgroundWithBlur:_isShouldBlur];
96 |
97 | // init Ten Dot
98 | [self initDot];
99 |
100 | }
101 | -(void) initBackgroundWithBlur:(BOOL)blur
102 | {
103 | // init Background for Blur View
104 | if (_isShouldBlur)
105 | {
106 | _backgroundBlur = [[FXBlurView alloc] initWithFrame:_containerView.bounds];
107 | _backgroundBlur.blurRadius = 40;
108 | _backgroundBlur.tintColor = [UIColor colorWithHexCode:@"#32ce55"];
109 | _backgroundBlur.dynamic = NO;
110 | [_backgroundBlur.layer displayIfNeeded];
111 |
112 | // Hide background
113 | _backgroundBlur.hidden = YES;
114 |
115 | }
116 | else
117 | {
118 | _backgroundStatic = [[UIView alloc] initWithFrame:_containerView.bounds];
119 | _backgroundStatic.backgroundColor = [UIColor colorWithHexCode:@"#32ce55"];
120 | }
121 |
122 | }
123 | -(void) initDot
124 | {
125 | CGPoint center = self.center;
126 |
127 | // init center dot
128 | UIView *centerDot = [[UIView alloc] initWithFrame:CGRectMake(center.x, center.y, 20, 20)];
129 | centerDot.clipsToBounds = YES;
130 | centerDot.layer.cornerRadius = centerDot.bounds.size.height /2;
131 | centerDot.backgroundColor = [UIColor whiteColor];
132 | centerDot.center = center;
133 |
134 | [self addSubview:centerDot];
135 |
136 | // init 10 dot
137 | for (NSInteger i = 0 ; i < kMaxTenDot; i++)
138 | {
139 | FeTenDot *dot = [[FeTenDot alloc] initDotAtMainView:self atIndex:i];
140 | [_arrDot addObject:dot];
141 |
142 | [self addSubview: dot];
143 |
144 | }
145 | }
146 | -(void) initLabel
147 | {
148 | // init Label
149 | _label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 200, 100)];
150 | _label.textColor = [UIColor whiteColor];
151 | _label.text = _titleLabelText;
152 | _label.textAlignment = NSTextAlignmentCenter;
153 |
154 | // fit for size
155 | [_label sizeToFit];
156 |
157 | // set center
158 | _label.center = CGPointMake(self.center.x, self.center.y + kPagingLabel + 30 + _label.bounds.size.height / 2);
159 |
160 | [self addSubview:_label];
161 | }
162 | -(void) resetLabel
163 | {
164 | if (_isAnimating)
165 | {
166 | // Animation Title label
167 | CATransition *animation = [CATransition animation];
168 | animation.duration = 0.8f;
169 | animation.type = kCATransitionFade;
170 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
171 | [_label.layer addAnimation:animation forKey:@"changeTextTransition"];
172 |
173 | // Change text
174 | _label.font = _fontTitleLabel;
175 | _label.text = _titleLabelText;
176 |
177 | }
178 | else
179 | {
180 | // Change the text
181 | _label.font = _fontTitleLabel;
182 | _label.text = _titleLabelText;
183 | }
184 | [_label sizeToFit];
185 |
186 | _label.center = CGPointMake(self.center.x, self.center.y + kPagingLabel + 30 + _label.bounds.size.height / 2);
187 | }
188 |
189 | #pragma mark Setter / getter
190 | -(void) setTitleLabelText:(NSString *)titleLabelText
191 | {
192 | // Return if the same
193 | if ([_titleLabelText isEqualToString:titleLabelText])
194 | return;
195 | _titleLabelText = titleLabelText;
196 |
197 |
198 | if (!_label)
199 | {
200 | [self initLabel];
201 | }
202 |
203 | [self resetLabel];
204 | }
205 | -(void) setFontTitleLabel:(UIFont *)fontTitleLabel
206 | {
207 | if (_fontTitleLabel == fontTitleLabel)
208 | return;
209 |
210 | _fontTitleLabel = fontTitleLabel;
211 |
212 | // Reset layout Label
213 | [self resetLabel];
214 |
215 | }
216 |
217 | #pragma mark Action Animate
218 | -(void) show
219 | {
220 | if (_isAnimating)
221 | return;
222 |
223 | //Set hidden
224 | self.hidden = NO;
225 | self.alpha = 0;
226 |
227 | if (_isShouldBlur)
228 | {
229 | _backgroundBlur.alpha = 0;
230 | _backgroundBlur.hidden = NO;
231 | [_containerView insertSubview:_backgroundBlur belowSubview:self];
232 | }
233 | else
234 | {
235 | [self insertSubview:_backgroundStatic atIndex:0];
236 | }
237 |
238 | // Call Delegate
239 | if ([_delegate respondsToSelector:@selector(FeSpinnerTenDotWillShow:)])
240 | {
241 | [_delegate FeSpinnerTenDotWillShow:self];
242 | }
243 |
244 | [UIView animateWithDuration:0.5f delay:0
245 | options:UIViewAnimationOptionCurveEaseIn
246 | animations:^
247 | {
248 | self.alpha = 1;
249 |
250 | if (_isShouldBlur)
251 | {
252 | _backgroundBlur.alpha = 1;
253 | }
254 | } completion:^(BOOL finished)
255 | {
256 | _isAnimating = YES;
257 | // Call Delegate
258 | if ([_delegate respondsToSelector:@selector(FeSpinnerTenDotDidShow:)])
259 | {
260 | [_delegate FeSpinnerTenDotDidShow:self];
261 | }
262 |
263 |
264 |
265 | CGFloat delay = 0;
266 | for (NSInteger i = 0 ; i < kMaxTenDot ; i++)
267 | {
268 | FeTenDot *dot = _arrDot[i];
269 | [dot performSelector:@selector(start) withObject:nil afterDelay:delay];
270 |
271 | delay += 0.1f;
272 | }
273 | }];
274 |
275 | }
276 | -(void) dismiss
277 | {
278 | if (!_isAnimating)
279 | return;
280 |
281 | [UIView animateWithDuration:0.4f delay:0
282 | options:UIViewAnimationOptionCurveEaseIn animations:^{
283 | self.alpha = 0;
284 |
285 | if (_isShouldBlur)
286 | {
287 | _backgroundBlur.alpha = 0;
288 | }
289 | } completion:^(BOOL finished) {
290 | for (NSInteger i = 0 ; i < kMaxTenDot ; i++)
291 | {
292 | FeTenDot *dot = _arrDot[i];
293 | [dot stop];
294 | [dot reset];
295 | }
296 |
297 | _isAnimating = NO;
298 |
299 | if (_isShouldBlur)
300 | [_backgroundBlur removeFromSuperview];
301 |
302 | // Call delegate
303 | if ([_delegate respondsToSelector:@selector(FeSpinnerTenDotDidDismiss:)])
304 | {
305 | [_delegate FeSpinnerTenDotDidDismiss:self];
306 | }
307 |
308 | [self removeFromSuperview];
309 | [self cleanUp];
310 | }];
311 |
312 |
313 | }
314 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
315 | {
316 | [self showWhileExecutingBlock:block completion:nil];
317 | }
318 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
319 | {
320 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
321 |
322 | }
323 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
324 | {
325 | // Check block != nil
326 | if (block != nil)
327 | {
328 | [self show];
329 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
330 | {
331 | block();
332 |
333 | // Update UI
334 | dispatch_async(dispatch_get_main_queue(), ^{
335 | completion();
336 | [self dismiss];
337 | });
338 | });
339 | }
340 | }
341 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
342 | {
343 | // Check Selector is responded
344 | if ([target respondsToSelector:selector])
345 | {
346 | methodForExecuting = selector;
347 | targetForExecuting = target;
348 | objectForExecuting = object;
349 | completionBlock = completion;
350 |
351 | [self show];
352 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
353 | }
354 | }
355 | #pragma mark Helper method
356 | -(void) executingMethod
357 | {
358 | @autoreleasepool {
359 | #pragma clang diagnostic push
360 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
361 | // Start executing the requested task
362 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
363 | #pragma clang diagnostic pop
364 | // Task completed, update view in main thread (note: view operations should
365 | // be done only in the main thread)
366 | dispatch_async(dispatch_get_main_queue(), ^{
367 | completionBlock();
368 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
369 | });
370 |
371 | }
372 | }
373 | -(void) cleanUp
374 | {
375 | NSLog(@"Clean up");
376 | if (objectForExecuting)
377 | objectForExecuting = nil;
378 | if (methodForExecuting)
379 | methodForExecuting = nil;
380 | if (targetForExecuting)
381 | targetForExecuting = nil;
382 | if (completionBlock)
383 | completionBlock = nil;
384 | [self dismiss];
385 | }
386 | @end
387 |
--------------------------------------------------------------------------------
/FeSpinner/FeSpinnerTenDotViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeSpinnerTenDotViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/18/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeSpinnerTenDotViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeSpinnerTenDotViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeSpinnerTenDotViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/18/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeSpinnerTenDotViewController.h"
10 | #import "FeSpinnerTenDot.h"
11 | #import "UIColor+flat.h"
12 |
13 | @interface FeSpinnerTenDotViewController ()
14 | {
15 | NSInteger index;
16 | }
17 | @property (strong, nonatomic) FeSpinnerTenDot *spinner;
18 | @property (strong, nonatomic) NSArray *arrTitile;
19 | @property (strong, nonatomic) NSTimer *timer;
20 |
21 | - (IBAction)start:(id)sender;
22 | - (IBAction)dismiss:(id)sender;
23 | -(void) changeTitle;
24 | -(void) longTask;
25 | @end
26 |
27 | @implementation FeSpinnerTenDotViewController
28 |
29 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
30 | {
31 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
32 | if (self) {
33 | // Custom initialization
34 | }
35 | return self;
36 | }
37 |
38 | - (void)viewDidLoad
39 | {
40 | [super viewDidLoad];
41 | // Do any additional setup after loading the view.
42 |
43 | self.view.backgroundColor = [UIColor colorWithHexCode:@"#019875"];
44 |
45 | //*********
46 | index = 0;
47 | _arrTitile = @[@"LOADING",@"PLZ WAITING",@"CALM DOWN",@"SUCCESSFUL"];
48 |
49 | // init Loader
50 | _spinner = [[FeSpinnerTenDot alloc] initWithView:self.view withBlur:NO];
51 | _spinner.titleLabelText = _arrTitile[index];
52 | _spinner.fontTitleLabel = [UIFont fontWithName:@"Neou-Thin" size:36];
53 | _spinner.delegate = self;
54 |
55 | [self.view addSubview:_spinner];
56 | }
57 |
58 | - (void)didReceiveMemoryWarning
59 | {
60 | [super didReceiveMemoryWarning];
61 | // Dispose of any resources that can be recreated.
62 | }
63 |
64 | -(void) viewDidAppear:(BOOL)animated
65 | {
66 | [super viewDidAppear:animated];
67 |
68 | [self start:self];
69 |
70 | [self performSelector:@selector(dismiss:) withObject:nil afterDelay:7.0f];
71 | }
72 | - (IBAction)start:(id)sender
73 | {
74 | if (!_timer)
75 | {
76 | _timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(changeTitle) userInfo:nil repeats:YES];
77 | }
78 |
79 | [_spinner showWhileExecutingSelector:@selector(longTask) onTarget:self withObject:nil completion:^{
80 | [_timer invalidate];
81 | _timer = nil;
82 |
83 | index = 0;
84 |
85 | [self.navigationController popToRootViewControllerAnimated:YES];
86 | }];
87 | }
88 | -(void) longTask
89 | {
90 | // Do a long take
91 | sleep(5);
92 | }
93 | - (IBAction)dismiss:(id)sender
94 | {
95 | [_timer invalidate];
96 | [_spinner dismiss];
97 |
98 | // pop
99 | [self.navigationController popViewControllerAnimated:YES];
100 | }
101 | -(void) changeTitle
102 | {
103 | NSLog(@"index = %d",index);
104 |
105 | if (index >= _arrTitile.count)
106 | return;
107 |
108 | _spinner.titleLabelText = _arrTitile[index];
109 | index++;
110 | }
111 | -(void) FeSpinnerTenDotDidDismiss:(FeSpinnerTenDot *)sender
112 | {
113 | NSLog(@"did dismiss");
114 | }
115 | @end
116 |
--------------------------------------------------------------------------------
/FeSpinner/FeTenDot.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeTenDot.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/13/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeTenDot : UIView
12 | @property (assign, nonatomic) CATransform3D originalTransform3D;
13 | -(id) initDotAtMainView:(UIView *) mainView atIndex:(NSInteger) index;
14 |
15 | -(void) start;
16 | -(void) stop;
17 | -(void) reset;
18 | @end
19 |
--------------------------------------------------------------------------------
/FeSpinner/FeTenDot.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeTenDot.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/13/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeTenDot.h"
10 |
11 | #define kMargeCenterX 10
12 | #define kMargeCenterY 10
13 | #define kDurationDot 0.15f
14 |
15 | @interface FeTenDot ()
16 | //Timer
17 | @property (strong, nonatomic) NSTimer *timer;
18 | @property (assign, nonatomic) BOOL isAnimating;
19 |
20 | // Main View
21 | @property (weak, nonatomic) UIView *mainView;
22 | @property (assign, nonatomic) NSInteger indexDot;
23 | @property (assign, nonatomic) CGPoint originCenter;
24 |
25 | -(CGPoint) centerAtIndex:(NSInteger) index;
26 | -(CATransform3D ) transform3DAtIndex:(NSInteger) index;
27 | -(void) animate;
28 | @end
29 | @implementation FeTenDot
30 |
31 | - (id)initWithFrame:(CGRect)frame
32 | {
33 | self = [super initWithFrame:frame];
34 | if (self) {
35 | // Initialization code
36 | }
37 | return self;
38 | }
39 | -(id) initDotAtMainView:(UIView *) mainView atIndex:(NSInteger) index
40 | {
41 |
42 | CGRect frame = CGRectMake(mainView.center.x, mainView.center.y, 20, 20);
43 | self = [super initWithFrame:frame];
44 |
45 | if (self)
46 | {
47 | // Deafault
48 | self.backgroundColor = [UIColor whiteColor];
49 | self.layer.cornerRadius = self.bounds.size.width / 2;
50 | self.clipsToBounds = YES;
51 | _isAnimating = NO;
52 | _mainView = mainView;
53 | _indexDot = index;
54 |
55 | self.center = [self centerAtIndex:index];
56 | _originCenter = self.center;
57 |
58 | _originalTransform3D = [self transform3DAtIndex:index];
59 | self.layer.transform = _originalTransform3D;
60 |
61 | self.userInteractionEnabled = NO;
62 | }
63 |
64 | return self;
65 | }
66 |
67 | #pragma mark Main method
68 | -(void) start
69 | {
70 | if (_isAnimating)
71 | {
72 | return;
73 | }
74 |
75 | // Animate
76 | if (!_isAnimating)
77 | {
78 | // Set bool
79 | _isAnimating = YES;
80 |
81 | // First animate
82 | [self animate];
83 |
84 | // Run loop
85 | _timer = [NSTimer scheduledTimerWithTimeInterval:2.7f target:self selector:@selector(animate) userInfo:nil repeats:HUGE_VAL];
86 | }
87 | }
88 | -(void) stop
89 | {
90 | if (!_timer || !_isAnimating)
91 | return;
92 |
93 | if (_timer && _isAnimating)
94 | {
95 | [_timer invalidate];
96 | _isAnimating = NO;
97 | }
98 | }
99 | -(void) animate
100 | {
101 | [UIView animateWithDuration:kDurationDot
102 | delay:0
103 | options:UIViewAnimationOptionCurveEaseOut
104 | animations:^{
105 | self.layer.transform = CATransform3DIdentity;
106 | } completion:^(BOOL finished) {
107 | [UIView animateWithDuration:kDurationDot delay:1.2f options:UIViewAnimationOptionCurveEaseOut animations:^{
108 | self.layer.transform = _originalTransform3D;
109 |
110 | } completion:^(BOOL finished) {
111 | [UIView animateWithDuration:0 delay:1.2f options:UIViewAnimationOptionCurveEaseOut animations:^{
112 |
113 | } completion:^(BOOL finished) {
114 |
115 | }];
116 | }];
117 | }];
118 | }
119 | -(void) reset
120 | {
121 | [_timer invalidate];
122 |
123 | self.layer.transform = CATransform3DIdentity;
124 |
125 | self.center = _originCenter;
126 |
127 | _originalTransform3D = [self transform3DAtIndex:_indexDot];
128 | self.layer.transform = _originalTransform3D;
129 | }
130 |
131 | #pragma mark Helper method
132 | -(CGPoint) centerAtIndex:(NSInteger)index
133 | {
134 | CGPoint center;
135 |
136 | switch (index)
137 | {
138 | case 0:
139 | {
140 | center = CGPointMake(self.center.x - 10, self.center.y - 50);
141 | break;
142 | }
143 | case 1:
144 | {
145 | center = CGPointMake(self.center.x + 14, self.center.y - 43);
146 |
147 | break;
148 | }
149 | case 2:
150 | {
151 | center = CGPointMake(self.center.x + 29, self.center.y - 24);
152 | break;
153 | }
154 | case 3:
155 | {
156 | center = CGPointMake(self.center.x + 29, self.center.y);
157 | break;
158 | }
159 | case 4:
160 | {
161 | center = CGPointMake(self.center.x + 15, self.center.y + 22);
162 | break;
163 | }
164 | case 5:
165 | {
166 | center = CGPointMake(self.center.x - 10, self.center.y + 30);
167 | break;
168 | }
169 | case 6:
170 | {
171 | center = CGPointMake(self.center.x -35, self.center.y + 22);
172 |
173 | break;
174 | }
175 | case 7:
176 | {
177 | center = CGPointMake(self.center.x -49, self.center.y );
178 | break;
179 | }
180 | case 8:
181 | {
182 | center = CGPointMake(self.center.x - 49, self.center.y - 24);
183 |
184 | break;
185 | }
186 | case 9:
187 | {
188 | center = CGPointMake(self.center.x - 34, self.center.y - 43);
189 | break;
190 | }
191 | default:
192 | break;
193 | }
194 | return center;
195 | }
196 | -(CATransform3D) transform3DAtIndex:(NSInteger)index
197 | {
198 | CATransform3D t = CATransform3DIdentity;
199 | switch (index) {
200 | case 0:
201 | {
202 | t = CATransform3DTranslate(t, 10 - kMargeCenterX, 50 - kMargeCenterY, 0);
203 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
204 | break;
205 | }
206 | case 1:
207 | {
208 | t = CATransform3DTranslate(t, -14 - kMargeCenterX, 43 - kMargeCenterY, 0);
209 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
210 | break;
211 | }
212 | case 2:
213 | {
214 | t = CATransform3DTranslate(t, -29 - kMargeCenterX, 24 - kMargeCenterY, 0);
215 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
216 | break;
217 | }
218 | case 3:
219 | {
220 | t = CATransform3DTranslate(t, -29 - kMargeCenterX, 0 - kMargeCenterY, 0);
221 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
222 | break;
223 | }
224 | case 4:
225 | {
226 | t = CATransform3DTranslate(t, -15 - kMargeCenterX, -22 - kMargeCenterY, 0);
227 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
228 | break;
229 | }
230 | case 5:
231 | {
232 | t = CATransform3DTranslate(t, 10 - kMargeCenterX, -30 - kMargeCenterY, 0);
233 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
234 | break;
235 | }
236 | case 6:
237 | {
238 | t = CATransform3DTranslate(t, 35 - kMargeCenterX, -22 - kMargeCenterY, 0);
239 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
240 | break;
241 | }
242 | case 7:
243 | {
244 | t = CATransform3DTranslate(t, 49 - kMargeCenterX, 0 - kMargeCenterY, 0);
245 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
246 | break;
247 | }
248 | case 8:
249 | {
250 | t = CATransform3DTranslate(t, 49 - kMargeCenterX, 24 - kMargeCenterY, 0);
251 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
252 |
253 | break;
254 | }
255 | case 9:
256 | {
257 | t = CATransform3DTranslate(t, 34 - kMargeCenterX, 43 - kMargeCenterY, 0);
258 | t = CATransform3DScale(t, 0.1f, 0.1f, 0.1f);
259 | break;
260 | }
261 | default:
262 | break;
263 | }
264 | return t;
265 | }
266 | @end
267 |
--------------------------------------------------------------------------------
/FeSpinner/FeThreeDotGlow.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeThreeDotGlow.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/4/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeThreeDotGlow : UIView
12 |
13 | @property (assign, nonatomic, readonly) BOOL isShowing;
14 |
15 | -(id) initWithView:(UIView *) view blur:(BOOL) blur;
16 |
17 | -(void) show;
18 |
19 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
20 |
21 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
22 |
23 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
24 |
25 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
26 |
27 | -(void) dismiss;
28 |
29 | @end
30 |
--------------------------------------------------------------------------------
/FeSpinner/FeThreeDotGlow.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeThreeDotGlow.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/4/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeThreeDotGlow.h"
10 | #import "UIColor+flat.h"
11 |
12 | @interface FeThreeDotGlow()
13 | {
14 | // Target, method, object and block
15 | id targetForExecuting;
16 | SEL methodForExecuting;
17 | id objectForExecuting;
18 | dispatch_block_t completionBlock;
19 | }
20 | @property (weak, nonatomic) UIView *container;
21 | @property (strong, nonatomic) CALayer *containerDotLayer;
22 | @property (strong, nonatomic) NSMutableArray *arrThreeDots;
23 | @property (strong, nonatomic) CABasicAnimation *rotateAnimation;
24 | @property (strong, nonatomic) CAKeyframeAnimation *glowAnimation;
25 | @property (strong, nonatomic) CAKeyframeAnimation *colorGlowAnimation;
26 | @property (strong, nonatomic) CAKeyframeAnimation *colorDotAnimation;
27 | @property (strong, nonatomic) CAAnimationGroup *groupAnimation;
28 |
29 | -(void) commonInit;
30 | -(void) initBackgroundBlur:(BOOL) blur;
31 | -(void) initThreeDot;
32 | -(void) initAniamtion;
33 | @end
34 | @implementation FeThreeDotGlow
35 |
36 | -(id) initWithView:(UIView *)view blur:(BOOL)blur
37 | {
38 | self = [super initWithFrame:view.bounds];
39 | if (self)
40 | {
41 | _container = view;
42 |
43 | [self commonInit];
44 | [self initBackgroundBlur:blur];
45 | [self initThreeDot];
46 | [self initAniamtion];
47 | }
48 | return self;
49 | }
50 | -(void) commonInit
51 | {
52 | _isShowing = NO;
53 | }
54 | -(void) initBackgroundBlur:(BOOL)blur
55 | {
56 | self.backgroundColor = [UIColor flatWetAsphaltColor];
57 | }
58 | -(void) initThreeDot
59 | {
60 | _arrThreeDots = [[NSMutableArray alloc] initWithCapacity:3];
61 |
62 | _containerDotLayer = [CALayer layer];
63 | _containerDotLayer.frame = CGRectMake(0, 0, 50, 50);
64 | _containerDotLayer.backgroundColor = [UIColor clearColor].CGColor;
65 | _containerDotLayer.position = self.center;
66 |
67 | for (NSInteger i = 0; i < 3; i++)
68 | {
69 | CALayer *dot = [CALayer layer];
70 | CGRect frame;
71 |
72 | switch (i) {
73 | case 0:
74 | {
75 | frame = CGRectMake(15, 0, 20, 20);
76 | break;
77 | }
78 | case 1:
79 | {
80 | frame = CGRectMake(0, 29.5, 20, 20);
81 | break;
82 | }
83 | case 2:
84 | {
85 | frame = CGRectMake(30.5, 29.5, 20, 20);
86 | break;
87 | }
88 | default:
89 | break;
90 | }
91 | dot.frame = frame;
92 | dot.backgroundColor = [UIColor flatCarrotColor].CGColor;
93 | dot.cornerRadius = 10;;
94 | dot.shadowColor = [UIColor flatCarrotColor].CGColor;
95 | dot.shadowOpacity = 1;
96 | dot.shadowOffset = CGSizeMake(0, 0);
97 | dot.shadowRadius = 15;
98 |
99 | [_containerDotLayer addSublayer:dot];
100 | [_arrThreeDots addObject:dot];
101 |
102 | }
103 |
104 | [self.layer addSublayer:_containerDotLayer];
105 | }
106 | -(void) initAniamtion
107 | {
108 | _rotateAnimation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
109 | _rotateAnimation.repeatCount = HUGE_VAL;
110 | _rotateAnimation.fromValue = [NSNumber numberWithFloat:0];
111 | _rotateAnimation.toValue = [NSNumber numberWithFloat:2 * M_PI];
112 | _rotateAnimation.duration = 1.5f;
113 |
114 | _glowAnimation = [CAKeyframeAnimation animationWithKeyPath:@"shadowRadius"];
115 | _glowAnimation.keyTimes = @[[NSNumber numberWithFloat:0.0f],
116 | [NSNumber numberWithFloat:0.5f],
117 | [NSNumber numberWithFloat:1.0f]];
118 | _glowAnimation.values = @[[NSNumber numberWithFloat:5.0f],
119 | [NSNumber numberWithFloat:20.0f],
120 | [NSNumber numberWithFloat:5.0f]];
121 | _glowAnimation.repeatCount = HUGE_VAL;
122 | _glowAnimation.duration = 1.5f;
123 |
124 | _colorGlowAnimation = [CAKeyframeAnimation animationWithKeyPath:@"shadowColor"];
125 | _colorGlowAnimation.keyTimes = @[[NSNumber numberWithFloat:0.0f],
126 | [NSNumber numberWithFloat:0.5f],
127 | [NSNumber numberWithFloat:1.0f]];
128 | _colorGlowAnimation.values = @[(id)[UIColor colorWithHexCode:@"#ff0000"].CGColor,
129 | (id)[UIColor colorWithHexCode:@"#00ff00"].CGColor,
130 | (id)[UIColor colorWithHexCode:@"#ff0000"].CGColor];
131 | _colorGlowAnimation.repeatCount = HUGE_VAL;
132 | _colorGlowAnimation.duration = 1.5f;
133 |
134 | _colorDotAnimation = [CAKeyframeAnimation animationWithKeyPath:@"backgroundColor"];
135 | _colorDotAnimation.keyTimes = @[[NSNumber numberWithFloat:0.0f],
136 | [NSNumber numberWithFloat:0.5f],
137 | [NSNumber numberWithFloat:1.0f]];
138 | _colorDotAnimation.values = @[(id)[UIColor colorWithHexCode:@"#ff0000"].CGColor,
139 | (id)[UIColor colorWithHexCode:@"#00ff00"].CGColor,
140 | (id)[UIColor colorWithHexCode:@"#ff0000"].CGColor];
141 | _colorDotAnimation.repeatCount = HUGE_VAL;
142 | _colorDotAnimation.duration = 1.5f;
143 |
144 | _groupAnimation = [CAAnimationGroup animation];
145 | _groupAnimation.duration = 1.5f;
146 | _groupAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
147 | _groupAnimation.repeatCount = HUGE_VAL;
148 | _groupAnimation.animations = @[_glowAnimation, _colorDotAnimation, _colorGlowAnimation];
149 |
150 | }
151 | -(void) show
152 | {
153 | if (_isShowing)
154 | return;
155 | _isShowing = YES;
156 |
157 | [_containerDotLayer addAnimation:_rotateAnimation forKey:@"transform.rotation"];
158 |
159 | for (CALayer *dot in _arrThreeDots) {
160 | [dot addAnimation:_groupAnimation forKey:@"shadowRadius"];
161 | }
162 | }
163 | -(void) dismiss
164 | {
165 | if (!_isShowing)
166 | return;
167 |
168 | _isShowing = NO;
169 |
170 | // Remove all animations
171 | for (CALayer *dot in _arrThreeDots)
172 | {
173 | [dot removeAllAnimations];
174 | }
175 | [_containerDotLayer removeAllAnimations];
176 | }
177 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
178 | {
179 | [self showWhileExecutingBlock:block completion:nil];
180 | }
181 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
182 | {
183 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
184 |
185 | }
186 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
187 | {
188 | // Check block != nil
189 | if (block != nil)
190 | {
191 | [self show];
192 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
193 | {
194 | block();
195 |
196 | // Update UI
197 | dispatch_async(dispatch_get_main_queue(), ^{
198 | completion();
199 | [self dismiss];
200 | });
201 | });
202 | }
203 | }
204 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
205 | {
206 | // Check Selector is responded
207 | if ([target respondsToSelector:selector])
208 | {
209 | methodForExecuting = selector;
210 | targetForExecuting = target;
211 | objectForExecuting = object;
212 | completionBlock = completion;
213 |
214 | [self show];
215 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
216 | }
217 | }
218 | #pragma mark Helper method
219 | -(void) executingMethod
220 | {
221 | @autoreleasepool {
222 | #pragma clang diagnostic push
223 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
224 | // Start executing the requested task
225 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
226 | #pragma clang diagnostic pop
227 | // Task completed, update view in main thread (note: view operations should
228 | // be done only in the main thread)
229 | dispatch_async(dispatch_get_main_queue(), ^{
230 | completionBlock();
231 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
232 | });
233 |
234 | }
235 | }
236 | -(void) cleanUp
237 | {
238 | NSLog(@"Clean up");
239 | if (objectForExecuting)
240 | objectForExecuting = nil;
241 | if (methodForExecuting)
242 | methodForExecuting = nil;
243 | if (targetForExecuting)
244 | targetForExecuting = nil;
245 | if (completionBlock)
246 | completionBlock = nil;
247 | [self dismiss];
248 | }
249 | @end
250 |
--------------------------------------------------------------------------------
/FeSpinner/FeThreeDotGlowViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeThreeDotGlowViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/4/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeThreeDotGlowViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeThreeDotGlowViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeThreeDotGlowViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 1/4/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeThreeDotGlowViewController.h"
10 | #import "FeThreeDotGlow.h"
11 |
12 | @interface FeThreeDotGlowViewController ()
13 | @property (strong, nonatomic) FeThreeDotGlow *threeDot;
14 | @end
15 |
16 | @implementation FeThreeDotGlowViewController
17 |
18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
19 | {
20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
21 | if (self) {
22 | // Custom initialization
23 | }
24 | return self;
25 | }
26 |
27 | - (void)viewDidLoad
28 | {
29 | [super viewDidLoad];
30 | // Do any additional setup after loading the view.
31 |
32 | _threeDot = [[FeThreeDotGlow alloc] initWithView:self.view blur:NO];
33 | [self.view addSubview:_threeDot];
34 |
35 | // Start
36 | [_threeDot showWhileExecutingBlock:^{
37 | [self myTask];
38 | } completion:^{
39 | [self.navigationController popToRootViewControllerAnimated:YES];
40 | }];
41 | }
42 |
43 | - (void)didReceiveMemoryWarning
44 | {
45 | [super didReceiveMemoryWarning];
46 | // Dispose of any resources that can be recreated.
47 | }
48 | - (void)myTask
49 | {
50 | // Do something usefull in here instead of sleeping ...
51 | sleep(6);
52 | }
53 |
54 | @end
55 |
--------------------------------------------------------------------------------
/FeSpinner/FeVietNamBar.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeVietNamBar.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/30/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeVietNamBar : CALayer
12 | // init Vietnam Bar at index
13 | -(id) initAtIndex:(NSInteger) index colors:(NSArray *) colors;
14 |
15 | // Start animation
16 | -(void) startAnimation;
17 |
18 | // Stop animation
19 | -(void) stopAnimation;
20 | @end
21 | /*
22 | //// General Declarations
23 | CGContextRef context = UIGraphicsGetCurrentContext();
24 |
25 | //// Color Declarations
26 | UIColor* fillColor = [UIColor colorWithRed: 0 green: 0 blue: 0 alpha: 0];
27 | UIColor* color = [UIColor colorWithRed: 0.781 green: 1 blue: 0.343 alpha: 1];
28 | UIColor* color2 = [UIColor colorWithRed: 0.114 green: 0.41 blue: 1 alpha: 1];
29 |
30 | //// Image Declarations
31 | UIImage* vietNamLoader = [UIImage imageNamed: @"vietNamLoader"];
32 | UIColor* vietNamLoaderPattern = [UIColor colorWithPatternImage: vietNamLoader];
33 |
34 | //// VietNamLoader 2 Drawing
35 | UIBezierPath* vietNamLoader2Path = [UIBezierPath bezierPathWithRect: CGRectMake(0, 0, 320, 480)];
36 | CGContextSaveGState(context);
37 | CGContextSetPatternPhase(context, CGSizeMake(0, 0));
38 | [vietNamLoaderPattern setFill];
39 | [vietNamLoader2Path fill];
40 | CGContextRestoreGState(context);
41 |
42 |
43 | //// Rectangle Drawing
44 | UIBezierPath* rectanglePath = [UIBezierPath bezierPathWithRect: CGRectMake(129, 36, 31, 10)];
45 | [fillColor setFill];
46 | [rectanglePath fill];
47 | [color setStroke];
48 | rectanglePath.lineWidth = 1;
49 | [rectanglePath stroke];
50 |
51 |
52 | //// Rectangle 2 Drawing
53 | UIBezierPath* rectangle2Path = [UIBezierPath bezierPathWithRect: CGRectMake(116.5, 48, 61, 10)];
54 | [fillColor setFill];
55 | [rectangle2Path fill];
56 | [color setStroke];
57 | rectangle2Path.lineWidth = 1;
58 | [rectangle2Path stroke];
59 |
60 |
61 | //// Rectangle 3 Drawing
62 | UIBezierPath* rectangle3Path = [UIBezierPath bezierPathWithRect: CGRectMake(84.5, 59.5, 101, 10)];
63 | [fillColor setFill];
64 | [rectangle3Path fill];
65 | [color setStroke];
66 | rectangle3Path.lineWidth = 1;
67 | [rectangle3Path stroke];
68 |
69 |
70 | //// Rectangle 4 Drawing
71 | UIBezierPath* rectangle4Path = [UIBezierPath bezierPathWithRect: CGRectMake(90.5, 71.5, 112, 10)];
72 | [fillColor setFill];
73 | [rectangle4Path fill];
74 | [color setStroke];
75 | rectangle4Path.lineWidth = 1;
76 | [rectangle4Path stroke];
77 |
78 |
79 | //// Rectangle 5 Drawing
80 | UIBezierPath* rectangle5Path = [UIBezierPath bezierPathWithRect: CGRectMake(97.5, 84.5, 88, 10)];
81 | [fillColor setFill];
82 | [rectangle5Path fill];
83 | [color setStroke];
84 | rectangle5Path.lineWidth = 1;
85 | [rectangle5Path stroke];
86 |
87 |
88 | //// Rectangle 6 Drawing
89 | UIBezierPath* rectangle6Path = [UIBezierPath bezierPathWithRect: CGRectMake(123.5, 95.5, 48, 10)];
90 | [fillColor setFill];
91 | [rectangle6Path fill];
92 | [color setStroke];
93 | rectangle6Path.lineWidth = 1;
94 | [rectangle6Path stroke];
95 |
96 |
97 | //// Rectangle 7 Drawing
98 | UIBezierPath* rectangle7Path = [UIBezierPath bezierPathWithRect: CGRectMake(126.5, 107.5, 39, 10)];
99 | [fillColor setFill];
100 | [rectangle7Path fill];
101 | [color setStroke];
102 | rectangle7Path.lineWidth = 1;
103 | [rectangle7Path stroke];
104 |
105 |
106 | //// Rectangle 8 Drawing
107 | UIBezierPath* rectangle8Path = [UIBezierPath bezierPathWithRect: CGRectMake(115.5, 119.5, 39, 10)];
108 | [fillColor setFill];
109 | [rectangle8Path fill];
110 | [color setStroke];
111 | rectangle8Path.lineWidth = 1;
112 | [rectangle8Path stroke];
113 |
114 |
115 | //// Rectangle 9 Drawing
116 | UIBezierPath* rectangle9Path = [UIBezierPath bezierPathWithRect: CGRectMake(128.5, 131.5, 31, 10)];
117 | [fillColor setFill];
118 | [rectangle9Path fill];
119 | [color setStroke];
120 | rectangle9Path.lineWidth = 1;
121 | [rectangle9Path stroke];
122 |
123 |
124 | //// Rectangle 10 Drawing
125 | UIBezierPath* rectangle10Path = [UIBezierPath bezierPathWithRect: CGRectMake(138.5, 144.5, 26, 10)];
126 | [fillColor setFill];
127 | [rectangle10Path fill];
128 | [color setStroke];
129 | rectangle10Path.lineWidth = 1;
130 | [rectangle10Path stroke];
131 |
132 |
133 | //// Rectangle 11 Drawing
134 | UIBezierPath* rectangle11Path = [UIBezierPath bezierPathWithRect: CGRectMake(153.5, 155.5, 21, 10)];
135 | [fillColor setFill];
136 | [rectangle11Path fill];
137 | [color setStroke];
138 | rectangle11Path.lineWidth = 1;
139 | [rectangle11Path stroke];
140 |
141 |
142 | //// Rectangle 12 Drawing
143 | UIBezierPath* rectangle12Path = [UIBezierPath bezierPathWithRect: CGRectMake(162.5, 167.5, 21, 10)];
144 | [fillColor setFill];
145 | [rectangle12Path fill];
146 | [color setStroke];
147 | rectangle12Path.lineWidth = 1;
148 | [rectangle12Path stroke];
149 |
150 |
151 | //// Rectangle 13 Drawing
152 | UIBezierPath* rectangle13Path = [UIBezierPath bezierPathWithRect: CGRectMake(173.5, 178.5, 21, 10)];
153 | [fillColor setFill];
154 | [rectangle13Path fill];
155 | [color setStroke];
156 | rectangle13Path.lineWidth = 1;
157 | [rectangle13Path stroke];
158 |
159 |
160 | //// Rectangle 14 Drawing
161 | UIBezierPath* rectangle14Path = [UIBezierPath bezierPathWithRect: CGRectMake(182.5, 190.5, 22, 10)];
162 | [fillColor setFill];
163 | [rectangle14Path fill];
164 | [color setStroke];
165 | rectangle14Path.lineWidth = 1;
166 | [rectangle14Path stroke];
167 |
168 |
169 | //// Rectangle 15 Drawing
170 | UIBezierPath* rectangle15Path = [UIBezierPath bezierPathWithRect: CGRectMake(188.5, 202.5, 24, 10)];
171 | [fillColor setFill];
172 | [rectangle15Path fill];
173 | [color setStroke];
174 | rectangle15Path.lineWidth = 1;
175 | [rectangle15Path stroke];
176 |
177 |
178 | //// Rectangle 16 Drawing
179 | UIBezierPath* rectangle16Path = [UIBezierPath bezierPathWithRect: CGRectMake(183.5, 214.5, 34, 10)];
180 | [fillColor setFill];
181 | [rectangle16Path fill];
182 | [color setStroke];
183 | rectangle16Path.lineWidth = 1;
184 | [rectangle16Path stroke];
185 |
186 |
187 | //// Rectangle 17 Drawing
188 | UIBezierPath* rectangle17Path = [UIBezierPath bezierPathWithRect: CGRectMake(181.5, 226.5, 42, 10)];
189 | [fillColor setFill];
190 | [rectangle17Path fill];
191 | [color setStroke];
192 | rectangle17Path.lineWidth = 1;
193 | [rectangle17Path stroke];
194 |
195 |
196 | //// Rectangle 18 Drawing
197 | UIBezierPath* rectangle18Path = [UIBezierPath bezierPathWithRect: CGRectMake(184.5, 238.5, 36, 10)];
198 | [fillColor setFill];
199 | [rectangle18Path fill];
200 | [color setStroke];
201 | rectangle18Path.lineWidth = 1;
202 | [rectangle18Path stroke];
203 |
204 |
205 | //// Rectangle 19 Drawing
206 | UIBezierPath* rectangle19Path = [UIBezierPath bezierPathWithRect: CGRectMake(186.5, 250.5, 37, 10)];
207 | [fillColor setFill];
208 | [rectangle19Path fill];
209 | [color setStroke];
210 | rectangle19Path.lineWidth = 1;
211 | [rectangle19Path stroke];
212 |
213 |
214 | //// Rectangle 20 Drawing
215 | UIBezierPath* rectangle20Path = [UIBezierPath bezierPathWithRect: CGRectMake(174.5, 262.5, 47, 10)];
216 | [fillColor setFill];
217 | [rectangle20Path fill];
218 | [color setStroke];
219 | rectangle20Path.lineWidth = 1;
220 | [rectangle20Path stroke];
221 |
222 |
223 | //// Rectangle 21 Drawing
224 | UIBezierPath* rectangle21Path = [UIBezierPath bezierPathWithRect: CGRectMake(153.5, 274.5, 64, 10)];
225 | [fillColor setFill];
226 | [rectangle21Path fill];
227 | [color setStroke];
228 | rectangle21Path.lineWidth = 1;
229 | [rectangle21Path stroke];
230 |
231 |
232 | //// Rectangle 22 Drawing
233 | UIBezierPath* rectangle22Path = [UIBezierPath bezierPathWithRect: CGRectMake(141.5, 286.5, 69, 10)];
234 | [fillColor setFill];
235 | [rectangle22Path fill];
236 | [color setStroke];
237 | rectangle22Path.lineWidth = 1;
238 | [rectangle22Path stroke];
239 |
240 |
241 | //// Rectangle 23 Drawing
242 | UIBezierPath* rectangle23Path = [UIBezierPath bezierPathWithRect: CGRectMake(123.5, 298.5, 71, 10)];
243 | [fillColor setFill];
244 | [rectangle23Path fill];
245 | [color setStroke];
246 | rectangle23Path.lineWidth = 1;
247 | [rectangle23Path stroke];
248 |
249 |
250 | //// Rectangle 24 Drawing
251 | UIBezierPath* rectangle24Path = [UIBezierPath bezierPathWithRect: CGRectMake(127.5, 311.5, 47, 10)];
252 | [fillColor setFill];
253 | [rectangle24Path fill];
254 | [color setStroke];
255 | rectangle24Path.lineWidth = 1;
256 | [rectangle24Path stroke];
257 |
258 |
259 | //// Rectangle 25 Drawing
260 | UIBezierPath* rectangle25Path = [UIBezierPath bezierPathWithRect: CGRectMake(120.5, 324.5, 38, 10)];
261 | [fillColor setFill];
262 | [rectangle25Path fill];
263 | [color setStroke];
264 | rectangle25Path.lineWidth = 1;
265 | [rectangle25Path stroke];
266 |
267 |
268 | //// Rectangle 26 Drawing
269 | UIBezierPath* rectangle26Path = [UIBezierPath bezierPathWithRect: CGRectMake(127.5, 336.5, 20, 10)];
270 | [fillColor setFill];
271 | [rectangle26Path fill];
272 | [color setStroke];
273 | rectangle26Path.lineWidth = 1;
274 | [rectangle26Path stroke];
275 |
276 |
277 | //// Rectangle 27 Drawing
278 | UIBezierPath* rectangle27Path = [UIBezierPath bezierPathWithRect: CGRectMake(266.5, 239.5, 11, 10)];
279 | [color2 setFill];
280 | [rectangle27Path fill];
281 | [color setStroke];
282 | rectangle27Path.lineWidth = 1;
283 | [rectangle27Path stroke];
284 |
285 |
286 | //// Rectangle 28 Drawing
287 | UIBezierPath* rectangle28Path = [UIBezierPath bezierPathWithRect: CGRectMake(266.5, 251.5, 25, 10)];
288 | [color2 setFill];
289 | [rectangle28Path fill];
290 | [color setStroke];
291 | rectangle28Path.lineWidth = 1;
292 | [rectangle28Path stroke];
293 |
294 |
295 | //// Rectangle 29 Drawing
296 | UIBezierPath* rectangle29Path = [UIBezierPath bezierPathWithRect: CGRectMake(259.5, 262.5, 25, 10)];
297 | [color2 setFill];
298 | [rectangle29Path fill];
299 | [color setStroke];
300 | rectangle29Path.lineWidth = 1;
301 | [rectangle29Path stroke];
302 |
303 |
304 | //// Rectangle 30 Drawing
305 | UIBezierPath* rectangle30Path = [UIBezierPath bezierPathWithRect: CGRectMake(236.5, 310.5, 23, 10)];
306 | [color2 setFill];
307 | [rectangle30Path fill];
308 | [color setStroke];
309 | rectangle30Path.lineWidth = 1;
310 | [rectangle30Path stroke];
311 |
312 |
313 | //// Rectangle 31 Drawing
314 | UIBezierPath* rectangle31Path = [UIBezierPath bezierPathWithRect: CGRectMake(230.5, 323.5, 22, 10)];
315 | [color2 setFill];
316 | [rectangle31Path fill];
317 | [color setStroke];
318 | rectangle31Path.lineWidth = 1;
319 | [rectangle31Path stroke];
320 |
321 |
322 |
323 | */
--------------------------------------------------------------------------------
/FeSpinner/FeVietNamLoader.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeVietNamLoader.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/30/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeVietNamLoader : UIView
12 | @property (assign, nonatomic, readonly) BOOL isBlur;
13 | @property (assign, nonatomic,readonly) BOOL isAnimating;
14 | @property (strong, nonatomic, readonly) NSArray *arrColors;
15 | @property (strong, nonatomic) NSString *title;
16 | @property (strong, nonatomic) UIFont *fontTitle;
17 |
18 | -(id) initWithView:(UIView *) view blur:(BOOL) blur color:(NSArray *) arrColors;
19 |
20 | -(void) show;
21 |
22 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
23 |
24 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
25 |
26 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
27 |
28 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
29 |
30 | -(void) dismiss;
31 | @end
32 |
--------------------------------------------------------------------------------
/FeSpinner/FeVietNamLoader.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeVietNamLoader.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/30/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeVietNamLoader.h"
10 | #import "FXBlurView.h"
11 | #import "FeVietNamBar.h"
12 | #import "UIColor+flat.h"
13 |
14 | #define kCountVietNamBar 31
15 |
16 | @interface FeVietNamLoader ()
17 | {
18 | // last position of VietNam Bar
19 | CGPoint lastPosition;
20 |
21 | // Target, method, object and block
22 | id targetForExecuting;
23 | SEL methodForExecuting;
24 | id objectForExecuting;
25 | dispatch_block_t completionBlock;
26 |
27 | }
28 | // Container
29 | @property (weak, nonatomic) UIView *container;
30 |
31 | // Background
32 | @property (strong, nonatomic) FXBlurView *backgroundBlur;
33 | @property (strong, nonatomic) UIView *backgroundStatic;
34 |
35 | // Arr of VietnamBar
36 | @property (strong, nonatomic) NSMutableArray *arrVietNamBars;
37 |
38 | // Label
39 | @property (strong, nonatomic) UILabel *label;
40 |
41 | // init common properties
42 | -(void) commonInit;
43 |
44 | // init Background
45 | -(void) initBackgroundBlur:(BOOL) blur;
46 |
47 | // init VietNamBar
48 | -(void) initVietNamBars;
49 |
50 | // init Label
51 | -(void) initLabel;
52 |
53 | // Reset label's titile with animation
54 | -(void) resetLabel;
55 |
56 | // executing method
57 | -(void) executingMethod;
58 |
59 | // cleanup memory
60 | -(void) cleanUp;
61 | @end
62 | @implementation FeVietNamLoader
63 |
64 | -(id) initWithView:(UIView *)view blur:(BOOL)blur color:(NSArray *)arrColors
65 | {
66 | self =[super initWithFrame:view.bounds];
67 | if (self)
68 | {
69 | // set default properties
70 | _container = view;
71 | _isBlur = blur;
72 | _isAnimating = NO;
73 |
74 | // check arr colors
75 | if (arrColors)
76 | _arrColors = arrColors;
77 | else
78 | {
79 | _arrColors = @[[UIColor flatAlizarinColor],[UIColor flatEmeraldColor],[UIColor flatSunFlowerColor]];
80 | }
81 |
82 | // add subView and hidden;
83 | [_container addSubview:self];
84 | self.hidden = YES;
85 | self.alpha = 0;
86 |
87 | // init common
88 | [self commonInit];
89 |
90 | // init Background
91 | [self initBackgroundBlur:blur];
92 |
93 | // init Vietnam bar
94 | [self initVietNamBars];
95 |
96 | // init Label
97 | [self initLabel];
98 | }
99 | return self;
100 | }
101 | -(void) commonInit
102 | {
103 | _arrVietNamBars = [[NSMutableArray alloc] initWithCapacity:kCountVietNamBar];
104 | }
105 | -(void) initBackgroundBlur:(BOOL)blur
106 | {
107 | if (blur)
108 | {
109 | _backgroundBlur = [[FXBlurView alloc] initWithFrame:_container.bounds];
110 | _backgroundBlur.blurRadius = 40;
111 | _backgroundBlur.tintColor = [UIColor flatWetAsphaltColor];
112 | _backgroundBlur.dynamic = NO;
113 | [_backgroundBlur.layer displayIfNeeded];
114 |
115 | // Hide background
116 | _backgroundBlur.hidden = YES;
117 | }
118 | else
119 | {
120 | _backgroundStatic = [[UIView alloc] initWithFrame:CGRectMake(0, 0, self.bounds.size.width, self.bounds.size.height)];
121 | _backgroundStatic.userInteractionEnabled = NO;
122 | _backgroundStatic.backgroundColor = [UIColor flatWetAsphaltColor];
123 | }
124 | }
125 | -(void) initVietNamBars
126 | {
127 | for (NSInteger i = 1 ; i <= kCountVietNamBar; i++)
128 | {
129 | FeVietNamBar *bar = [[FeVietNamBar alloc ] initAtIndex:i colors:_arrColors];
130 |
131 | [self.layer addSublayer:bar];
132 | [_arrVietNamBars addObject:bar];
133 |
134 | if (i == 26)
135 | {
136 | lastPosition = bar.position;
137 | }
138 | }
139 | }
140 |
141 | -(void) initLabel
142 | {
143 | _label = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 100, 100)];
144 | _label.textAlignment = NSTextAlignmentCenter;
145 | _label.text = @"LOADING";
146 | _label.font = [UIFont fontWithName:@"Neou-Thin" size:36];
147 | _label.textColor = [UIColor whiteColor];
148 |
149 | // Size to fit
150 | [_label sizeToFit];
151 | _label.center = CGPointMake(self.center.x, lastPosition.y + 40);
152 |
153 | [self addSubview:_label];
154 | }
155 | #pragma mark Override setter / getter
156 | -(void) setTitle:(NSString *)title
157 | {
158 | if ([title isEqualToString:_title])
159 | return;
160 |
161 |
162 | // set new titile
163 | _title = title;
164 |
165 | // reset label with animation
166 | [self resetLabel];
167 |
168 | }
169 | -(void) setFontTitle:(UIFont *)fontTitle
170 | {
171 | if (_fontTitle == fontTitle)
172 | return;
173 |
174 | // set new font
175 | _fontTitle = fontTitle;
176 |
177 | // reset with animation
178 | [self resetLabel];
179 | }
180 | -(void) resetLabel
181 | {
182 | if (_isAnimating)
183 | {
184 | // Animation Title label
185 | CATransition *animation = [CATransition animation];
186 | animation.duration = 0.8f;
187 | animation.type = kCATransitionFade;
188 | animation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
189 | [_label.layer addAnimation:animation forKey:@"changeTextTransition"];
190 |
191 | // Change text
192 | _label.font = _fontTitle;
193 | _label.text = _title;
194 |
195 | }
196 | else
197 | {
198 | // Change the text
199 | _label.font = _fontTitle;
200 | _label.text = _title;
201 | }
202 | [_label sizeToFit];
203 |
204 | // set center
205 | _label.center = CGPointMake(self.center.x, lastPosition.y + 40);
206 | }
207 |
208 | #pragma mark Action
209 | -(void) show
210 | {
211 | if (_isAnimating)
212 | return;
213 |
214 | self.hidden = NO;
215 | self.alpha = 0;
216 |
217 | // Add background
218 | if (_isBlur)
219 | {
220 | _backgroundBlur.alpha = 0;
221 | _backgroundBlur.hidden = NO;
222 | [_container insertSubview:_backgroundBlur belowSubview:self];
223 | }
224 | else
225 | {
226 | [self insertSubview:_backgroundStatic atIndex:0];
227 | }
228 |
229 | [UIView animateWithDuration:0.4f
230 | delay:0 options:UIViewAnimationOptionCurveEaseIn
231 | animations:^{
232 | self.alpha = 1;
233 | } completion:^(BOOL finished) {
234 |
235 | _isAnimating = YES;
236 |
237 | for (FeVietNamBar *bar in _arrVietNamBars) {
238 | [bar startAnimation];
239 | }
240 | }];
241 | }
242 | -(void) dismiss
243 | {
244 | if (!_isAnimating)
245 | return;
246 |
247 | // Fade out
248 | // and remove from super view
249 | [UIView animateWithDuration:0.4f delay:0 options:UIViewAnimationOptionCurveEaseIn
250 | animations:^{
251 | self.alpha = 0;
252 | } completion:^(BOOL finished) {
253 | _isAnimating = NO;
254 |
255 | // remove all animation
256 | for (FeVietNamBar *bar in _arrVietNamBars) {
257 | [bar stopAnimation];
258 | }
259 |
260 | [self removeFromSuperview];
261 | }];
262 | }
263 |
264 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
265 | {
266 | [self showWhileExecutingBlock:block completion:nil];
267 | }
268 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
269 | {
270 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
271 |
272 | }
273 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
274 | {
275 | // Check block != nil
276 | if (block != nil)
277 | {
278 | [self show];
279 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
280 | {
281 | block();
282 |
283 | // Update UI
284 | dispatch_async(dispatch_get_main_queue(), ^{
285 | completion();
286 | [self dismiss];
287 | });
288 | });
289 | }
290 | }
291 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
292 | {
293 | // Check Selector is responded
294 | if ([target respondsToSelector:selector])
295 | {
296 | methodForExecuting = selector;
297 | targetForExecuting = target;
298 | objectForExecuting = object;
299 | completionBlock = completion;
300 |
301 | [self show];
302 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
303 | }
304 | }
305 | #pragma mark Helper method
306 | -(void) executingMethod
307 | {
308 | @autoreleasepool {
309 | #pragma clang diagnostic push
310 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
311 | // Start executing the requested task
312 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
313 | #pragma clang diagnostic pop
314 | // Task completed, update view in main thread (note: view operations should
315 | // be done only in the main thread)
316 | dispatch_async(dispatch_get_main_queue(), ^{
317 | completionBlock();
318 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
319 | });
320 |
321 | }
322 | }
323 | -(void) cleanUp
324 | {
325 | NSLog(@"Clean up");
326 | if (objectForExecuting)
327 | objectForExecuting = nil;
328 | if (methodForExecuting)
329 | methodForExecuting = nil;
330 | if (targetForExecuting)
331 | targetForExecuting = nil;
332 | if (completionBlock)
333 | completionBlock = nil;
334 | [self dismiss];
335 | }
336 | @end
337 |
--------------------------------------------------------------------------------
/FeSpinner/FeVietNamLoaderViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeVietNamLoaderViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/30/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeVietNamLoaderViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeVietNamLoaderViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeVietNamLoaderViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 12/30/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeVietNamLoaderViewController.h"
10 | #import "FeVietNamLoader.h"
11 |
12 | @interface FeVietNamLoaderViewController ()
13 | @property (strong, nonatomic) FeVietNamLoader *vietNamLoader;
14 | @end
15 |
16 | @implementation FeVietNamLoaderViewController
17 |
18 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
19 | {
20 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
21 | if (self) {
22 | // Custom initialization
23 | }
24 | return self;
25 | }
26 |
27 | - (void)viewDidLoad
28 | {
29 | [super viewDidLoad];
30 | // Do any additional setup after loading the view.
31 |
32 | _vietNamLoader = [[FeVietNamLoader alloc] initWithView:self.view blur:NO color:nil];
33 | [self.view addSubview:_vietNamLoader];
34 |
35 | // Start
36 | [_vietNamLoader showWhileExecutingBlock:^{
37 | [self myTask];
38 | } completion:^{
39 | [self.navigationController popToRootViewControllerAnimated:YES];
40 | }];
41 | }
42 |
43 | - (void)didReceiveMemoryWarning
44 | {
45 | [super didReceiveMemoryWarning];
46 | // Dispose of any resources that can be recreated.
47 | }
48 |
49 | - (void)myTask
50 | {
51 | // Do something usefull in here instead of sleeping ...
52 | sleep(6);
53 | }
54 |
55 | @end
56 |
--------------------------------------------------------------------------------
/FeSpinner/FeViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/20/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/20/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import "FeViewController.h"
10 | #import "FXBlurView.h"
11 | #import "UIColor+flat.h"
12 | #import "FeSpinnerTenDot.h"
13 |
14 | @interface FeViewController ()
15 | @property (strong, nonatomic) FeSpinnerTenDot *spinnerTenDot;
16 | @property (weak, nonatomic) IBOutlet UIView *containerView;
17 | - (IBAction)start:(id)sender;
18 | - (IBAction)stop:(id)sender;
19 |
20 | @end
21 |
22 | @implementation FeViewController
23 |
24 | - (void)viewDidLoad
25 | {
26 | [super viewDidLoad];
27 | // Do any additional setup after loading the view, typically from a nib.
28 |
29 |
30 | _spinnerTenDot = [[FeSpinnerTenDot alloc] initWithView:_containerView withBlur:YES];
31 | _spinnerTenDot.titleLabelText = @"LOADING";
32 | _spinnerTenDot.fontTitleLabel = [UIFont fontWithName:@"Neou-Thin" size:22];
33 | }
34 |
35 | - (void)didReceiveMemoryWarning
36 | {
37 | [super didReceiveMemoryWarning];
38 | // Dispose of any resources that can be recreated.
39 | }
40 |
41 | - (IBAction)start:(id)sender
42 | {
43 |
44 | [_spinnerTenDot show];
45 | }
46 | - (void)performBlock:(void(^)())block afterDelay:(NSTimeInterval)delay
47 | {
48 | dispatch_time_t popTime = dispatch_time(DISPATCH_TIME_NOW, (int64_t)(delay * NSEC_PER_SEC));
49 | dispatch_after(popTime, dispatch_get_main_queue(), block);
50 | }
51 |
52 | - (IBAction)stop:(id)sender
53 | {
54 | [_spinnerTenDot dismiss];
55 | //_spinnerTenDot.titleLabelText = @"Plz waiting";
56 | }
57 | @end
58 |
--------------------------------------------------------------------------------
/FeSpinner/FeWifiManHub.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeWifiManHub.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 5/28/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 | typedef NS_ENUM(NSInteger, FeWifiManHubMode){
11 | FeWifiManHubModeOnlyLoader,
12 | FeWifiManHubModeOnlyPercent
13 | };
14 | @interface FeWifiManHub : UIView
15 |
16 | @property (assign, readonly, nonatomic) BOOL isAnimate;
17 | @property (assign, nonatomic) CGFloat percent;
18 | @property (assign, readonly, nonatomic) FeWifiManHubMode currentMode;
19 |
20 | -(id) initWithView:(UIView *) view withMode:(FeWifiManHubMode) mode;
21 |
22 | -(void) show;
23 |
24 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
25 |
26 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
27 |
28 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
29 |
30 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
31 |
32 | -(void) dismiss;
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/FeSpinner/FeWifiManHub.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeWifiManHub.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 5/28/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeWifiManHub.h"
10 | #define kFe_WifiMan_Width 85.0f
11 | #define kFe_WifiMan_Height 85.0f
12 |
13 | @interface FeWifiManHub ()
14 | {
15 | // Target, method, object and block
16 | id targetForExecuting;
17 | SEL methodForExecuting;
18 | id objectForExecuting;
19 | dispatch_block_t completionBlock;
20 | }
21 | @property (strong, nonatomic) UIImageView *wifimanImageView_colored;
22 | @property (strong, nonatomic) UIImageView *wifiManImageView_grayScale;
23 | @property (strong, nonatomic) CALayer *contentLayer;
24 |
25 | @property (strong, nonatomic) UILabel *titleLbl;
26 | @property (strong, nonatomic) UILabel *subTitleLbl;
27 |
28 | // Mask
29 | @property (strong, nonatomic) CALayer *maskLayer;
30 |
31 | // Window
32 | @property (weak, nonatomic) UIView *containerView;
33 |
34 | -(void) initCommon;
35 | -(void) initWifimanImageView;
36 | -(void) initMaskLayer;
37 | -(void) initTitle;
38 | -(void) initWifiManHub;
39 | @end
40 | @implementation FeWifiManHub
41 |
42 | -(id) initWithView:(UIView *)view withMode:(FeWifiManHubMode)mode
43 | {
44 | self = [super init];
45 | if (self)
46 | {
47 | _containerView = view;
48 | self.frame = CGRectMake(0, 0, 181, 147);
49 | self.center = view.center;
50 | _currentMode = mode;
51 |
52 | self.hidden = YES;
53 |
54 | [self initCommon];
55 |
56 | [self initTitle];
57 |
58 | if (_currentMode == FeWifiManHubModeOnlyPercent)
59 | {
60 | [self initWifimanImageView];
61 |
62 | [self initMaskLayer];
63 | }
64 | else
65 | {
66 | [self initWifiManHub];
67 | }
68 | }
69 | return self;
70 | }
71 | -(void) initCommon
72 | {
73 | _isAnimate = NO;
74 | self.backgroundColor = [UIColor colorWithWhite:0 alpha:0.8f];
75 | self.layer.cornerRadius = 10.0f;
76 | self.clipsToBounds = YES;
77 | }
78 | -(void) initWifimanImageView
79 | {
80 | CGRect frame = CGRectMake(48, 12, kFe_WifiMan_Width, kFe_WifiMan_Height);
81 | UIImage *imageColored = [UIImage imageNamed:@"wifimanhub"];
82 | UIImage *imageGray = [UIImage imageNamed:@"wifimanhub_grayscale"];
83 |
84 | // Colored
85 | _wifimanImageView_colored = [[UIImageView alloc] initWithFrame:frame];
86 | _wifimanImageView_colored.image = imageColored;
87 |
88 | // Gray
89 | _wifiManImageView_grayScale = [[UIImageView alloc] initWithFrame:frame];
90 | _wifiManImageView_grayScale.image = imageGray;
91 |
92 | [self addSubview:_wifiManImageView_grayScale];
93 | [self addSubview:_wifimanImageView_colored];
94 | }
95 | -(void) initTitle
96 | {
97 | // Title
98 | _titleLbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 88, 181, 31)];
99 | _titleLbl.text = @"Đang tải";
100 | _titleLbl.font = [UIFont boldSystemFontOfSize:17];
101 | _titleLbl.backgroundColor = [UIColor clearColor];
102 | _titleLbl.textAlignment = NSTextAlignmentCenter;
103 | _titleLbl.textColor = [UIColor whiteColor];
104 |
105 | // Sub
106 | _subTitleLbl = [[UILabel alloc] initWithFrame:CGRectMake(0, 110, 181, 31)];
107 | _subTitleLbl.text = @"Vui lòng chờ trong giây lát...";
108 | _subTitleLbl.font = [UIFont systemFontOfSize:12];
109 | _subTitleLbl.backgroundColor = [UIColor clearColor];
110 | _subTitleLbl.textAlignment = NSTextAlignmentCenter;
111 | _subTitleLbl.textColor = [UIColor whiteColor];
112 |
113 | [self addSubview:_titleLbl];
114 | [self addSubview:_subTitleLbl];
115 | }
116 | -(void) initMaskLayer
117 | {
118 | _maskLayer = [CALayer layer];
119 | _maskLayer.frame = CGRectMake(0, 0, kFe_WifiMan_Width, kFe_WifiMan_Height);
120 | _maskLayer.backgroundColor = [UIColor whiteColor].CGColor;
121 | _maskLayer.anchorPoint = CGPointMake(0, 0);
122 | _maskLayer.position = CGPointMake(0,kFe_WifiMan_Height);
123 |
124 | _wifimanImageView_colored.layer.mask = _maskLayer;
125 | }
126 | -(void) initWifiManHub
127 | {
128 | CGRect frame = CGRectMake(48, 12, kFe_WifiMan_Width, kFe_WifiMan_Height);
129 | UIImage *imageColored = [UIImage imageNamed:@"WifiMan_Sign_1"];
130 |
131 | /*
132 | // Colored
133 | _wifimanImageView_colored = [[UIImageView alloc] initWithFrame:frame];
134 | _wifimanImageView_colored.image = imageColored;
135 | [self addSubview:_wifimanImageView_colored];
136 | */
137 |
138 | _contentLayer = [CALayer layer];
139 | _contentLayer.frame = frame;
140 | _contentLayer.backgroundColor = [UIColor clearColor].CGColor;
141 | _contentLayer.contents = (id)imageColored.CGImage;
142 | [self.layer addSublayer:_contentLayer];
143 | }
144 | #pragma mark Action
145 | -(void) show
146 | {
147 | if (_isAnimate)
148 | return;
149 |
150 | _isAnimate = YES;
151 | self.hidden = NO;
152 | CAKeyframeAnimation *anim = [CAKeyframeAnimation animationWithKeyPath:@"contents"];
153 | NSArray *times = [NSArray arrayWithObjects:[NSNumber numberWithFloat:0.0], [NSNumber numberWithFloat:0.25], [NSNumber numberWithFloat:0.5], [NSNumber numberWithFloat:0.75],[NSNumber numberWithFloat:1.0f], nil];
154 | [anim setKeyTimes:times];
155 |
156 | UIImage *image_1 = [UIImage imageNamed:@"WifiMan_Sign_1"];
157 | UIImage *image_2 = [UIImage imageNamed:@"WifiMan_Sign_2"];
158 | UIImage *image_3 = [UIImage imageNamed:@"WifiMan_Sign_3"];
159 | UIImage *image_4 = [UIImage imageNamed:@"WifiMan_Sign_4"];
160 |
161 | NSArray *values = @[(id)image_1.CGImage,(id)image_2.CGImage,(id)image_3.CGImage,(id)image_4.CGImage,(id)image_1.CGImage];
162 |
163 | [anim setValues:values];
164 | [anim setDuration:3.0f];
165 | [anim setKeyTimes:times];
166 | anim.repeatCount = MAXFLOAT;
167 |
168 | [_contentLayer addAnimation:anim forKey:@"content"];
169 |
170 | }
171 | -(void) dismiss
172 | {
173 | if (!_isAnimate)
174 | return;
175 |
176 | [self removeFromSuperview];
177 | _isAnimate = NO;
178 | }
179 |
180 | -(void) showWhileExecutingBlock:(dispatch_block_t)block
181 | {
182 | [self showWhileExecutingBlock:block completion:nil];
183 | }
184 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object
185 | {
186 | [self showWhileExecutingSelector:selector onTarget:target withObject:object completion:nil];
187 |
188 | }
189 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t)completion
190 | {
191 | // Check block != nil
192 | if (block != nil)
193 | {
194 | [self show];
195 | dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0), ^
196 | {
197 | block();
198 |
199 | // Update UI
200 | dispatch_async(dispatch_get_main_queue(), ^{
201 | completion();
202 | [self dismiss];
203 | });
204 | });
205 | }
206 | }
207 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t)completion
208 | {
209 | // Check Selector is responded
210 | if ([target respondsToSelector:selector])
211 | {
212 | methodForExecuting = selector;
213 | targetForExecuting = target;
214 | objectForExecuting = object;
215 | completionBlock = completion;
216 |
217 | [self show];
218 | [NSThread detachNewThreadSelector:@selector(executingMethod) toTarget:self withObject:nil];
219 | }
220 | }
221 | #pragma mark Helper method
222 | -(void) executingMethod
223 | {
224 | @autoreleasepool {
225 | #pragma clang diagnostic push
226 | #pragma clang diagnostic ignored "-Warc-performSelector-leaks"
227 | // Start executing the requested task
228 | [targetForExecuting performSelector:methodForExecuting withObject:objectForExecuting];
229 | #pragma clang diagnostic pop
230 | // Task completed, update view in main thread (note: view operations should
231 | // be done only in the main thread)
232 | dispatch_async(dispatch_get_main_queue(), ^{
233 | completionBlock();
234 | [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
235 | });
236 |
237 | }
238 | }
239 | -(void) cleanUp
240 | {
241 | NSLog(@"Clean up");
242 | if (objectForExecuting)
243 | objectForExecuting = nil;
244 | if (methodForExecuting)
245 | methodForExecuting = nil;
246 | if (targetForExecuting)
247 | targetForExecuting = nil;
248 | if (completionBlock)
249 | completionBlock = nil;
250 | [self dismiss];
251 | }
252 | -(void) setPercent:(CGFloat)percent
253 | {
254 | if (_percent == percent)
255 | return;
256 |
257 | if (percent < 0 || percent > 1 || _currentMode != FeWifiManHubModeOnlyPercent)
258 | return;
259 |
260 | _percent = percent;
261 |
262 | // Update on Main queue
263 | dispatch_async(dispatch_get_main_queue(), ^{
264 | CGFloat denta = _percent * kFe_WifiMan_Height;
265 | _maskLayer.position = CGPointMake(0, kFe_WifiMan_Height - denta);
266 | });
267 |
268 |
269 | }
270 | @end
271 |
--------------------------------------------------------------------------------
/FeSpinner/FeWifiManHub.xib:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
28 |
35 |
36 |
37 |
38 |
39 |
40 |
41 |
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
51 |
--------------------------------------------------------------------------------
/FeSpinner/FeWifiManViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeWifiManViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 5/28/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeWifiManViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeWifiManViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeWifiManViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 5/28/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeWifiManViewController.h"
10 | #import "FeWifiManHub.h"
11 |
12 | @interface FeWifiManViewController ()
13 | @property (strong, nonatomic) FeWifiManHub *wifiManHubLoader;
14 | @property (strong, nonatomic) FeWifiManHub *wifiManHubPercent;
15 |
16 | @end
17 |
18 | @implementation FeWifiManViewController
19 |
20 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
21 | {
22 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
23 | if (self) {
24 | // Custom initialization
25 | }
26 | return self;
27 | }
28 |
29 | - (void)viewDidLoad
30 | {
31 | [super viewDidLoad];
32 | // Do any additional setup after loading the view.
33 |
34 | // Loader
35 |
36 |
37 | _wifiManHubLoader = [[FeWifiManHub alloc] initWithView:self.view withMode:FeWifiManHubModeOnlyLoader];
38 | [self.navigationController.view addSubview:_wifiManHubLoader];
39 |
40 | [_wifiManHubLoader showWhileExecutingBlock:^{
41 | [self myTask];
42 | } completion:^{
43 | NSLog(@"Completion");
44 |
45 | [self.navigationController popToRootViewControllerAnimated:YES];
46 | }];
47 |
48 |
49 | /*
50 | // Percent
51 | _wifiManHubPercent = [[FeWifiManHub alloc] initWithView:self.view withMode:FeWifiManHubModeOnlyPercent];
52 | [self.navigationController.view addSubview:_wifiManHubPercent];
53 |
54 | [_wifiManHubPercent showWhileExecutingBlock:^{
55 | [self myProgressTask];
56 | } completion:^{
57 | NSLog(@"Completion");
58 |
59 |
60 | }];
61 | */
62 |
63 | }
64 |
65 | - (void)didReceiveMemoryWarning
66 | {
67 | [super didReceiveMemoryWarning];
68 | // Dispose of any resources that can be recreated.
69 | }
70 | - (void)myProgressTask
71 | {
72 | // This just increases the progress indicator in a loop
73 | float progress = 0.0f;
74 | while (progress < 1.0f) {
75 | progress += 0.01f;
76 | NSLog(@"percent = %.2f",progress);\
77 |
78 | // Set percent
79 | _wifiManHubPercent.percent = progress;
80 | usleep(30000);
81 | }
82 | }
83 |
84 | - (void)myTask
85 | {
86 | // Do something usefull in here instead of sleeping ...
87 | sleep(6);
88 | }
89 | -(void) stopLoader
90 | {
91 |
92 | }
93 | @end
94 |
--------------------------------------------------------------------------------
/FeSpinner/FeZeroLoader.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeZeroLoader.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/17/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeZeroLoader : UIView
12 |
13 | // is running
14 | @property (assign, readonly, nonatomic) BOOL isShowing;
15 |
16 | -(instancetype) initWithView:(UIView *) view title:(NSString *) title;
17 |
18 | -(void) show;
19 |
20 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
21 |
22 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
23 |
24 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
25 |
26 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
27 |
28 | -(void) dismiss;
29 |
30 | @end
31 |
--------------------------------------------------------------------------------
/FeSpinner/FeZeroLoader.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeZeroLoader.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/17/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeZeroLoader.h"
10 | #import "UIColor+flat.h"
11 |
12 | #define CATransform3DPerspective(t, x, y) (CATransform3DConcat(t, CATransform3DMake(1, 0, 0, x, 0, 1, 0, y, 0, 0, 1, 0, 0, 0, 0, 1)))
13 | #define CATransform3DMakePerspective(x, y) (CATransform3DPerspective(CATransform3DIdentity, x, y))
14 |
15 | CG_INLINE CATransform3D
16 | CATransform3DMake(CGFloat m11, CGFloat m12, CGFloat m13, CGFloat m14,
17 | CGFloat m21, CGFloat m22, CGFloat m23, CGFloat m24,
18 | CGFloat m31, CGFloat m32, CGFloat m33, CGFloat m34,
19 | CGFloat m41, CGFloat m42, CGFloat m43, CGFloat m44)
20 | {
21 | CATransform3D t;
22 | t.m11 = m11; t.m12 = m12; t.m13 = m13; t.m14 = m14;
23 | t.m21 = m21; t.m22 = m22; t.m23 = m23; t.m24 = m24;
24 | t.m31 = m31; t.m32 = m32; t.m33 = m33; t.m34 = m34;
25 | t.m41 = m41; t.m42 = m42; t.m43 = m43; t.m44 = m44;
26 | return t;
27 | }
28 |
29 | #define DEGREES_TO_RADIANS(angle) ((angle) / 180.0 * M_PI)
30 |
31 | @interface FeZeroLoader ()
32 | // Container View
33 | @property (weak, nonatomic) UIView *containerView;
34 |
35 | // Container Layer
36 | @property (strong, nonatomic) CALayer *containerLayer;
37 |
38 | // Bars
39 | @property (strong, nonatomic) CALayer *topBar;
40 | @property (strong, nonatomic) CALayer *middleBar;
41 | @property (strong, nonatomic) CALayer *bottombar;
42 |
43 | -(void) initCommon;
44 | -(void) initContainer;
45 | -(void) initBars;
46 | @end
47 |
48 | @implementation FeZeroLoader
49 |
50 | -(instancetype) initWithView:(UIView *)view title:(NSString *)title
51 | {
52 | self = [super init];
53 | if (self)
54 | {
55 | _containerView = view;
56 |
57 | [self initCommon];
58 |
59 | [self initContainer];
60 |
61 | [self initBars];
62 | }
63 | return self;
64 | }
65 |
66 | -(void) initCommon
67 | {
68 | self.frame = CGRectMake(0, 0, _containerView.bounds.size.width, _containerView.bounds.size.height);
69 | self.backgroundColor = [UIColor colorWithHexCode:@"#282828"];
70 | }
71 | -(void) initContainer
72 | {
73 | _containerLayer = [CALayer layer];
74 | _containerLayer.backgroundColor = [UIColor blackColor].CGColor;
75 | _containerLayer.frame = CGRectMake(0, 0, 100, 100);
76 | _containerLayer.anchorPoint = CGPointMake(0.5f, 0.5f);
77 | _containerLayer.position = CGPointMake(self.bounds.size.width / 2, self.bounds.size.height / 2);
78 |
79 | [self.layer addSublayer:_containerLayer];
80 | }
81 | -(void) initBars
82 | {
83 | float theta = -15.0f;
84 | CGAffineTransform t = CGAffineTransformIdentity;
85 | t.b = tan(theta*M_PI/180.0f);
86 |
87 | // First
88 | _topBar = [CALayer layer];
89 | _topBar.frame = CGRectMake(20, 0, 53, 20);
90 | _topBar.transform = CATransform3DMakeAffineTransform(t);
91 | _topBar.backgroundColor = [UIColor whiteColor].CGColor;
92 |
93 | [_containerLayer addSublayer:_topBar];
94 |
95 | }
96 | -(void) show
97 | {
98 |
99 | }
100 | @end
101 |
--------------------------------------------------------------------------------
/FeSpinner/FeZeroLoaderViewController.h:
--------------------------------------------------------------------------------
1 | //
2 | // FeZeroLoaderViewController.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/17/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeZeroLoaderViewController : UIViewController
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/FeZeroLoaderViewController.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeZeroLoaderViewController.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 8/17/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "FeZeroLoaderViewController.h"
10 | #import "FeZeroLoader.h"
11 |
12 | @interface FeZeroLoaderViewController ()
13 |
14 | @property (strong, nonatomic) FeZeroLoader *zeroLoader;
15 |
16 | @end
17 |
18 | @implementation FeZeroLoaderViewController
19 |
20 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
21 | {
22 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
23 | if (self) {
24 | // Custom initialization
25 | }
26 | return self;
27 | }
28 |
29 | - (void)viewDidLoad
30 | {
31 | [super viewDidLoad];
32 | // Do any additional setup after loading the view.
33 |
34 | _zeroLoader = [[FeZeroLoader alloc] initWithView:self.view title:@"Loading"];
35 | [self.view addSubview:_zeroLoader];
36 |
37 | [_zeroLoader show];
38 | }
39 |
40 | - (void)didReceiveMemoryWarning
41 | {
42 | [super didReceiveMemoryWarning];
43 | // Dispose of any resources that can be recreated.
44 | }
45 |
46 |
47 | @end
48 |
--------------------------------------------------------------------------------
/FeSpinner/Feasd.h:
--------------------------------------------------------------------------------
1 | //
2 | // Feasd.h
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 5/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface Feasd : UIView
12 |
13 | @end
14 |
--------------------------------------------------------------------------------
/FeSpinner/Feasd.m:
--------------------------------------------------------------------------------
1 | //
2 | // Feasd.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 5/14/14.
6 | // Copyright (c) 2014 fe. All rights reserved.
7 | //
8 |
9 | #import "Feasd.h"
10 |
11 | @implementation Feasd
12 |
13 | - (id)initWithFrame:(CGRect)frame
14 | {
15 | self = [super initWithFrame:frame];
16 | if (self) {
17 | // Initialization code
18 | }
19 | return self;
20 | }
21 |
22 | /*
23 | // Only override drawRect: if you perform custom drawing.
24 | // An empty implementation adversely affects performance during animation.
25 | - (void)drawRect:(CGRect)rect
26 | {
27 | // Drawing code
28 | }
29 | */
30 |
31 | @end
32 |
--------------------------------------------------------------------------------
/FeSpinner/Images.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" : "40x40",
11 | "scale" : "2x"
12 | },
13 | {
14 | "idiom" : "iphone",
15 | "size" : "60x60",
16 | "scale" : "2x"
17 | },
18 | {
19 | "idiom" : "ipad",
20 | "size" : "29x29",
21 | "scale" : "1x"
22 | },
23 | {
24 | "idiom" : "ipad",
25 | "size" : "29x29",
26 | "scale" : "2x"
27 | },
28 | {
29 | "idiom" : "ipad",
30 | "size" : "40x40",
31 | "scale" : "1x"
32 | },
33 | {
34 | "idiom" : "ipad",
35 | "size" : "40x40",
36 | "scale" : "2x"
37 | },
38 | {
39 | "idiom" : "ipad",
40 | "size" : "76x76",
41 | "scale" : "1x"
42 | },
43 | {
44 | "idiom" : "ipad",
45 | "size" : "76x76",
46 | "scale" : "2x"
47 | }
48 | ],
49 | "info" : {
50 | "version" : 1,
51 | "author" : "xcode"
52 | }
53 | }
--------------------------------------------------------------------------------
/FeSpinner/Images.xcassets/LaunchImage.launchimage/Contents.json:
--------------------------------------------------------------------------------
1 | {
2 | "images" : [
3 | {
4 | "orientation" : "portrait",
5 | "idiom" : "iphone",
6 | "extent" : "full-screen",
7 | "minimum-system-version" : "7.0",
8 | "scale" : "2x"
9 | },
10 | {
11 | "orientation" : "portrait",
12 | "idiom" : "iphone",
13 | "subtype" : "retina4",
14 | "extent" : "full-screen",
15 | "minimum-system-version" : "7.0",
16 | "scale" : "2x"
17 | },
18 | {
19 | "orientation" : "portrait",
20 | "idiom" : "ipad",
21 | "extent" : "full-screen",
22 | "minimum-system-version" : "7.0",
23 | "scale" : "1x"
24 | },
25 | {
26 | "orientation" : "landscape",
27 | "idiom" : "ipad",
28 | "extent" : "full-screen",
29 | "minimum-system-version" : "7.0",
30 | "scale" : "1x"
31 | },
32 | {
33 | "orientation" : "portrait",
34 | "idiom" : "ipad",
35 | "extent" : "full-screen",
36 | "minimum-system-version" : "7.0",
37 | "scale" : "2x"
38 | },
39 | {
40 | "orientation" : "landscape",
41 | "idiom" : "ipad",
42 | "extent" : "full-screen",
43 | "minimum-system-version" : "7.0",
44 | "scale" : "2x"
45 | }
46 | ],
47 | "info" : {
48 | "version" : 1,
49 | "author" : "xcode"
50 | }
51 | }
--------------------------------------------------------------------------------
/FeSpinner/Neou-Thin.ttf:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/Neou-Thin.ttf
--------------------------------------------------------------------------------
/FeSpinner/UIColor+flat.h:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+flat.h
3 | // SaiGonRain
4 | //
5 | // Created by Bang Nguyen on 26/09/2013.
6 | // Copyright (c) 2013 Bang Nguyen. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface UIColor (flat)
12 |
13 | + (UIColor*)flatTurquoiseColor;
14 | + (UIColor*)flatGreenSeaColor;
15 | + (UIColor*)flatEmeraldColor;
16 | + (UIColor*)flatNephritisColor;
17 | + (UIColor*)flatPeterRiverColor;
18 | + (UIColor*)flatBelizeHoleColor;
19 | + (UIColor*)flatAmethystColor;
20 | + (UIColor*)flatWisteriaColor;
21 | + (UIColor*)flatWetAsphaltColor;
22 | + (UIColor*)flatMidNightColor;
23 | + (UIColor*)flatSunFlowerColor;
24 | + (UIColor*)flatOrangeColor;
25 | + (UIColor*)flatCarrotColor;
26 | + (UIColor*)flatPumpkinColor;
27 | + (UIColor*)flatAlizarinColor;
28 | + (UIColor*)flatPomegranateColor;
29 | + (UIColor*)flatCloudColor;
30 | + (UIColor*)flatSilverColor;
31 | + (UIColor*)flatConcreteColor;
32 | + (UIColor*)flatAsbestosColor;
33 |
34 | +(UIColor *) colorWithHexCode:(NSString *)hexCode;
35 |
36 | @end
37 |
--------------------------------------------------------------------------------
/FeSpinner/UIColor+flat.m:
--------------------------------------------------------------------------------
1 | //
2 | // UIColor+flat.m
3 | // SaiGonRain
4 | //
5 | // Created by Bang Nguyen on 26/09/2013.
6 | // Copyright (c) 2013 Bang Nguyen. All rights reserved.
7 | //
8 |
9 | #import "UIColor+flat.h"
10 |
11 | @implementation UIColor (flat)
12 |
13 | + (UIColor*)flatTurquoiseColor {
14 | return [UIColor colorWithRed:26.0f/255.0f
15 | green:188.0f/255.0f
16 | blue:156.0f/255.0f
17 | alpha:1.0f];
18 | }
19 |
20 | + (UIColor*)flatGreenSeaColor {
21 | return [UIColor colorWithRed:22.0f/255.0f
22 | green:160.0f/255.0f
23 | blue:133.0f/255.0f
24 | alpha:1.0f];
25 | }
26 |
27 | + (UIColor*)flatEmeraldColor {
28 | return [UIColor colorWithRed:46.0f/255.0f
29 | green:204.0f/255.0f
30 | blue:113.0f/255.0f
31 | alpha:1.0f];
32 | }
33 |
34 | + (UIColor*)flatNephritisColor {
35 | return [UIColor colorWithRed:39.0f/255.0f
36 | green:174.0f/255.0f
37 | blue:96.0f/255.0f
38 | alpha:1.0f];
39 | }
40 |
41 | + (UIColor*)flatPeterRiverColor {
42 | return [UIColor colorWithRed:52.0f/255.0f
43 | green:152.0f/255.0f
44 | blue:219.0f/255.0f
45 | alpha:1.0f];
46 | }
47 |
48 | + (UIColor*)flatBelizeHoleColor {
49 | return [UIColor colorWithRed:41.0f/255.0f
50 | green:128.0f/255.0f
51 | blue:185.0f/255.0f
52 | alpha:1.0f];
53 | }
54 |
55 | + (UIColor*)flatAmethystColor {
56 | return [UIColor colorWithRed:155.0f/255.0f
57 | green:89.0f/255.0f
58 | blue:182.0f/255.0f
59 | alpha:1.0f];
60 | }
61 |
62 | + (UIColor*)flatWisteriaColor {
63 | return [UIColor colorWithRed:142.0f/255.0f
64 | green:68.0f/255.0f
65 | blue:173.0f/255.0f
66 | alpha:1.0f];
67 | }
68 |
69 | + (UIColor*)flatWetAsphaltColor {
70 | return [UIColor colorWithRed:52.0f/255.0f
71 | green:73.0f/255.0f
72 | blue:94.0f/255.0f
73 | alpha:1.0f];
74 | }
75 |
76 | + (UIColor*)flatMidNightColor {
77 | return [UIColor colorWithRed:44.0f/255.0f
78 | green:62.0f/255.0f
79 | blue:80.0f/255.0f
80 | alpha:1.0f];
81 | }
82 |
83 | + (UIColor*)flatSunFlowerColor {
84 | return [UIColor colorWithRed:241.0f/255.0f
85 | green:196.0f/255.0f
86 | blue:15.0f/255.0f
87 | alpha:1.0f];
88 | }
89 |
90 | + (UIColor*)flatOrangeColor {
91 | return [UIColor colorWithRed:243.0f/255.0f
92 | green:156.0f/255.0f
93 | blue:18.0f/255.0f
94 | alpha:1.0f];
95 | }
96 |
97 | + (UIColor*)flatCarrotColor {
98 | return [UIColor colorWithRed:230.0f/255.0f
99 | green:126.0f/255.0f
100 | blue:34.0f/255.0f
101 | alpha:1.0f];
102 | }
103 |
104 | + (UIColor*)flatPumpkinColor {
105 | return [UIColor colorWithRed:211.0f/255.0f
106 | green:84.0f/255.0f
107 | blue:0.0f/255.0f
108 | alpha:1.0f];
109 | }
110 |
111 | + (UIColor*)flatAlizarinColor {
112 | return [UIColor colorWithRed:231.0f/255.0f
113 | green:76.0f/255.0f
114 | blue:60.0f/255.0f
115 | alpha:1.0f];
116 | }
117 |
118 | + (UIColor*)flatPomegranateColor {
119 | return [UIColor colorWithRed:192.0f/255.0f
120 | green:57.0f/255.0f
121 | blue:43.0f/255.0f
122 | alpha:1.0f];
123 | }
124 |
125 | + (UIColor*)flatCloudColor {
126 | return [UIColor colorWithRed:236.0f/255.0f
127 | green:240.0f/255.0f
128 | blue:241.0f/255.0f
129 | alpha:1.0f];
130 | }
131 |
132 | + (UIColor*)flatSilverColor {
133 | return [UIColor colorWithRed:189.0f/255.0f
134 | green:195.0f/255.0f
135 | blue:199.0f/255.0f
136 | alpha:1.0f];
137 | }
138 |
139 | + (UIColor*)flatConcreteColor {
140 | return [UIColor colorWithRed:149.0f/255.0f
141 | green:165.0f/255.0f
142 | blue:166.0f/255.0f
143 | alpha:1.0f];
144 | }
145 |
146 | + (UIColor*)flatAsbestosColor {
147 | return [UIColor colorWithRed:127.0f/255.0f
148 | green:140.0f/255.0f
149 | blue:141.0f/255.0f
150 | alpha:1.0f];
151 | }
152 |
153 | +(UIColor *) colorWithHexCode:(NSString *)hexCode
154 | {
155 | NSString *cleanString = [hexCode stringByReplacingOccurrencesOfString:@"#" withString:@""];
156 | if([cleanString length] == 3) {
157 | cleanString = [NSString stringWithFormat:@"%@%@%@%@%@%@",
158 | [cleanString substringWithRange:NSMakeRange(0, 1)],[cleanString substringWithRange:NSMakeRange(0, 1)],
159 | [cleanString substringWithRange:NSMakeRange(1, 1)],[cleanString substringWithRange:NSMakeRange(1, 1)],
160 | [cleanString substringWithRange:NSMakeRange(2, 1)],[cleanString substringWithRange:NSMakeRange(2, 1)]];
161 | }
162 | if([cleanString length] == 6) {
163 | cleanString = [cleanString stringByAppendingString:@"ff"];
164 | }
165 |
166 | unsigned int baseValue;
167 | [[NSScanner scannerWithString:cleanString] scanHexInt:&baseValue];
168 |
169 | float red = ((baseValue >> 24) & 0xFF)/255.0f;
170 | float green = ((baseValue >> 16) & 0xFF)/255.0f;
171 | float blue = ((baseValue >> 8) & 0xFF)/255.0f;
172 | float alpha = ((baseValue >> 0) & 0xFF)/255.0f;
173 |
174 | return [UIColor colorWithRed:red green:green blue:blue alpha:alpha];
175 | }
176 |
177 | @end
178 |
--------------------------------------------------------------------------------
/FeSpinner/WifiMan_Sign_1@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/WifiMan_Sign_1@2x.png
--------------------------------------------------------------------------------
/FeSpinner/WifiMan_Sign_2@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/WifiMan_Sign_2@2x.png
--------------------------------------------------------------------------------
/FeSpinner/WifiMan_Sign_3@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/WifiMan_Sign_3@2x.png
--------------------------------------------------------------------------------
/FeSpinner/WifiMan_Sign_4@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/WifiMan_Sign_4@2x.png
--------------------------------------------------------------------------------
/FeSpinner/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/FeSpinner/main.m:
--------------------------------------------------------------------------------
1 | //
2 | // main.m
3 | // FeSpinner
4 | //
5 | // Created by Nghia Tran on 11/20/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | #import "FeAppDelegate.h"
12 |
13 | int main(int argc, char * argv[])
14 | {
15 | @autoreleasepool {
16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([FeAppDelegate class]));
17 | }
18 | }
19 |
--------------------------------------------------------------------------------
/FeSpinner/wifimanhub@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/wifimanhub@2x.png
--------------------------------------------------------------------------------
/FeSpinner/wifimanhub_grayscale@2x.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/NghiaTranUIT/FeSpinner/7bb57750e5874bc5107f7c467c90eda54693d3c3/FeSpinner/wifimanhub_grayscale@2x.png
--------------------------------------------------------------------------------
/FeSpinnerTests/FeSpinnerTests-Info.plist:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | CFBundleDevelopmentRegion
6 | en
7 | CFBundleExecutable
8 | ${EXECUTABLE_NAME}
9 | CFBundleIdentifier
10 | com.fe.${PRODUCT_NAME:rfc1034identifier}
11 | CFBundleInfoDictionaryVersion
12 | 6.0
13 | CFBundlePackageType
14 | BNDL
15 | CFBundleShortVersionString
16 | 1.0
17 | CFBundleSignature
18 | ????
19 | CFBundleVersion
20 | 1
21 |
22 |
23 |
--------------------------------------------------------------------------------
/FeSpinnerTests/FeSpinnerTests.m:
--------------------------------------------------------------------------------
1 | //
2 | // FeSpinnerTests.m
3 | // FeSpinnerTests
4 | //
5 | // Created by Nghia Tran on 11/20/13.
6 | // Copyright (c) 2013 fe. All rights reserved.
7 | //
8 |
9 | #import
10 |
11 | @interface FeSpinnerTests : XCTestCase
12 |
13 | @end
14 |
15 | @implementation FeSpinnerTests
16 |
17 | - (void)setUp
18 | {
19 | [super setUp];
20 | // Put setup code here. This method is called before the invocation of each test method in the class.
21 | }
22 |
23 | - (void)tearDown
24 | {
25 | // Put teardown code here. This method is called after the invocation of each test method in the class.
26 | [super tearDown];
27 | }
28 |
29 | - (void)testExample
30 | {
31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__);
32 | }
33 |
34 | @end
35 |
--------------------------------------------------------------------------------
/FeSpinnerTests/en.lproj/InfoPlist.strings:
--------------------------------------------------------------------------------
1 | /* Localized versions of Info.plist keys */
2 |
3 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | ## Rocket Loader Collection
2 |
3 | The loader collection for iOS app.
4 |
5 | 
6 |
7 | ## REQUIREMENT
8 | FeSpinner work on any version iOS and compatible with ARC or non-ARC.
9 | But your project should include some Apple's framework.
10 |
11 | + Foundation.framework
12 | + UIKit.framework
13 | + CoreGraphics.framework
14 | + QuartzCore.framework
15 |
16 | ## Screenshot
17 |
18 | **Handwriting Loader**
19 |
20 | 
21 |
22 | **Rolling Loader**
23 |
24 | 
25 |
26 | **Equalizer Loader**
27 |
28 | 
29 |
30 | **Hourglass Loader**
31 |
32 | 
33 |
34 | **Wifihub Loader** : Here is loader which i created for my friend few month ago. Wifi Chùa - http://www.wifichuaapp.com.
35 |
36 | 
37 |
38 | **Threedots Glow**
39 |
40 | 
41 |
42 | **Vietnam Loader**
43 |
44 | 
45 |
46 | **Loading Box Loader**
47 |
48 | 
49 |
50 | **Ten Dots Loader**
51 |
52 | 
53 |
54 | ## ADD ROCKET LOADER TO YOUR PROJECT
55 |
56 | Just simply copy file .h and .m in each type loader you like.
57 |
58 | ## HOW TO USE
59 |
60 | FeSpinner is very similar MBProgessHUB.
61 |
62 | FeSpinner have some helpful method.
63 |
64 | ```objc
65 | -(id) initWithView:(UIView *) view blur:(BOOL) blur backgroundColors:(NSArray *) arrColor;
66 |
67 | -(void) show;
68 |
69 | -(void) showWhileExecutingBlock:(dispatch_block_t) block;
70 |
71 | -(void) showWhileExecutingBlock:(dispatch_block_t)block completion:(dispatch_block_t) completion;
72 |
73 | -(void) showWhileExecutingSelector:(SEL) selector onTarget:(id) target withObject:(id) object;
74 |
75 | -(void) showWhileExecutingSelector:(SEL)selector onTarget:(id)target withObject:(id)object completion:(dispatch_block_t) completion;
76 |
77 | -(void) dismiss;
78 | ```
79 | ## MIT License
80 | Copyright (c) 2014 Nghia Tran
81 |
82 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
83 |
84 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
85 |
86 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
87 |
88 | ## Release notes
89 |
90 | Version 1.0
91 |
92 | Initial release
93 |
--------------------------------------------------------------------------------