├── 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 | ![](http://nghiatran.me/wp-content/uploads/2015/01/iTunesArtwork.png "Rocket Loader Collection") 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 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/Handwriting.gif) 21 | 22 | **Rolling Loader** 23 | 24 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/RollingLoader.gif) 25 | 26 | **Equalizer Loader** 27 | 28 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/EqualizerLoader.gif) 29 | 30 | **Hourglass Loader** 31 | 32 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/HourGlassLoader.gif) 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 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/WifiHubLoader.gif) 37 | 38 | **Threedots Glow** 39 | 40 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/TheeDotGlow.gif) 41 | 42 | **Vietnam Loader** 43 | 44 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/VietnamLoader.gif) 45 | 46 | **Loading Box Loader** 47 | 48 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/LoadingBox.gif) 49 | 50 | **Ten Dots Loader** 51 | 52 | ![GIF](http://nghiatran.me/wp-content/uploads/2015/01/TenDot.gif) 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 | --------------------------------------------------------------------------------