123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967 |
- //
- // SVProgressHUD.m
- //
- // Created by Sam Vermette on 27.03.11.
- // Copyright 2011 Sam Vermette. All rights reserved.
- //
- // https://github.com/samvermette/SVProgressHUD
- //
- #if !__has_feature(objc_arc)
- #error SVProgressHUD is ARC only. Either turn on ARC for the project or use -fobjc-arc flag
- #endif
- #define IS_IOS7 [[[UIDevice currentDevice] systemVersion] hasPrefix:@"7"]
- #import "SVProgressHUD.h"
- #import <QuartzCore/QuartzCore.h>
- NSString * const SVProgressHUDDidReceiveTouchEventNotification = @"SVProgressHUDDidReceiveTouchEventNotification";
- NSString * const SVProgressHUDWillDisappearNotification = @"SVProgressHUDWillDisappearNotification";
- NSString * const SVProgressHUDDidDisappearNotification = @"SVProgressHUDDidDisappearNotification";
- NSString * const SVProgressHUDWillAppearNotification = @"SVProgressHUDWillAppearNotification";
- NSString * const SVProgressHUDDidAppearNotification = @"SVProgressHUDDidAppearNotification";
- NSString * const SVProgressHUDStatusUserInfoKey = @"SVProgressHUDStatusUserInfoKey";
- static UIColor *SVProgressHUDBackgroundColor;
- static UIColor *SVProgressHUDForegroundColor;
- static CGFloat SVProgressHUDRingThickness;
- static UIFont *SVProgressHUDFont;
- static UIImage *SVProgressHUDSuccessImage;
- static UIImage *SVProgressHUDErrorImage;
- static const CGFloat SVProgressHUDRingRadius = 18;
- static const CGFloat SVProgressHUDRingNoTextRadius = 24;
- static const CGFloat SVProgressHUDParallaxDepthPoints = 10;
- @interface SVProgressHUD ()
- @property (nonatomic, readwrite) SVProgressHUDMaskType maskType;
- @property (nonatomic, strong, readonly) NSTimer *fadeOutTimer;
- @property (nonatomic, readonly, getter = isClear) BOOL clear;
- @property (nonatomic, strong) UIControl *overlayView;
- @property (nonatomic, strong) UIView *hudView;
- @property (nonatomic, strong) UILabel *stringLabel;
- @property (nonatomic, strong) UIImageView *imageView;
- @property (nonatomic, strong) SVIndefiniteAnimatedView *indefiniteAnimatedView;
- @property (nonatomic, readwrite) CGFloat progress;
- @property (nonatomic, readwrite) NSUInteger activityCount;
- @property (nonatomic, strong) CAShapeLayer *backgroundRingLayer;
- @property (nonatomic, strong) CAShapeLayer *ringLayer;
- @property (nonatomic, readonly) CGFloat visibleKeyboardHeight;
- @property (nonatomic, assign) UIOffset offsetFromCenter;
- - (void)showProgress:(float)progress
- status:(NSString*)string
- maskType:(SVProgressHUDMaskType)hudMaskType;
- - (void)showImage:(UIImage*)image
- status:(NSString*)status
- duration:(NSTimeInterval)duration;
- - (void)dismiss;
- - (void)setStatus:(NSString*)string;
- - (void)registerNotifications;
- - (NSDictionary *)notificationUserInfo;
- - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle;
- - (void)positionHUD:(NSNotification*)notification;
- - (NSTimeInterval)displayDurationForString:(NSString*)string;
- @end
- @implementation SVProgressHUD
- + (SVProgressHUD*)sharedView {
- static dispatch_once_t once;
- static SVProgressHUD *sharedView;
- dispatch_once(&once, ^ { sharedView = [[self alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; });
- return sharedView;
- }
- #pragma mark - Setters
- + (void)setStatus:(NSString *)string {
- [[self sharedView] setStatus:string];
- }
- + (void)setBackgroundColor:(UIColor *)color {
- [self sharedView].hudView.backgroundColor = color;
- SVProgressHUDBackgroundColor = color;
- }
- + (void)setForegroundColor:(UIColor *)color {
- [self sharedView];
- SVProgressHUDForegroundColor = color;
- }
- + (void)setFont:(UIFont *)font {
- [self sharedView];
- SVProgressHUDFont = font;
- }
- + (void)setRingThickness:(CGFloat)width {
- [self sharedView];
- SVProgressHUDRingThickness = width;
- }
- + (void)setSuccessImage:(UIImage *)image {
- [self sharedView];
- SVProgressHUDSuccessImage = image;
- }
- + (void)setErrorImage:(UIImage *)image {
- [self sharedView];
- SVProgressHUDErrorImage = image;
- }
- #pragma mark - Show Methods
- + (void)show {
- [[self sharedView] showProgress:-1 status:nil maskType:SVProgressHUDMaskTypeNone];
- }
- + (void)showWithStatus:(NSString *)status {
- [[self sharedView] showProgress:-1 status:status maskType:SVProgressHUDMaskTypeNone];
- }
- + (void)showWithMaskType:(SVProgressHUDMaskType)maskType {
- [[self sharedView] showProgress:-1 status:nil maskType:maskType];
- }
- + (void)showWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType {
- [[self sharedView] showProgress:-1 status:status maskType:maskType];
- }
- + (void)showProgress:(float)progress {
- [[self sharedView] showProgress:progress status:nil maskType:SVProgressHUDMaskTypeNone];
- }
- + (void)showProgress:(float)progress status:(NSString *)status {
- [[self sharedView] showProgress:progress status:status maskType:SVProgressHUDMaskTypeNone];
- }
- + (void)showProgress:(float)progress status:(NSString *)status maskType:(SVProgressHUDMaskType)maskType {
- [[self sharedView] showProgress:progress status:status maskType:maskType];
- }
- #pragma mark - Show then dismiss methods
- + (void)showSuccessWithStatus:(NSString *)string {
- [self sharedView];
- [self showImage:SVProgressHUDSuccessImage status:string];
- }
- + (void)showErrorWithStatus:(NSString *)string {
- [self sharedView];
- [self showImage:SVProgressHUDErrorImage status:string];
- }
- + (void)showImage:(UIImage *)image status:(NSString *)string {
- NSTimeInterval displayInterval = [[SVProgressHUD sharedView] displayDurationForString:string];
- [[self sharedView] showImage:image status:string duration:displayInterval];
- }
- #pragma mark - Dismiss Methods
- + (void)popActivity {
- [self sharedView].activityCount--;
- if([self sharedView].activityCount == 0)
- [[self sharedView] dismiss];
- }
- + (void)dismiss {
- if ([self isVisible]) {
- [[self sharedView] dismiss];
- }
- }
- #pragma mark - Offset
- + (void)setOffsetFromCenter:(UIOffset)offset {
- [self sharedView].offsetFromCenter = offset;
- }
- + (void)resetOffsetFromCenter {
- [self setOffsetFromCenter:UIOffsetZero];
- }
- #pragma mark - Instance Methods
- - (id)initWithFrame:(CGRect)frame {
-
- if ((self = [super initWithFrame:frame])) {
- self.userInteractionEnabled = NO;
- self.backgroundColor = [UIColor clearColor];
- self.alpha = 0;
- self.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- self.activityCount = 0;
-
- SVProgressHUDBackgroundColor = [UIColor whiteColor];
- SVProgressHUDForegroundColor = [UIColor blackColor];
-
- if (IS_IOS7) {
- SVProgressHUDFont = [UIFont preferredFontForTextStyle:UIFontTextStyleSubheadline];
- SVProgressHUDSuccessImage = [[UIImage imageNamed:@"SVProgressHUD.bundle/success"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
- SVProgressHUDErrorImage = [[UIImage imageNamed:@"SVProgressHUD.bundle/error"] imageWithRenderingMode:UIImageRenderingModeAlwaysTemplate];
- }
-
- SVProgressHUDRingThickness = 4;
- }
-
- return self;
- }
- - (void)drawRect:(CGRect)rect {
-
- CGContextRef context = UIGraphicsGetCurrentContext();
-
- switch (self.maskType) {
-
- case SVProgressHUDMaskTypeBlack: {
- [[UIColor colorWithWhite:0 alpha:0.5] set];
- CGContextFillRect(context, self.bounds);
- break;
- }
-
- case SVProgressHUDMaskTypeGradient: {
-
- size_t locationsCount = 2;
- CGFloat locations[2] = {0.0f, 1.0f};
- CGFloat colors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f};
- CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
- CGGradientRef gradient = CGGradientCreateWithColorComponents(colorSpace, colors, locations, locationsCount);
- CGColorSpaceRelease(colorSpace);
-
- CGFloat freeHeight = self.bounds.size.height - self.visibleKeyboardHeight;
-
- CGPoint center = CGPointMake(self.bounds.size.width/2, freeHeight/2);
- float radius = MIN(self.bounds.size.width , self.bounds.size.height) ;
- CGContextDrawRadialGradient (context, gradient, center, 0, center, radius, kCGGradientDrawsAfterEndLocation);
- CGGradientRelease(gradient);
-
- break;
- }
- }
- }
- - (void)updatePosition {
-
- CGFloat hudWidth = 100;
- CGFloat hudHeight = 100;
- CGFloat stringHeightBuffer = 20;
- CGFloat stringAndImageHeightBuffer = 80;
-
- CGFloat stringWidth = 0;
- CGFloat stringHeight = 0;
- CGRect labelRect = CGRectZero;
-
- NSString *string = self.stringLabel.text;
- // False if it's text-only
- BOOL imageUsed = (self.imageView.image) || (self.imageView.hidden);
-
- if(string) {
- CGSize constraintSize = CGSizeMake(200, 300);
-
- CGRect stringRect = CGRectZero;
-
- if (IS_IOS7) {
- stringRect = [string boundingRectWithSize:constraintSize
- options:(NSStringDrawingUsesFontLeading|NSStringDrawingTruncatesLastVisibleLine|NSStringDrawingUsesLineFragmentOrigin)
- attributes:@{NSFontAttributeName: self.stringLabel.font}
- context:NULL];
- } else {
- CGSize stringSize = [string boundingRectWithSize:constraintSize options:NSStringDrawingUsesLineFragmentOrigin attributes:@{NSFontAttributeName : self.stringLabel.font} context:nil].size;
- stringRect = CGRectMake(0, 0, stringSize.width, stringSize.height);
- }
-
- stringWidth = stringRect.size.width;
- stringHeight = ceil(stringRect.size.height);
-
- if (imageUsed)
- hudHeight = stringAndImageHeightBuffer + stringHeight;
- else
- hudHeight = stringHeightBuffer + stringHeight;
-
- if(stringWidth > hudWidth)
- hudWidth = ceil(stringWidth/2)*2;
-
- CGFloat labelRectY = imageUsed ? 68 : 9;
-
- if(hudHeight > 100) {
- labelRect = CGRectMake(12, labelRectY, hudWidth, stringHeight);
- hudWidth+=24;
- } else {
- hudWidth+=24;
- labelRect = CGRectMake(0, labelRectY, hudWidth, stringHeight);
- }
- }
-
- self.hudView.bounds = CGRectMake(0, 0, hudWidth, hudHeight);
-
- if(string)
- self.imageView.center = CGPointMake(CGRectGetWidth(self.hudView.bounds)/2, 36);
- else
- self.imageView.center = CGPointMake(CGRectGetWidth(self.hudView.bounds)/2, CGRectGetHeight(self.hudView.bounds)/2);
-
- self.stringLabel.hidden = NO;
- self.stringLabel.frame = labelRect;
-
- [CATransaction begin];
- [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
-
- if(string) {
- self.indefiniteAnimatedView.radius = SVProgressHUDRingRadius;
- [self.indefiniteAnimatedView sizeToFit];
-
- CGPoint center = CGPointMake((CGRectGetWidth(self.hudView.bounds)/2), 36);
- self.indefiniteAnimatedView.center = center;
-
- if(self.progress != -1)
- self.backgroundRingLayer.position = self.ringLayer.position = CGPointMake((CGRectGetWidth(self.hudView.bounds)/2), 36);
- }
- else {
- self.indefiniteAnimatedView.radius = SVProgressHUDRingNoTextRadius;
- [self.indefiniteAnimatedView sizeToFit];
-
- CGPoint center = CGPointMake((CGRectGetWidth(self.hudView.bounds)/2), CGRectGetHeight(self.hudView.bounds)/2);
- self.indefiniteAnimatedView.center = center;
-
- if(self.progress != -1)
- self.backgroundRingLayer.position = self.ringLayer.position = CGPointMake((CGRectGetWidth(self.hudView.bounds)/2), CGRectGetHeight(self.hudView.bounds)/2);
- }
-
- [CATransaction commit];
- }
- - (void)setStatus:(NSString *)string {
-
- self.stringLabel.text = string;
- [self updatePosition];
-
- }
- - (void)setFadeOutTimer:(NSTimer *)newTimer {
-
- if(_fadeOutTimer)
- (void)([_fadeOutTimer invalidate]), _fadeOutTimer = nil;
-
- if(newTimer)
- _fadeOutTimer = newTimer;
- }
- - (void)registerNotifications {
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIApplicationDidChangeStatusBarOrientationNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardWillHideNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardDidHideNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardWillShowNotification
- object:nil];
-
- [[NSNotificationCenter defaultCenter] addObserver:self
- selector:@selector(positionHUD:)
- name:UIKeyboardDidShowNotification
- object:nil];
- }
- - (NSDictionary *)notificationUserInfo
- {
- return (self.stringLabel.text ? @{SVProgressHUDStatusUserInfoKey : self.stringLabel.text} : nil);
- }
- - (void)positionHUD:(NSNotification*)notification {
-
- CGFloat keyboardHeight;
- double animationDuration;
-
- UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
-
- if(notification) {
- NSDictionary* keyboardInfo = [notification userInfo];
- CGRect keyboardFrame = [[keyboardInfo valueForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue];
- animationDuration = [[keyboardInfo valueForKey:UIKeyboardAnimationDurationUserInfoKey] doubleValue];
-
- if(notification.name == UIKeyboardWillShowNotification || notification.name == UIKeyboardDidShowNotification) {
- if(UIInterfaceOrientationIsPortrait(orientation))
- keyboardHeight = keyboardFrame.size.height;
- else
- keyboardHeight = keyboardFrame.size.width;
- } else
- keyboardHeight = 0;
- } else {
- keyboardHeight = self.visibleKeyboardHeight;
- }
-
- CGRect orientationFrame = [UIScreen mainScreen].bounds;
- CGRect statusBarFrame = [UIApplication sharedApplication].statusBarFrame;
-
- if(UIInterfaceOrientationIsLandscape(orientation)) {
- float temp = orientationFrame.size.width;
- orientationFrame.size.width = orientationFrame.size.height;
- orientationFrame.size.height = temp;
-
- temp = statusBarFrame.size.width;
- statusBarFrame.size.width = statusBarFrame.size.height;
- statusBarFrame.size.height = temp;
- }
-
- CGFloat activeHeight = orientationFrame.size.height;
-
- if(keyboardHeight > 0)
- activeHeight += statusBarFrame.size.height*2;
-
- activeHeight -= keyboardHeight;
- CGFloat posY = floor(activeHeight*0.45);
- CGFloat posX = orientationFrame.size.width/2;
-
- CGPoint newCenter;
- CGFloat rotateAngle;
-
- switch (orientation) {
- case UIInterfaceOrientationPortraitUpsideDown:
- rotateAngle = M_PI;
- newCenter = CGPointMake(posX, orientationFrame.size.height-posY);
- break;
- case UIInterfaceOrientationLandscapeLeft:
- rotateAngle = -M_PI/2.0f;
- newCenter = CGPointMake(posY, posX);
- break;
- case UIInterfaceOrientationLandscapeRight:
- rotateAngle = M_PI/2.0f;
- newCenter = CGPointMake(orientationFrame.size.height-posY, posX);
- break;
- default: // as UIInterfaceOrientationPortrait
- rotateAngle = 0.0;
- newCenter = CGPointMake(posX, posY);
- break;
- }
-
- if(notification) {
- [UIView animateWithDuration:animationDuration
- delay:0
- options:UIViewAnimationOptionAllowUserInteraction
- animations:^{
- [self moveToPoint:newCenter rotateAngle:rotateAngle];
- } completion:NULL];
- }
-
- else {
- [self moveToPoint:newCenter rotateAngle:rotateAngle];
- }
-
- }
- - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle {
- self.hudView.transform = CGAffineTransformMakeRotation(angle);
- self.hudView.center = CGPointMake(newCenter.x + self.offsetFromCenter.horizontal, newCenter.y + self.offsetFromCenter.vertical);
- }
- - (void)overlayViewDidReceiveTouchEvent:(id)sender forEvent:(UIEvent *)event {
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidReceiveTouchEventNotification object:event];
- }
- #pragma mark - Master show/dismiss methods
- - (void)showProgress:(float)progress status:(NSString*)string maskType:(SVProgressHUDMaskType)hudMaskType {
-
- if(!self.overlayView.superview){
- NSEnumerator *frontToBackWindows = [[[UIApplication sharedApplication]windows]reverseObjectEnumerator];
-
- for (UIWindow *window in frontToBackWindows)
- if (window.windowLevel == UIWindowLevelNormal) {
- [window addSubview:self.overlayView];
- break;
- }
- }
-
- if(!self.superview)
- [self.overlayView addSubview:self];
-
- self.fadeOutTimer = nil;
- self.imageView.hidden = YES;
- self.maskType = hudMaskType;
- self.progress = progress;
-
- self.stringLabel.text = string;
- [self updatePosition];
-
- if(progress >= 0) {
- self.imageView.image = nil;
- self.imageView.hidden = NO;
- [self.indefiniteAnimatedView removeFromSuperview];
-
- self.ringLayer.strokeEnd = progress;
-
- if(progress == 0)
- self.activityCount++;
- }
- else {
- self.activityCount++;
- [self cancelRingLayerAnimation];
- [self.hudView addSubview:self.indefiniteAnimatedView];
- }
-
- if(self.maskType != SVProgressHUDMaskTypeNone) {
- self.overlayView.userInteractionEnabled = YES;
- self.accessibilityLabel = string;
- self.isAccessibilityElement = YES;
- }
- else {
- self.overlayView.userInteractionEnabled = NO;
- self.hudView.accessibilityLabel = string;
- self.hudView.isAccessibilityElement = YES;
- }
-
- [self.overlayView setHidden:NO];
- self.overlayView.backgroundColor = [UIColor clearColor];
- [self positionHUD:nil];
-
- if(self.alpha != 1) {
- NSDictionary *userInfo = [self notificationUserInfo];
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillAppearNotification
- object:nil
- userInfo:userInfo];
-
- [self registerNotifications];
- self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1.3, 1.3);
-
- if(self.isClear) {
- self.alpha = 1;
- self.hudView.alpha = 0;
- }
-
- [UIView animateWithDuration:0.15
- delay:0
- options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState
- animations:^{
- self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1/1.3, 1/1.3);
-
- if(self.isClear) // handle iOS 7 UIToolbar not answer well to hierarchy opacity change
- self.hudView.alpha = 1;
- else
- self.alpha = 1;
- }
- completion:^(BOOL finished){
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidAppearNotification
- object:nil
- userInfo:userInfo];
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
- UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, string);
- }];
-
- [self setNeedsDisplay];
- }
- }
- - (void)showImage:(UIImage *)image status:(NSString *)string duration:(NSTimeInterval)duration {
- self.progress = -1;
- [self cancelRingLayerAnimation];
-
- if(![self.class isVisible])
- [self.class show];
-
- self.imageView.tintColor = SVProgressHUDForegroundColor;
- self.imageView.image = image;
- self.imageView.hidden = NO;
-
- self.stringLabel.text = string;
- [self updatePosition];
- [self.indefiniteAnimatedView removeFromSuperview];
-
- if(self.maskType != SVProgressHUDMaskTypeNone) {
- self.accessibilityLabel = string;
- self.isAccessibilityElement = YES;
- } else {
- self.hudView.accessibilityLabel = string;
- self.hudView.isAccessibilityElement = YES;
- }
-
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
- UIAccessibilityPostNotification(UIAccessibilityAnnouncementNotification, string);
-
- self.fadeOutTimer = [NSTimer timerWithTimeInterval:duration target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
- [[NSRunLoop mainRunLoop] addTimer:self.fadeOutTimer forMode:NSRunLoopCommonModes];
- }
- - (void)dismiss {
- NSDictionary *userInfo = [self notificationUserInfo];
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDWillDisappearNotification
- object:nil
- userInfo:userInfo];
-
- self.activityCount = 0;
- [UIView animateWithDuration:0.15
- delay:0
- options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
- animations:^{
- self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 0.8, 0.8);
- if(self.isClear) // handle iOS 7 UIToolbar not answer well to hierarchy opacity change
- self.hudView.alpha = 0;
- else
- self.alpha = 0;
- }
- completion:^(BOOL finished){
- if(self.alpha == 0 || self.hudView.alpha == 0) {
- self.alpha = 0;
- self.hudView.alpha = 0;
-
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [self cancelRingLayerAnimation];
- [_hudView removeFromSuperview];
- _hudView = nil;
-
- [_overlayView removeFromSuperview];
- _overlayView = nil;
-
- [_indefiniteAnimatedView removeFromSuperview];
- _indefiniteAnimatedView = nil;
-
- UIAccessibilityPostNotification(UIAccessibilityScreenChangedNotification, nil);
-
- [[NSNotificationCenter defaultCenter] postNotificationName:SVProgressHUDDidDisappearNotification
- object:nil
- userInfo:userInfo];
-
- // Tell the rootViewController to update the StatusBar appearance
- UIViewController *rootController = [[UIApplication sharedApplication] keyWindow].rootViewController;
- if ([rootController respondsToSelector:@selector(setNeedsStatusBarAppearanceUpdate)]) {
- [rootController setNeedsStatusBarAppearanceUpdate];
- }
- // uncomment to make sure UIWindow is gone from app.windows
- //NSLog(@"%@", [UIApplication sharedApplication].windows);
- //NSLog(@"keyWindow = %@", [UIApplication sharedApplication].keyWindow);
- }
- }];
- }
- #pragma mark - Ring progress animation
- - (SVIndefiniteAnimatedView *)indefiniteAnimatedView {
- if (_indefiniteAnimatedView == nil) {
- _indefiniteAnimatedView = [[SVIndefiniteAnimatedView alloc] initWithFrame:CGRectZero];
- _indefiniteAnimatedView.radius = self.stringLabel.text ? SVProgressHUDRingRadius : SVProgressHUDRingNoTextRadius;
- [_indefiniteAnimatedView sizeToFit];
- }
- return _indefiniteAnimatedView;
- }
- - (CAShapeLayer *)ringLayer {
- if(!_ringLayer) {
- CGPoint center = CGPointMake(CGRectGetWidth(_hudView.frame)/2, CGRectGetHeight(_hudView.frame)/2);
- _ringLayer = [self createRingLayerWithCenter:center
- radius:SVProgressHUDRingRadius
- lineWidth:SVProgressHUDRingThickness
- color:SVProgressHUDForegroundColor];
- [self.hudView.layer addSublayer:_ringLayer];
- }
- return _ringLayer;
- }
- - (CAShapeLayer *)backgroundRingLayer {
- if(!_backgroundRingLayer) {
- CGPoint center = CGPointMake(CGRectGetWidth(_hudView.frame)/2, CGRectGetHeight(_hudView.frame)/2);
- _backgroundRingLayer = [self createRingLayerWithCenter:center
- radius:SVProgressHUDRingRadius
- lineWidth:SVProgressHUDRingThickness
- color:[SVProgressHUDForegroundColor colorWithAlphaComponent:0.1]];
- _backgroundRingLayer.strokeEnd = 1;
- [self.hudView.layer addSublayer:_backgroundRingLayer];
- }
- return _backgroundRingLayer;
- }
- - (void)cancelRingLayerAnimation {
- [CATransaction begin];
- [CATransaction setDisableActions:YES];
- [_hudView.layer removeAllAnimations];
-
- _ringLayer.strokeEnd = 0.0f;
- if (_ringLayer.superlayer) {
- [_ringLayer removeFromSuperlayer];
- }
- _ringLayer = nil;
-
- if (_backgroundRingLayer.superlayer) {
- [_backgroundRingLayer removeFromSuperlayer];
- }
- _backgroundRingLayer = nil;
-
- [CATransaction commit];
- }
- - (CAShapeLayer *)createRingLayerWithCenter:(CGPoint)center radius:(CGFloat)radius lineWidth:(CGFloat)lineWidth color:(UIColor *)color {
-
- UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:CGPointMake(radius, radius) radius:radius startAngle:-M_PI_2 endAngle:(M_PI + M_PI_2) clockwise:YES];
-
- CAShapeLayer *slice = [CAShapeLayer layer];
- slice.contentsScale = [[UIScreen mainScreen] scale];
- slice.frame = CGRectMake(center.x-radius, center.y-radius, radius*2, radius*2);
- slice.fillColor = [UIColor clearColor].CGColor;
- slice.strokeColor = color.CGColor;
- slice.lineWidth = lineWidth;
- slice.lineCap = kCALineCapRound;
- slice.lineJoin = kCALineJoinBevel;
- slice.path = smoothedPath.CGPath;
- return slice;
- }
- #pragma mark - Utilities
- + (BOOL)isVisible {
- return ([self sharedView].alpha == 1);
- }
- #pragma mark - Getters
- - (NSTimeInterval)displayDurationForString:(NSString*)string {
- return MIN((float)string.length*0.06 + 0.3, 5.0);
- }
- - (BOOL)isClear { // used for iOS 7
- return (self.maskType == SVProgressHUDMaskTypeClear || self.maskType == SVProgressHUDMaskTypeNone);
- }
- - (UIControl *)overlayView {
- if(!_overlayView) {
- _overlayView = [[UIControl alloc] initWithFrame:[UIScreen mainScreen].bounds];
- _overlayView.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- _overlayView.backgroundColor = [UIColor clearColor];
- [_overlayView addTarget:self action:@selector(overlayViewDidReceiveTouchEvent:forEvent:) forControlEvents:UIControlEventTouchDown];
- }
- return _overlayView;
- }
- - (UIView *)hudView {
- if(!_hudView) {
- _hudView = [[UIView alloc] initWithFrame:CGRectZero];
- _hudView.backgroundColor = SVProgressHUDBackgroundColor;
- _hudView.layer.cornerRadius = 14;
- _hudView.layer.masksToBounds = YES;
-
- _hudView.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin |
- UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin);
-
- if (IS_IOS7) {
- UIInterpolatingMotionEffect *effectX = [[UIInterpolatingMotionEffect alloc] initWithKeyPath: @"center.x" type: UIInterpolatingMotionEffectTypeTiltAlongHorizontalAxis];
- effectX.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints);
- effectX.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints);
-
- UIInterpolatingMotionEffect *effectY = [[UIInterpolatingMotionEffect alloc] initWithKeyPath: @"center.y" type: UIInterpolatingMotionEffectTypeTiltAlongVerticalAxis];
- effectY.minimumRelativeValue = @(-SVProgressHUDParallaxDepthPoints);
- effectY.maximumRelativeValue = @(SVProgressHUDParallaxDepthPoints);
-
- [_hudView addMotionEffect: effectX];
- [_hudView addMotionEffect: effectY];
- }
-
- [self addSubview:_hudView];
- }
- return _hudView;
- }
- - (UILabel *)stringLabel {
- if (_stringLabel == nil) {
- _stringLabel = [[UILabel alloc] initWithFrame:CGRectZero];
- _stringLabel.backgroundColor = [UIColor clearColor];
- _stringLabel.adjustsFontSizeToFitWidth = YES;
- _stringLabel.textAlignment = NSTextAlignmentCenter;
- _stringLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
- _stringLabel.textColor = SVProgressHUDForegroundColor;
- _stringLabel.font = SVProgressHUDFont;
- _stringLabel.numberOfLines = 0;
- }
-
- if(!_stringLabel.superview)
- [self.hudView addSubview:_stringLabel];
-
- return _stringLabel;
- }
- - (UIImageView *)imageView {
- if (_imageView == nil)
- _imageView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, 28, 28)];
-
- if(!_imageView.superview)
- [self.hudView addSubview:_imageView];
-
- return _imageView;
- }
- - (CGFloat)visibleKeyboardHeight {
-
- UIWindow *keyboardWindow = nil;
- for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
- if(![[testWindow class] isEqual:[UIWindow class]]) {
- keyboardWindow = testWindow;
- break;
- }
- }
-
- for (__strong UIView *possibleKeyboard in [keyboardWindow subviews]) {
- if([possibleKeyboard isKindOfClass:NSClassFromString(@"UIPeripheralHostView")] || [possibleKeyboard isKindOfClass:NSClassFromString(@"UIKeyboard")])
- return possibleKeyboard.bounds.size.height;
- }
-
- return 0;
- }
- @end
- #pragma mark SVIndefiniteAnimatedView
- @interface SVIndefiniteAnimatedView ()
- @property (nonatomic, strong) CAShapeLayer *indefiniteAnimatedLayer;
- @end
- @implementation SVIndefiniteAnimatedView
- - (id)initWithFrame:(CGRect)frame {
- if (self = [super initWithFrame:frame]) {
- self.strokeThickness = SVProgressHUDRingThickness;
- self.radius = SVProgressHUDRingRadius;
- self.strokeColor = SVProgressHUDForegroundColor;
- }
- return self;
- }
- - (void)willMoveToSuperview:(UIView *)newSuperview {
- if (newSuperview != nil) {
- [self layoutAnimatedLayer];
- }
- else {
- [_indefiniteAnimatedLayer removeFromSuperlayer];
- _indefiniteAnimatedLayer = nil;
- }
- }
- - (void)layoutAnimatedLayer {
- CALayer *layer = self.indefiniteAnimatedLayer;
-
- [self.layer addSublayer:layer];
- layer.position = CGPointMake(self.bounds.size.width - layer.bounds.size.width / 2, self.bounds.size.height - layer.bounds.size.height / 2);
- }
- - (CAShapeLayer*)indefiniteAnimatedLayer {
- if(!_indefiniteAnimatedLayer) {
- CGPoint arcCenter = CGPointMake(self.radius+self.strokeThickness/2+5, self.radius+self.strokeThickness/2+5);
- CGRect rect = CGRectMake(0, 0, arcCenter.x*2, arcCenter.y*2);
-
- UIBezierPath* smoothedPath = [UIBezierPath bezierPathWithArcCenter:arcCenter
- radius:self.radius
- startAngle:M_PI*3/2
- endAngle:M_PI/2+M_PI*5
- clockwise:YES];
-
- _indefiniteAnimatedLayer = [CAShapeLayer layer];
- _indefiniteAnimatedLayer.contentsScale = [[UIScreen mainScreen] scale];
- _indefiniteAnimatedLayer.frame = rect;
- _indefiniteAnimatedLayer.fillColor = [UIColor clearColor].CGColor;
- _indefiniteAnimatedLayer.strokeColor = self.strokeColor.CGColor;
- _indefiniteAnimatedLayer.lineWidth = self.strokeThickness;
- _indefiniteAnimatedLayer.lineCap = kCALineCapRound;
- _indefiniteAnimatedLayer.lineJoin = kCALineJoinBevel;
- _indefiniteAnimatedLayer.path = smoothedPath.CGPath;
-
- CALayer *maskLayer = [CALayer layer];
- maskLayer.contents = (id)[[UIImage imageNamed:@"SVProgressHUD.bundle/angle-mask@2x.png"] CGImage];
- maskLayer.frame = _indefiniteAnimatedLayer.bounds;
- _indefiniteAnimatedLayer.mask = maskLayer;
-
- NSTimeInterval animationDuration = 1;
- CAMediaTimingFunction *linearCurve = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionLinear];
-
- CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"transform.rotation"];
- animation.fromValue = 0;
- animation.toValue = [NSNumber numberWithFloat:M_PI*2];
- animation.duration = animationDuration;
- animation.timingFunction = linearCurve;
- animation.removedOnCompletion = NO;
- animation.repeatCount = INFINITY;
- animation.fillMode = kCAFillModeForwards;
- animation.autoreverses = NO;
- [_indefiniteAnimatedLayer.mask addAnimation:animation forKey:@"rotate"];
-
- CAAnimationGroup *animationGroup = [CAAnimationGroup animation];
- animationGroup.duration = animationDuration;
- animationGroup.repeatCount = INFINITY;
- animationGroup.removedOnCompletion = NO;
- animationGroup.timingFunction = linearCurve;
-
- CABasicAnimation *strokeStartAnimation = [CABasicAnimation animationWithKeyPath:@"strokeStart"];
- strokeStartAnimation.fromValue = @0.015;
- strokeStartAnimation.toValue = @0.515;
-
- CABasicAnimation *strokeEndAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
- strokeEndAnimation.fromValue = @0.485;
- strokeEndAnimation.toValue = @0.985;
-
- animationGroup.animations = @[strokeStartAnimation, strokeEndAnimation];
- [_indefiniteAnimatedLayer addAnimation:animationGroup forKey:@"progress"];
-
- }
- return _indefiniteAnimatedLayer;
- }
- - (void)setFrame:(CGRect)frame {
- [super setFrame:frame];
-
- if (self.superview != nil) {
- [self layoutAnimatedLayer];
- }
- }
- - (void)setRadius:(CGFloat)radius {
- _radius = radius;
-
- [_indefiniteAnimatedLayer removeFromSuperlayer];
- _indefiniteAnimatedLayer = nil;
-
- [self layoutAnimatedLayer];
- }
- - (void)setStrokeColor:(UIColor *)strokeColor {
- _strokeColor = strokeColor;
- _indefiniteAnimatedLayer.strokeColor = strokeColor.CGColor;
- }
- - (void)setStrokeThickness:(CGFloat)strokeThickness {
- _strokeThickness = strokeThickness;
- _indefiniteAnimatedLayer.lineWidth = _strokeThickness;
- }
- - (CGSize)sizeThatFits:(CGSize)size {
- return CGSizeMake((self.radius+self.strokeThickness/2+5)*2, (self.radius+self.strokeThickness/2+5)*2);
- }
- @end
|