| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540 |
- //
- // SVProgressHUD.m
- //
- // Created by Sam Vermette on 27.03.11.
- // Copyright 2011 Sam Vermette. All rights reserved.
- //
- // https://github.com/samvermette/SVProgressHUD
- //
- #import "SVProgressHUD.h"
- #import <QuartzCore/QuartzCore.h>
- @interface SVProgressHUD ()
- @property (nonatomic, readwrite) SVProgressHUDMaskType maskType;
- @property (nonatomic, strong, readonly) NSTimer *fadeOutTimer;
- @property (nonatomic, strong, readonly) UIWindow *overlayWindow;
- @property (nonatomic, strong, readonly) UIView *hudView;
- @property (nonatomic, strong, readonly) UILabel *stringLabel;
- @property (nonatomic, strong, readonly) UIImageView *imageView;
- @property (nonatomic, strong, readonly) UIActivityIndicatorView *spinnerView;
- @property (nonatomic, readonly) CGFloat visibleKeyboardHeight;
- - (void)showWithStatus:(NSString*)string maskType:(SVProgressHUDMaskType)hudMaskType networkIndicator:(BOOL)show;
- - (void)setStatus:(NSString*)string;
- - (void)registerNotifications;
- - (void)moveToPoint:(CGPoint)newCenter rotateAngle:(CGFloat)angle;
- - (void)positionHUD:(NSNotification*)notification;
- - (void)dismiss;
- - (void)dismissWithStatus:(NSString*)string error:(BOOL)error;
- - (void)dismissWithStatus:(NSString*)string error:(BOOL)error afterDelay:(NSTimeInterval)seconds;
- @end
- @implementation SVProgressHUD
- @synthesize overlayWindow, hudView, maskType, fadeOutTimer, stringLabel, imageView, spinnerView, visibleKeyboardHeight;
- - (void)dealloc {
- self.fadeOutTimer = nil;
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- }
- + (SVProgressHUD*)sharedView {
- static dispatch_once_t once;
- static SVProgressHUD *sharedView;
- dispatch_once(&once, ^ { sharedView = [[SVProgressHUD alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; });
- return sharedView;
- }
- + (void)setStatus:(NSString *)string {
- [[SVProgressHUD sharedView] setStatus:string];
- }
- #pragma mark - Show Methods
- + (void)show {
- [[SVProgressHUD sharedView] showWithStatus:nil maskType:SVProgressHUDMaskTypeNone networkIndicator:NO];
- }
- + (void)showWithStatus:(NSString *)status {
- [[SVProgressHUD sharedView] showWithStatus:status maskType:SVProgressHUDMaskTypeNone networkIndicator:NO];
- }
- + (void)showWithMaskType:(SVProgressHUDMaskType)maskType {
- [[SVProgressHUD sharedView] showWithStatus:nil maskType:maskType networkIndicator:NO];
- }
- + (void)showWithStatus:(NSString*)status maskType:(SVProgressHUDMaskType)maskType {
- [[SVProgressHUD sharedView] showWithStatus:status maskType:maskType networkIndicator:NO];
- }
- + (void)showSuccessWithStatus:(NSString *)string {
- [SVProgressHUD showSuccessWithStatus:string duration:1];
- }
- + (void)showSuccessWithStatus:(NSString *)string duration:(NSTimeInterval)duration {
- [SVProgressHUD show];
- [SVProgressHUD dismissWithSuccess:string afterDelay:duration];
- }
- + (void)showErrorWithStatus:(NSString *)string {
- [SVProgressHUD showErrorWithStatus:string duration:1];
- }
- + (void)showErrorWithStatus:(NSString *)string duration:(NSTimeInterval)duration {
- [SVProgressHUD show];
- [SVProgressHUD dismissWithError:string afterDelay:duration];
- }
- #pragma mark - Dismiss Methods
- + (void)dismiss {
- [[SVProgressHUD sharedView] dismiss];
- }
- + (void)dismissWithSuccess:(NSString*)successString {
- [[SVProgressHUD sharedView] dismissWithStatus:successString error:NO];
- }
- + (void)dismissWithSuccess:(NSString *)successString afterDelay:(NSTimeInterval)seconds {
- [[SVProgressHUD sharedView] dismissWithStatus:successString error:NO afterDelay:seconds];
- }
- + (void)dismissWithError:(NSString*)errorString {
- [[SVProgressHUD sharedView] dismissWithStatus:errorString error:YES];
- }
- + (void)dismissWithError:(NSString *)errorString afterDelay:(NSTimeInterval)seconds {
- [[SVProgressHUD sharedView] dismissWithStatus:errorString error:YES afterDelay:seconds];
- }
- #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;
- }
-
- 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);
-
- CGPoint center = CGPointMake(self.bounds.size.width/2, self.bounds.size.height/2);
- float radius = MIN(self.bounds.size.width , self.bounds.size.height) ;
- CGContextDrawRadialGradient (context, gradient, center, 0, center, radius, kCGGradientDrawsAfterEndLocation);
- CGGradientRelease(gradient);
-
- break;
- }
- }
- }
- - (void)setStatus:(NSString *)string {
-
- CGFloat hudWidth = 100;
- CGFloat hudHeight = 100;
- CGFloat stringWidth = 0;
- CGFloat stringHeight = 0;
- CGRect labelRect = CGRectZero;
-
- if(string) {
- CGSize stringSize = [string sizeWithFont:self.stringLabel.font constrainedToSize:CGSizeMake(200, 300)];
- stringWidth = stringSize.width;
- stringHeight = stringSize.height;
- hudHeight = 80+stringHeight;
-
- if(stringWidth > hudWidth)
- hudWidth = ceil(stringWidth/2)*2;
-
- if(hudHeight > 100) {
- labelRect = CGRectMake(12, 66, hudWidth, stringHeight);
- hudWidth+=24;
- } else {
- hudWidth+=24;
- labelRect = CGRectMake(0, 66, 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.text = string;
- self.stringLabel.frame = labelRect;
-
- if(string)
- self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.hudView.bounds)/2)+0.5, 40.5);
- else
- self.spinnerView.center = CGPointMake(ceil(CGRectGetWidth(self.hudView.bounds)/2)+0.5, ceil(self.hudView.bounds.size.height/2)+0.5);
- }
- - (void)setFadeOutTimer:(NSTimer *)newTimer {
-
- if(fadeOutTimer)
- [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];
- }
- - (void)positionHUD:(NSNotification*)notification {
-
- CGFloat keyboardHeight;
- double animationDuration = 0.0;
-
- 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;
- }
- rotateAngle = 0.0;
- newCenter = CGPointMake(posX, posY);
- 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 = newCenter;
- }
- #pragma mark - Master show/dismiss methods
- - (void)showWithStatus:(NSString*)string maskType:(SVProgressHUDMaskType)hudMaskType networkIndicator:(BOOL)show {
- dispatch_async(dispatch_get_main_queue(), ^{
- if(!self.superview)
- [self.overlayWindow addSubview:self];
-
- self.fadeOutTimer = nil;
- self.imageView.hidden = YES;
- self.maskType = hudMaskType;
-
- [self setStatus:string];
- [self.spinnerView startAnimating];
-
- if(self.maskType != SVProgressHUDMaskTypeNone) {
- self.overlayWindow.userInteractionEnabled = YES;
- } else {
- self.overlayWindow.userInteractionEnabled = NO;
- }
-
- [self.overlayWindow makeKeyAndVisible];
- [self positionHUD:nil];
-
- if(self.alpha != 1) {
- [self registerNotifications];
- self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1.3, 1.3);
-
- [UIView animateWithDuration:0.15
- delay:0
- options:UIViewAnimationOptionAllowUserInteraction | UIViewAnimationCurveEaseOut | UIViewAnimationOptionBeginFromCurrentState
- animations:^{
- self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 1/1.3, 1/1.3);
- self.alpha = 1;
- }
- completion:NULL];
- }
-
- [self setNeedsDisplay];
- });
- }
- - (void)dismissWithStatus:(NSString *)string error:(BOOL)error {
- [self dismissWithStatus:string error:error afterDelay:0.9];
- }
- - (void)dismissWithStatus:(NSString *)string error:(BOOL)error afterDelay:(NSTimeInterval)seconds {
- dispatch_async(dispatch_get_main_queue(), ^{
- if(self.alpha != 1)
- return;
-
- if(error)
- self.imageView.image = [UIImage imageNamed:@"SVProgressHUD.bundle/error.png"];
- else
- self.imageView.image = [UIImage imageNamed:@"SVProgressHUD.bundle/success.png"];
-
- self.imageView.hidden = NO;
- [self setStatus:string];
- [self.spinnerView stopAnimating];
-
- self.fadeOutTimer = [NSTimer scheduledTimerWithTimeInterval:seconds target:self selector:@selector(dismiss) userInfo:nil repeats:NO];
- });
- }
- - (void)dismiss {
- dispatch_async(dispatch_get_main_queue(), ^{
- [UIView animateWithDuration:0.15
- delay:0
- options:UIViewAnimationCurveEaseIn | UIViewAnimationOptionAllowUserInteraction
- animations:^{
- self.hudView.transform = CGAffineTransformScale(self.hudView.transform, 0.8, 0.8);
- self.alpha = 0;
- }
- completion:^(BOOL finished){
- if(self.alpha == 0) {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
- [hudView removeFromSuperview];
- hudView = nil;
-
- // Make sure to remove the overlay window from the list of windows
- // before trying to find the key window in that same list
- NSMutableArray *windows = [[NSMutableArray alloc] initWithArray:[UIApplication sharedApplication].windows];
- [windows removeObject:overlayWindow];
- overlayWindow = nil;
-
- [windows enumerateObjectsWithOptions:NSEnumerationReverse usingBlock:^(UIWindow *window, NSUInteger idx, BOOL *stop) {
- if([window isKindOfClass:[UIWindow class]] && window.windowLevel == UIWindowLevelNormal) {
- [window makeKeyWindow];
- *stop = YES;
- }
- }];
- }
- }];
- });
- }
- #pragma mark - Utilities
- + (BOOL)isVisible {
- return ([SVProgressHUD sharedView].alpha == 1);
- }
- #pragma mark - Getters
- - (UIWindow *)overlayWindow {
- if(!overlayWindow) {
- overlayWindow = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
- overlayWindow.autoresizingMask = UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight;
- overlayWindow.backgroundColor = [UIColor clearColor];
- overlayWindow.userInteractionEnabled = NO;
- }
- return overlayWindow;
- }
- - (UIView *)hudView {
- if(!hudView) {
- hudView = [[UIView alloc] initWithFrame:CGRectZero];
- hudView.layer.cornerRadius = 10;
- hudView.backgroundColor = [UIColor colorWithWhite:0 alpha:0.8];
- hudView.autoresizingMask = (UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleTopMargin |
- UIViewAutoresizingFlexibleRightMargin | UIViewAutoresizingFlexibleLeftMargin);
-
- [self addSubview:hudView];
- }
- return hudView;
- }
- - (UILabel *)stringLabel {
- if (stringLabel == nil) {
- stringLabel = [[UILabel alloc] initWithFrame:CGRectZero];
- stringLabel.textColor = [UIColor whiteColor];
- stringLabel.backgroundColor = [UIColor clearColor];
- stringLabel.adjustsFontSizeToFitWidth = YES;
- stringLabel.textAlignment = NSTextAlignmentCenter;
- stringLabel.baselineAdjustment = UIBaselineAdjustmentAlignCenters;
- stringLabel.font = [UIFont boldSystemFontOfSize:16];
- stringLabel.shadowColor = [UIColor blackColor];
- stringLabel.shadowOffset = CGSizeMake(0, -1);
- 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;
- }
- - (UIActivityIndicatorView *)spinnerView {
- if (spinnerView == nil) {
- spinnerView = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
- spinnerView.hidesWhenStopped = YES;
- spinnerView.bounds = CGRectMake(0, 0, 37, 37);
- }
-
- if(!spinnerView.superview)
- [self.hudView addSubview:spinnerView];
-
- return spinnerView;
- }
- - (CGFloat)visibleKeyboardHeight {
-
- UIWindow *keyboardWindow = nil;
- for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
- if(![[testWindow class] isEqual:[UIWindow class]]) {
- keyboardWindow = testWindow;
- break;
- }
- }
- // Locate UIKeyboard.
- UIView *foundKeyboard = nil;
- for (__strong UIView *possibleKeyboard in [keyboardWindow subviews]) {
-
- // iOS 4 sticks the UIKeyboard inside a UIPeripheralHostView.
- if ([[possibleKeyboard description] hasPrefix:@"<UIPeripheralHostView"]) {
- possibleKeyboard = [[possibleKeyboard subviews] objectAtIndex:0];
- }
-
- if ([[possibleKeyboard description] hasPrefix:@"<UIKeyboard"]) {
- foundKeyboard = possibleKeyboard;
- break;
- }
- }
-
- if(foundKeyboard && foundKeyboard.bounds.size.height > 100)
- return foundKeyboard.bounds.size.height;
-
- return 0;
- }
- @end
|