MBProgressHUD.h
#import <Foundation/Foundation.h>
#import "MBProgressHUD.h"
#define SNS_DEPRECATED_ATTRIBUTE __attribute__((deprecated))
typedef enum _tagShowType{
EST_NORMAL=0,
EST_SUCCESS,
EST_FAIL,
}enShowType;
@interface HudMessageView : NSObject{
MBProgressHUD* _hud;
}
+(HudMessageView*) sharedHudMessageView;
+(void) destroyHudMessageView;
-(id) init;
/////////////////////////////////////////////////////////////////////////
// //
// 新接口,每个接口都可以单独调用 //
// //
/////////////////////////////////////////////////////////////////////////
/* loading提示
title : 提示的文字
imagePath : 提示的图片路径,可以为nil,如果是nil则使用默认的菊花图案
missTime : 停留的时间,如果是0,则不会自动消失
*/
-(void) loadingPromptWithTitle:(NSString *)title imagePath:(NSString *) imagePath missTime:(float)missTime;
/* 成功提示
title : 提示的文字
succImagePath : 提示图片,nil的情况默认是对勾图片
missTime : 停留时间
*/
-(void) successPromptWithTitle:(NSString *)title succImagePath:(NSString*)succImagePath missTime:(float)missTime;
/* 失败提示
title : 提示的文字
failImagePath : 提示图片,nil的情况默认是叉叉图片
missTime : 停留时间
*/
-(void) failPromptWithTitle:(NSString *)title failImagePath:(NSString*)failImagePath missTime:(float)missTime;
/* 纯文字提示
title : 提示的文字
missTime : 停留时间,如果是0,则不会自动消失
*/
-(void) wordPromptWithTitle:(NSString *)title missTime:(float) missTime;
/////////////////////////////////////////////////////////////////////////
// //
// 以下的接口都是以前的老接口,还可以用,不建议再使用 //
// //
/////////////////////////////////////////////////////////////////////////
//下面的函数
//函数成单调用 调用时设置延时时间 到时间后自动消失
-(void) showWithType:(enShowType)showType title:(NSString*)title afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) showWithType:(enShowType)showType title:(NSString*)title afterDelay:(float)afterDelay hudMode:(MBProgressHUDMode)modeSNS_DEPRECATED_ATTRIBUTE;
//下面的函数是过程式 调用方式成对出现
//1. 首先调用showloading 显示状态
//2. 再调用showSuccess 或者 showFailStatus 延时隐藏
-(void) showLoading:(NSString*)titleSNS_DEPRECATED_ATTRIBUTE;
-(void) showSuccessStatus:(NSString*)title afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) showSuccessStatusKeepMode:(NSString*)title afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) showFailStatus:(NSString*)title afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) showFailStatusKeepMode:(NSString*)title afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) showLoading:(NSString*)title imagePath:(NSString*)imagePathSNS_DEPRECATED_ATTRIBUTE;
-(void) showSuccessStatus:(NSString*)title succImagePath:(NSString*)succImagePath afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) showFailStatus:(NSString*)title failImagPath:(NSString*)failImagPath afterDelay:(float)afterDelaySNS_DEPRECATED_ATTRIBUTE;
-(void) adjustHUDOrientation;
@end
HudMessageView.m
#import "HudMessageView.h"
@implementation HudMessageView
static HudMessageView* g_HudMessageView =nil;
+(HudMessageView*) sharedHudMessageView{
if (nil==g_HudMessageView)
{
g_HudMessageView = [[HudMessageViewalloc] init];
}
returng_HudMessageView;
}
+(void) destroyHudMessageView{
if (g_HudMessageView)
{
[g_HudMessageViewrelease];
g_HudMessageView =nil;
}
}
-(id) init{
if( (self=[superinit]) ) {
UIWindow *window = [UIApplicationsharedApplication].keyWindow;
_hud = [[MBProgressHUDalloc] initWithView:window];
[window addSubview:_hud];
// Set determinate mode
//_hud.delegate = self;
_hud.dimBackground =YES;
}
returnself;
}
-(void) dealloc{
[_hudremoveFromSuperview];
[_hudrelease];
[superdealloc];
}
-(void) showWithType:(enShowType)showType title:(NSString*)title afterDelay:(float)afterDelay{
[selfshowLoading:title];
switch (showType)
{
caseEST_NORMAL:
[_hudhide:YESafterDelay:afterDelay];
break;
caseEST_SUCCESS:
[selfshowSuccessStatus:title afterDelay:afterDelay];
break;
caseEST_FAIL:
[selfshowFailStatus:title afterDelay:afterDelay];
break;
default:
break;
}
}
-(void) showWithType:(enShowType)showType title:(NSString*)title afterDelay:(float)afterDelay hudMode:(MBProgressHUDMode)mode{
[selfshowLoading:title];
switch (showType)
{
caseEST_NORMAL:
[_hudhide:YESafterDelay:afterDelay];
break;
caseEST_SUCCESS:
[selfshowSuccessStatus:title afterDelay:afterDelay];
break;
caseEST_FAIL:
[selfshowFailStatus:title afterDelay:afterDelay];
break;
default:
break;
}
_hud.mode = mode;
}
-(void) showLoading:(NSString *)title{
[selfshowLoading:title imagePath:nil];
}
-(void) showLoading:(NSString*)title imagePath:(NSString*)imagePath{
if (imagePath)
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:imagePath]] autorelease];
_hud.mode =MBProgressHUDModeCustomView;
}
else
{
_hud.mode =MBProgressHUDModeIndeterminate;
}
_hud.labelText = title;
[_hudshow:YES];
}
-(void) showSuccessStatus:(NSString *)title afterDelay:(float)afterDelay{
[selfshowSuccessStatus:title succImagePath:@"055_success@2x.png"afterDelay:afterDelay];
}
-(void) showSuccessStatusKeepMode:(NSString *)title afterDelay:(float)afterDelay{
[selfshowSuccessStatus:title succImagePath:nilafterDelay:afterDelay];
}
-(void) showSuccessStatus:(NSString*)title succImagePath:(NSString*)succImagePath afterDelay:(float)afterDelay{
if (succImagePath)
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:succImagePath]]autorelease];
_hud.mode =MBProgressHUDModeCustomView;
}
_hud.labelText = title;
if (fabs(afterDelay) <0.000001f)
{
[_hudhide:YES];
}
else
{
[_hudhide:YESafterDelay:afterDelay];
}
}
-(void) showFailStatus:(NSString *)title afterDelay:(float)afterDelay{
[selfshowFailStatus:title failImagPath:@"055_fail@2x.png"afterDelay:afterDelay];
}
-(void) showFailStatusKeepMode:(NSString *)title afterDelay:(float)afterDelay{
[selfshowFailStatus:title failImagPath:nilafterDelay:afterDelay];
}
-(void) showFailStatus:(NSString*)title failImagPath:(NSString*)failImagPath afterDelay:(float)afterDelay{
if (failImagPath)
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImage imageNamed_New:failImagPath]]autorelease];
_hud.mode =MBProgressHUDModeCustomView;
}
_hud.labelText = title;
if (fabs(afterDelay) <0.000001f)
{
[_hudhide:YES];
}
else
{
[_hudhide:YESafterDelay:afterDelay];
}
}
-(void) adjustHUDOrientation
{
[_hud setTransformForCurrentOrientation:NO];
}
-(void) loadingPromptWithTitle:(NSString *)title imagePath:(NSString *) imagePath missTime:(float)missTime
{
if (imagePath)
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:imagePath]] autorelease];
_hud.mode =MBProgressHUDModeCustomView;
}
else
{
_hud.mode =MBProgressHUDModeIndeterminate;
}
_hud.labelText = title;
if (_hud.dimBackground)
{
[_hudshow:YES];
}
if (fabs(missTime) >0.000001f)
{
[_hudhide:YESafterDelay:missTime];
}
}
-(void) successPromptWithTitle:(NSString *)title succImagePath:(NSString *)succImagePath missTime:(float)missTime
{
if (_hud.dimBackground)
{
if (succImagePath)
{
[selfloadingPromptWithTitle:titleimagePath:succImagePath missTime:0];
}
else
{
[selfloadingPromptWithTitle:titleimagePath:@"055_success"missTime:0];
}
}
else
{
if (succImagePath)
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:succImagePath]]autorelease];
}
else
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"055_success"]]autorelease];
}
_hud.mode =MBProgressHUDModeCustomView;
_hud.labelText = title;
}
if (fabs(missTime) <0.000001f)
{
[_hudhide:YES];
}
else
{
[_hudhide:YESafterDelay:missTime];
}
}
-(void) failPromptWithTitle:(NSString *)title failImagePath:(NSString*)failImagePath missTime:(float)missTime
{
if (_hud.dimBackground)
{
if (failImagePath)
{
[selfloadingPromptWithTitle:titleimagePath:failImagePath missTime:0];
}
else
{
[selfloadingPromptWithTitle:titleimagePath:@"055_fail.png"missTime:0];
}
}
else
{
if (failImagePath)
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:failImagePath]]autorelease];
}
else
{
_hud.customView = [[[UIImageViewalloc] initWithImage:[UIImageimageNamed:@"055_fail.png"]]autorelease];
}
_hud.mode =MBProgressHUDModeCustomView;
_hud.labelText = title;
}
if (fabs(missTime) <0.000001f)
{
[_hudhide:YES];
}
else
{
[_hudhide:YESafterDelay:missTime];
}
}
-(void) wordPromptWithTitle:(NSString *)title missTime:(float) missTime
{
_hud.mode =MBProgressHUDModeText;
_hud.labelText = title;
if (_hud.dimBackground)
{
[_hudshow:YES];
}
if (fabs(missTime) >0.000001f)
{
[_hudhide:YESafterDelay:missTime];
}
}
@end
MBProgressHUD.h
#import <Foundation/Foundation.h>
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>
@protocol MBProgressHUDDelegate;
typedef enum {
/** Progress is shown using an UIActivityIndicatorView. This is the default. */
MBProgressHUDModeIndeterminate,
/** Progress is shown using a round, pie-chart like, progress view. */
MBProgressHUDModeDeterminate,
/** Progress is shown using a horizontal progress bar */
MBProgressHUDModeDeterminateHorizontalBar,
/** Progress is shown using a ring-shaped progress view. */
MBProgressHUDModeAnnularDeterminate,
/** Shows a custom view */
MBProgressHUDModeCustomView,
/** Shows only labels */
MBProgressHUDModeText
} MBProgressHUDMode;
typedef enum {
/** Opacity animation */
MBProgressHUDAnimationFade,
/** Opacity + scale animation */
MBProgressHUDAnimationZoom,
MBProgressHUDAnimationZoomOut =MBProgressHUDAnimationZoom,
MBProgressHUDAnimationZoomIn
} MBProgressHUDAnimation;
#ifndef MB_INSTANCETYPE
#if __has_feature(objc_instancetype)
#define MB_INSTANCETYPE instancetype
#else
#define MB_INSTANCETYPE id
#endif
#endif
#ifndef MB_STRONG
#if __has_feature(objc_arc)
#define MB_STRONG strong
#else
#define MB_STRONG retain
#endif
#endif
#ifndef MB_WEAK
#if __has_feature(objc_arc_weak)
#define MB_WEAK weak
#elif __has_feature(objc_arc)
#define MB_WEAK unsafe_unretained
#else
#define MB_WEAK assign
#endif
#endif
#if NS_BLOCKS_AVAILABLE
typedef void (^MBProgressHUDCompletionBlock)();
#endif
/**
* Displays a simple HUD window containing a progress indicator and two optional labels for short messages.
*
* This is a simple drop-in class for displaying a progress HUD view similar to Apple's private UIProgressHUD class.
* The MBProgressHUD window spans over the entire space given to it by the initWithFrame constructor and catches all
* user input on this region, thereby preventing the user operations on components below the view. The HUD itself is
* drawn centered as a rounded semi-transparent view which resizes depending on the user specified content.
*
* This view supports four modes of operation:
* - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView
* - MBProgressHUDModeDeterminate - shows a custom round progress indicator
* - MBProgressHUDModeAnnularDeterminate - shows a custom annular progress indicator
* - MBProgressHUDModeCustomView - shows an arbitrary, user specified view (@see customView)
*
* All three modes can have optional labels assigned:
* - If the labelText property is set and non-empty then a label containing the provided content is placed below the
* indicator view.
* - If also the detailsLabelText property is set then another label is placed below the first label.
*/
@interface MBProgressHUD : UIView
/**
* Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:.
*
* @param view The view that the HUD will be added to
* @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
* animations while appearing.
* @return A reference to the created HUD.
*
* @see hideHUDForView:animated:
* @see animationType
*/
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;
/**
* Finds the top-most HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:.
*
* @param view The view that is going to be searched for a HUD subview.
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
* animations while disappearing.
* @return YES if a HUD was found and removed, NO otherwise.
*
* @see showHUDAddedTo:animated:
* @see animationType
*/
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated;
/**
* Finds all the HUD subviews and hides them.
*
* @param view The view that is going to be searched for HUD subviews.
* @param animated If set to YES the HUDs will disappear using the current animationType. If set to NO the HUDs will not use
* animations while disappearing.
* @return the number of HUDs found and removed.
*
* @see hideHUDForView:animated:
* @see animationType
*/
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated;
/**
* Finds the top-most HUD subview and returns it.
*
* @param view The view that is going to be searched.
* @return A reference to the last HUD subview discovered.
*/
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view;
/**
* Finds all HUD subviews and returns them.
*
* @param view The view that is going to be searched.
* @return All found HUD views (array of MBProgressHUD objects).
*/
+ (NSArray *)allHUDsForView:(UIView *)view;
/**
* A convenience constructor that initializes the HUD with the window's bounds. Calls the designated constructor with
* window.bounds as the parameter.
*
* @param window The window instance that will provide the bounds for the HUD. Should be the same instance as
* the HUD's superview (i.e., the window that the HUD will be added to).
*/
- (id)initWithWindow:(UIWindow *)window;
/**
* A convenience constructor that initializes the HUD with the view's bounds. Calls the designated constructor with
* view.bounds as the parameter
*
* @param view The view instance that will provide the bounds for the HUD. Should be the same instance as
* the HUD's superview (i.e., the view that the HUD will be added to).
*/
- (id)initWithView:(UIView *)view;
/**
* Display the HUD. You need to make sure that the main thread completes its run loop soon after this method call so
* the user interface can be updated. Call this method when your task is already set-up to be executed in a new thread
* (e.g., when using something like NSOperation or calling an asynchronous call like NSURLRequest).
*
* @param animated If set to YES the HUD will appear using the current animationType. If set to NO the HUD will not use
* animations while appearing.
*
* @see animationType
*/
- (void)show:(BOOL)animated;
/**
* Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
* hide the HUD when your task completes.
*
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
* animations while disappearing.
*
* @see animationType
*/
- (void)hide:(BOOL)animated;
/**
* Hide the HUD after a delay. This still calls the hudWasHidden: delegate. This is the counterpart of the show: method. Use it to
* hide the HUD when your task completes.
*
* @param animated If set to YES the HUD will disappear using the current animationType. If set to NO the HUD will not use
* animations while disappearing.
* @param delay Delay in seconds until the HUD is hidden.
*
* @see animationType
*/
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay;
/**
* Shows the HUD while a background task is executing in a new thread, then hides the HUD.
*
* This method also takes care of autorelease pools so your method does not have to be concerned with setting up a
* pool.
*
* @param method The method to be executed while the HUD is shown. This method will be executed in a new thread.
* @param target The object that the target method belongs to.
* @param object An optional object to be passed to the method.
* @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will not use
* animations while (dis)appearing.
*/
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;
#if NS_BLOCKS_AVAILABLE
/**
* Shows the HUD while a block is executing on a background queue, then hides the HUD.
*
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block;
/**
* Shows the HUD while a block is executing on a background queue, then hides the HUD.
*
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(MBProgressHUDCompletionBlock)completion;
/**
* Shows the HUD while a block is executing on the specified dispatch queue, then hides the HUD.
*
* @see showAnimated:whileExecutingBlock:onQueue:completionBlock:
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue;
/**
* Shows the HUD while a block is executing on the specified dispatch queue, executes completion block on the main queue, and then hides the HUD.
*
* @param animated If set to YES the HUD will (dis)appear using the current animationType. If set to NO the HUD will
* not use animations while (dis)appearing.
* @param block The block to be executed while the HUD is shown.
* @param queue The dispatch queue on which the block should be executed.
* @param completion The block to be executed on completion.
*
* @see completionBlock
*/
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion;
/**
* A block that gets called after the HUD was completely hidden.
*/
@property (copy)MBProgressHUDCompletionBlock completionBlock;
#endif
/**
* MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate.
*
* @see MBProgressHUDMode
*/
@property (assign)MBProgressHUDMode mode;
/**
* The animation type that should be used when the HUD is shown and hidden.
*
* @see MBProgressHUDAnimation
*/
@property (assign)MBProgressHUDAnimation animationType;
/**
* The UIView (e.g., a UIImageView) to be shown when the HUD is in MBProgressHUDModeCustomView.
* For best results use a 37 by 37 pixel view (so the bounds match the built in indicator bounds).
*/
@property (MB_STRONG)UIView *customView;
/**
* The HUD delegate object.
*
* @see MBProgressHUDDelegate
*/
@property (MB_WEAK)id<MBProgressHUDDelegate> delegate;
/**
* An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit
* the entire text. If the text is too long it will get clipped by displaying "..." at the end. If left unchanged or
* set to @"", then no message is displayed.
*/
@property (copy)NSString *labelText;
/**
* An optional details message displayed below the labelText message. This message is displayed only if the labelText
* property is also set and is different from an empty string (@""). The details text can span multiple lines.
*/
@property (copy)NSString *detailsLabelText;
/**
* The opacity of the HUD window. Defaults to 0.8 (80% opacity).
*/
@property (assign)float opacity;
/**
* The color of the HUD window. Defaults to black. If this property is set, color is set using
* this UIColor and the opacity property is not used. using retain because performing copy on
* UIColor base colors (like [UIColor greenColor]) cause problems with the copyZone.
*/
@property (MB_STRONG)UIColor *color;
/**
* The x-axis offset of the HUD relative to the centre of the superview.
*/
@property (assign)float xOffset;
/**
* The y-axis offset of the HUD relative to the centre of the superview.
*/
@property (assign)float yOffset;
/**
* The amount of space between the HUD edge and the HUD elements (labels, indicators or custom views).
* Defaults to 20.0
*/
@property (assign)float margin;
/**
* The corner radius for the HUD
* Defaults to 10.0
*/
@property (assign)float cornerRadius;
/**
* Cover the HUD background view with a radial gradient.
*/
@property (assign)BOOL dimBackground;
/*
* Grace period is the time (in seconds) that the invoked method may be run without
* showing the HUD. If the task finishes before the grace time runs out, the HUD will
* not be shown at all.
* This may be used to prevent HUD display for very short tasks.
* Defaults to 0 (no grace time).
* Grace time functionality is only supported when the task status is known!
* @see taskInProgress
*/
@property (assign)float graceTime;
/**
* The minimum time (in seconds) that the HUD is shown.
* This avoids the problem of the HUD being shown and than instantly hidden.
* Defaults to 0 (no minimum show time).
*/
@property (assign)float minShowTime;
/**
* Indicates that the executed operation is in progress. Needed for correct graceTime operation.
* If you don't set a graceTime (different than 0.0) this does nothing.
* This property is automatically set when using showWhileExecuting:onTarget:withObject:animated:.
* When threading is done outside of the HUD (i.e., when the show: and hide: methods are used directly),
* you need to set this property when your task starts and completes in order to have normal graceTime
* functionality.
*/
@property (assign)BOOL taskInProgress;
/**
* Removes the HUD from its parent view when hidden.
* Defaults to NO.
*/
@property (assign)BOOL removeFromSuperViewOnHide;
/**
* Font to be used for the main label. Set this property if the default is not adequate.
*/
@property (MB_STRONG)UIFont* labelFont;
/**
* Color to be used for the main label. Set this property if the default is not adequate.
*/
@property (MB_STRONG)UIColor* labelColor;
/**
* Font to be used for the details label. Set this property if the default is not adequate.
*/
@property (MB_STRONG)UIFont* detailsLabelFont;
/**
* Color to be used for the details label. Set this property if the default is not adequate.
*/
@property (MB_STRONG)UIColor* detailsLabelColor;
/**
* The color of the activity indicator. Defaults to [UIColor whiteColor]
* Does nothing on pre iOS 5.
*/
@property (MB_STRONG)UIColor *activityIndicatorColor;
/**
* The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0.
*/
@property (assign)float progress;
/**
* The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size).
*/
@property (assign)CGSize minSize;
/**
* The actual size of the HUD bezel.
* You can use this to limit touch handling on the bezel aria only.
* @see https://github.com/jdg/MBProgressHUD/pull/200
*/
@property (atomic,assign, readonly)CGSize size;
/**
* Force the HUD dimensions to be equal if possible.
*/
@property (assign,getter = isSquare) BOOL square;
@end
@protocol MBProgressHUDDelegate <NSObject>
@optional
/**
* Called after the HUD was fully hidden from the screen.
*/
- (void)hudWasHidden:(MBProgressHUD *)hud;
@end
/**
* A progress view for showing definite progress by filling up a circle (pie chart).
*/
@interface MBRoundProgressView :UIView
/**
* Progress (0.0 to 1.0)
*/
@property (nonatomic,assign) float progress;
/**
* Indicator progress color.
* Defaults to white [UIColor whiteColor]
*/
@property (nonatomic,MB_STRONG) UIColor *progressTintColor;
/**
* Indicator background (non-progress) color.
* Defaults to translucent white (alpha 0.1)
*/
@property (nonatomic,MB_STRONG) UIColor *backgroundTintColor;
/*
* Display mode - NO = round or YES = annular. Defaults to round.
*/
@property (nonatomic,assign, getter = isAnnular)BOOL annular;
@end
/**
* A flat bar progress view.
*/
@interface MBBarProgressView : UIView
/**
* Progress (0.0 to 1.0)
*/
@property (nonatomic,assign) float progress;
/**
* Bar border line color.
* Defaults to white [UIColor whiteColor].
*/
@property (nonatomic,MB_STRONG) UIColor *lineColor;
/**
* Bar background color.
* Defaults to clear [UIColor clearColor];
*/
@property (nonatomic,MB_STRONG) UIColor *progressRemainingColor;
/**
* Bar progress color.
* Defaults to white [UIColor whiteColor].
*/
@property (nonatomic,MB_STRONG) UIColor *progressColor;
@end
MBProgressHUD.m
#import "MBProgressHUD.h"
#import <tgmath.h>
#if __has_feature(objc_arc)
#define MB_AUTORELEASE(exp) exp
#define MB_RELEASE(exp) exp
#define MB_RETAIN(exp) exp
#else
#define MB_AUTORELEASE(exp) [exp autorelease]
#define MB_RELEASE(exp) [exp release]
#define MB_RETAIN(exp) [exp retain]
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 60000
#define MBLabelAlignmentCenter NSTextAlignmentCenter
#else
#define MBLabelAlignmentCenter UITextAlignmentCenter
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define MB_TEXTSIZE(text, font) [text length] > 0 ? [text \
sizeWithAttributes:@{NSFontAttributeName:font}] : CGSizeZero;
#else
#define MB_TEXTSIZE(text, font) [text length] > 0 ? [text sizeWithFont:font] : CGSizeZero;
#endif
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 70000
#define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] >0 ? [text \
boundingRectWithSize:maxSize options:(NSStringDrawingUsesLineFragmentOrigin) \
attributes:@{NSFontAttributeName:font} context:nil].size : CGSizeZero;
#else
#define MB_MULTILINE_TEXTSIZE(text, font, maxSize, mode) [text length] >0 ? [text \
sizeWithFont:font constrainedToSize:maxSize lineBreakMode:mode] : CGSizeZero;
#endif
#ifndef kCFCoreFoundationVersionNumber_iOS_7_0
#define kCFCoreFoundationVersionNumber_iOS_7_0 847.20
#endif
#ifndef kCFCoreFoundationVersionNumber_iOS_8_0
#define kCFCoreFoundationVersionNumber_iOS_8_0 1129.15
#endif
static constCGFloat kPadding = 4.f;
static constCGFloat kLabelFontSize =16.f;
static constCGFloat kDetailsLabelFontSize =12.f;
@interface MBProgressHUD () {
BOOL useAnimation;
SEL methodForExecution;
id targetForExecution;
id objectForExecution;
UILabel *label;
UILabel *detailsLabel;
BOOL isFinished;
CGAffineTransform rotationTransform;
}
@property (atomic,MB_STRONG) UIView *indicator;
@property (atomic,MB_STRONG) NSTimer *graceTimer;
@property (atomic,MB_STRONG) NSTimer *minShowTimer;
@property (atomic,MB_STRONG) NSDate *showStarted;
@end
@implementation MBProgressHUD
#pragma mark - Properties
@synthesize animationType;
@synthesize delegate;
@synthesize opacity;
@synthesize color;
@synthesize labelFont;
@synthesize labelColor;
@synthesize detailsLabelFont;
@synthesize detailsLabelColor;
@synthesize indicator;
@synthesize xOffset;
@synthesize yOffset;
@synthesize minSize;
@synthesize square;
@synthesize margin;
@synthesize dimBackground;
@synthesize graceTime;
@synthesize minShowTime;
@synthesize graceTimer;
@synthesize minShowTimer;
@synthesize taskInProgress;
@synthesize removeFromSuperViewOnHide;
@synthesize customView;
@synthesize showStarted;
@synthesize mode;
@synthesize labelText;
@synthesize detailsLabelText;
@synthesize progress;
@synthesize size;
@synthesize activityIndicatorColor;
#if NS_BLOCKS_AVAILABLE
@synthesize completionBlock;
#endif
#pragma mark - Class methods
+ (MB_INSTANCETYPE)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
MBProgressHUD *hud = [[selfalloc] initWithView:view];
hud.removeFromSuperViewOnHide =YES;
[view addSubview:hud];
[hud show:animated];
returnMB_AUTORELEASE(hud);
}
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
MBProgressHUD *hud = [selfHUDForView:view];
if (hud !=nil) {
hud.removeFromSuperViewOnHide =YES;
[hud hide:animated];
returnYES;
}
returnNO;
}
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated {
NSArray *huds = [MBProgressHUDallHUDsForView:view];
for (MBProgressHUD *hudin huds) {
hud.removeFromSuperViewOnHide =YES;
[hud hide:animated];
}
return [hudscount];
}
+ (MB_INSTANCETYPE)HUDForView:(UIView *)view {
NSEnumerator *subviewsEnum = [view.subviewsreverseObjectEnumerator];
for (UIView *subviewin subviewsEnum) {
if ([subviewisKindOfClass:self]) {
return (MBProgressHUD *)subview;
}
}
returnnil;
}
+ (NSArray *)allHUDsForView:(UIView *)view {
NSMutableArray *huds = [NSMutableArrayarray];
NSArray *subviews = view.subviews;
for (UIView *aViewin subviews) {
if ([aViewisKindOfClass:self]) {
[huds addObject:aView];
}
}
return [NSArrayarrayWithArray:huds];
}
#pragma mark - Lifecycle
- (id)initWithFrame:(CGRect)frame {
self = [superinitWithFrame:frame];
if (self) {
// Set default values for properties
self.animationType =MBProgressHUDAnimationFade;
self.mode =MBProgressHUDModeIndeterminate;
self.labelText =nil;
self.detailsLabelText =nil;
self.opacity =0.8f;
self.color =nil;
self.labelFont = [UIFontboldSystemFontOfSize:kLabelFontSize];
self.labelColor = [UIColorwhiteColor];
self.detailsLabelFont = [UIFontboldSystemFontOfSize:kDetailsLabelFontSize];
self.detailsLabelColor = [UIColorwhiteColor];
self.activityIndicatorColor = [UIColorwhiteColor];
self.xOffset =0.0f;
self.yOffset =0.0f;
self.dimBackground =NO;
self.margin =20.0f;
self.cornerRadius =10.0f;
self.graceTime =0.0f;
self.minShowTime =0.0f;
self.removeFromSuperViewOnHide =NO;
self.minSize =CGSizeZero;
self.square =NO;
self.contentMode =UIViewContentModeCenter;
self.autoresizingMask =UIViewAutoresizingFlexibleTopMargin |UIViewAutoresizingFlexibleBottomMargin
| UIViewAutoresizingFlexibleLeftMargin |UIViewAutoresizingFlexibleRightMargin;
// Transparent background
self.opaque =NO;
self.backgroundColor = [UIColorclearColor];
// Make it invisible for now
self.alpha =0.0f;
taskInProgress =NO;
rotationTransform =CGAffineTransformIdentity;
[selfsetupLabels];
[selfupdateIndicators];
[selfregisterForKVO];
[selfregisterForNotifications];
}
returnself;
}
- (id)initWithView:(UIView *)view {
NSAssert(view,@"View must not be nil.");
return [selfinitWithFrame:view.bounds];
}
- (id)initWithWindow:(UIWindow *)window {
return [selfinitWithView:window];
}
- (void)dealloc {
[selfunregisterFromNotifications];
[selfunregisterFromKVO];
#if !__has_feature(objc_arc)
[color release];
[indicator release];
[label release];
[detailsLabel release];
[labelText release];
[detailsLabelText release];
[graceTimer release];
[minShowTimer release];
[showStarted release];
[customView release];
[labelFont release];
[labelColor release];
[detailsLabelFont release];
[detailsLabelColor release];
#if NS_BLOCKS_AVAILABLE
[completionBlock release];
#endif
[super dealloc];
#endif
}
#pragma mark - Show & hide
- (void)show:(BOOL)animated {
useAnimation = animated;
// If the grace time is set postpone the HUD display
if (self.graceTime >0.0) {
self.graceTimer = [NSTimerscheduledTimerWithTimeInterval:self.graceTimetarget:self
selector:@selector(handleGraceTimer:)userInfo:nilrepeats:NO];
}
// ... otherwise show the HUD imediately
else {
[selfsetNeedsDisplay];
[selfshowUsingAnimation:useAnimation];
}
}
- (void)hide:(BOOL)animated {
useAnimation = animated;
// If the minShow time is set, calculate how long the hud was shown,
// and pospone the hiding operation if necessary
if (self.minShowTime >0.0 && showStarted) {
NSTimeInterval interv = [[NSDatedate] timeIntervalSinceDate:showStarted];
if (interv <self.minShowTime) {
self.minShowTimer = [NSTimerscheduledTimerWithTimeInterval:(self.minShowTime - interv)target:self
selector:@selector(handleMinShowTimer:)userInfo:nilrepeats:NO];
return;
}
}
// ... otherwise hide the HUD immediately
[selfhideUsingAnimation:useAnimation];
}
- (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay {
[selfperformSelector:@selector(hideDelayed:)withObject:[NSNumbernumberWithBool:animated]afterDelay:delay];
}
- (void)hideDelayed:(NSNumber *)animated {
[selfhide:[animated boolValue]];
}
#pragma mark - Timer callbacks
- (void)handleGraceTimer:(NSTimer *)theTimer {
// Show the HUD only if the task is still running
if (taskInProgress) {
[selfsetNeedsDisplay];
[selfshowUsingAnimation:useAnimation];
}
}
- (void)handleMinShowTimer:(NSTimer *)theTimer {
[selfhideUsingAnimation:useAnimation];
}
#pragma mark - View Hierrarchy
- (BOOL)shouldPerformOrientationTransform {
BOOL isPreiOS8 =NSFoundationVersionNumber <kCFCoreFoundationVersionNumber_iOS_8_0;
// prior to iOS8 code needs to take care of rotation if it is being added to the window
return isPreiOS8 && [self.superviewisKindOfClass:[UIWindowclass]];
}
- (void)didMoveToSuperview {
if ([selfshouldPerformOrientationTransform]) {
[selfsetTransformForCurrentOrientation:NO];
}
}
#pragma mark - Internal show & hide operations
- (void)showUsingAnimation:(BOOL)animated {
if (animated &&animationType ==MBProgressHUDAnimationZoomIn) {
self.transform =CGAffineTransformConcat(rotationTransform,CGAffineTransformMakeScale(0.5f,0.5f));
} elseif (animated &&animationType ==MBProgressHUDAnimationZoomOut) {
self.transform =CGAffineTransformConcat(rotationTransform,CGAffineTransformMakeScale(1.5f,1.5f));
}
self.showStarted = [NSDatedate];
// Fade in
if (animated) {
[UIViewbeginAnimations:nilcontext:NULL];
[UIViewsetAnimationDuration:0.30];
self.alpha =1.0f;
if (animationType ==MBProgressHUDAnimationZoomIn ||animationType ==MBProgressHUDAnimationZoomOut) {
self.transform =rotationTransform;
}
[UIViewcommitAnimations];
}
else {
self.alpha =1.0f;
}
}
- (void)hideUsingAnimation:(BOOL)animated {
// Fade out
if (animated &&showStarted) {
[UIViewbeginAnimations:nilcontext:NULL];
[UIViewsetAnimationDuration:0.30];
[UIViewsetAnimationDelegate:self];
[UIViewsetAnimationDidStopSelector:@selector(animationFinished:finished:context:)];
// 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden
// in the done method
if (animationType ==MBProgressHUDAnimationZoomIn) {
self.transform =CGAffineTransformConcat(rotationTransform,CGAffineTransformMakeScale(1.5f,1.5f));
} elseif (animationType ==MBProgressHUDAnimationZoomOut) {
self.transform =CGAffineTransformConcat(rotationTransform,CGAffineTransformMakeScale(0.5f,0.5f));
}
self.alpha =0.02f;
[UIViewcommitAnimations];
}
else {
self.alpha =0.0f;
[selfdone];
}
self.showStarted =nil;
}
- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
[selfdone];
}
- (void)done {
[NSObjectcancelPreviousPerformRequestsWithTarget:self];
isFinished =YES;
self.alpha =0.0f;
if (removeFromSuperViewOnHide) {
[selfremoveFromSuperview];
}
#if NS_BLOCKS_AVAILABLE
if (self.completionBlock) {
self.completionBlock();
self.completionBlock =NULL;
}
#endif
if ([delegaterespondsToSelector:@selector(hudWasHidden:)]) {
[delegateperformSelector:@selector(hudWasHidden:)withObject:self];
}
}
#pragma mark - Threading
- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
methodForExecution = method;
targetForExecution =MB_RETAIN(target);
objectForExecution =MB_RETAIN(object);
// Launch execution in new thread
self.taskInProgress =YES;
[NSThreaddetachNewThreadSelector:@selector(launchExecution)toTarget:selfwithObject:nil];
// Show HUD view
[selfshow:animated];
}
#if NS_BLOCKS_AVAILABLE
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block {
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
[selfshowAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:NULL];
}
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block completionBlock:(void (^)())completion {
dispatch_queue_t queue =dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT,0);
[selfshowAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion];
}
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue {
[selfshowAnimated:animated whileExecutingBlock:block onQueue:queuecompletionBlock:NULL];
}
- (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue
completionBlock:(MBProgressHUDCompletionBlock)completion {
self.taskInProgress =YES;
self.completionBlock = completion;
dispatch_async(queue, ^(void) {
block();
dispatch_async(dispatch_get_main_queue(), ^(void) {
[selfcleanUp];
});
});
[selfshow:animated];
}
#endif
- (void)launchExecution {
@autoreleasepool {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// Start executing the requested task
[targetForExecutionperformSelector:methodForExecutionwithObject:objectForExecution];
#pragma clang diagnostic pop
// Task completed, update view in main thread (note: view operations should
// be done only in the main thread)
[selfperformSelectorOnMainThread:@selector(cleanUp)withObject:nilwaitUntilDone:NO];
}
}
- (void)cleanUp {
taskInProgress =NO;
#if !__has_feature(objc_arc)
[targetForExecution release];
[objectForExecution release];
#else
targetForExecution =nil;
objectForExecution =nil;
#endif
[selfhide:useAnimation];
}
#pragma mark - UI
- (void)setupLabels {
label = [[UILabelalloc] initWithFrame:self.bounds];
label.adjustsFontSizeToFitWidth =NO;
label.textAlignment =MBLabelAlignmentCenter;
label.opaque =NO;
label.backgroundColor = [UIColorclearColor];
label.textColor =self.labelColor;
label.font =self.labelFont;
label.text =self.labelText;
[selfaddSubview:label];
detailsLabel = [[UILabelalloc] initWithFrame:self.bounds];
detailsLabel.font =self.detailsLabelFont;
detailsLabel.adjustsFontSizeToFitWidth =NO;
detailsLabel.textAlignment =MBLabelAlignmentCenter;
detailsLabel.opaque =NO;
detailsLabel.backgroundColor = [UIColorclearColor];
detailsLabel.textColor =self.detailsLabelColor;
detailsLabel.numberOfLines =0;
detailsLabel.font =self.detailsLabelFont;
detailsLabel.text =self.detailsLabelText;
[selfaddSubview:detailsLabel];
}
- (void)updateIndicators {
BOOL isActivityIndicator = [indicatorisKindOfClass:[UIActivityIndicatorViewclass]];
BOOL isRoundIndicator = [indicatorisKindOfClass:[MBRoundProgressViewclass]];
if (mode ==MBProgressHUDModeIndeterminate) {
if (!isActivityIndicator) {
// Update to indeterminate indicator
[indicatorremoveFromSuperview];
self.indicator =MB_AUTORELEASE([[UIActivityIndicatorViewalloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]);
[(UIActivityIndicatorView *)indicatorstartAnimating];
[selfaddSubview:indicator];
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
[(UIActivityIndicatorView *)indicatorsetColor:self.activityIndicatorColor];
#endif
}
elseif (mode ==MBProgressHUDModeDeterminateHorizontalBar) {
// Update to bar determinate indicator
[indicatorremoveFromSuperview];
self.indicator =MB_AUTORELEASE([[MBBarProgressViewalloc] init]);
[selfaddSubview:indicator];
}
elseif (mode ==MBProgressHUDModeDeterminate ||mode == MBProgressHUDModeAnnularDeterminate) {
if (!isRoundIndicator) {
// Update to determinante indicator
[indicatorremoveFromSuperview];
self.indicator =MB_AUTORELEASE([[MBRoundProgressViewalloc] init]);
[selfaddSubview:indicator];
}
if (mode ==MBProgressHUDModeAnnularDeterminate) {
[(MBRoundProgressView *)indicatorsetAnnular:YES];
}
}
elseif (mode ==MBProgressHUDModeCustomView &&customView !=indicator) {
// Update custom view indicator
[indicatorremoveFromSuperview];
self.indicator =customView;
[selfaddSubview:indicator];
} elseif (mode ==MBProgressHUDModeText) {
[indicatorremoveFromSuperview];
self.indicator =nil;
}
}
#pragma mark - Layout
- (void)layoutSubviews {
[superlayoutSubviews];
// Entirely cover the parent view
UIView *parent =self.superview;
if (parent) {
// if (NSFoundationVersionNumber <= NSFoundationVersionNumber_iOS_7_1)
// {
// self.frame = CGRectMake(0.f, 0.f, parent.bounds.size.height, parent.bounds.size.width);
// }
// else
{
self.frame = parent.bounds;
}
}
CGRect bounds =self.bounds;
// Determine the total widt and height needed
CGFloat maxWidth = bounds.size.width -4 * margin;
CGSize totalSize =CGSizeZero;
CGRect indicatorF =indicator.bounds;
indicatorF.size.width =MIN(indicatorF.size.width, maxWidth);
totalSize.width =MAX(totalSize.width, indicatorF.size.width);
totalSize.height += indicatorF.size.height;
CGSize labelSize =MB_TEXTSIZE(label.text,label.font);
labelSize.width =MIN(labelSize.width, maxWidth);
totalSize.width =MAX(totalSize.width, labelSize.width);
totalSize.height += labelSize.height;
if (labelSize.height >0.f && indicatorF.size.height >0.f) {
totalSize.height +=kPadding;
}
CGFloat remainingHeight = bounds.size.height - totalSize.height - kPadding - 4 *margin;
CGSize maxSize =CGSizeMake(maxWidth, remainingHeight);
CGSize detailsLabelSize =MB_MULTILINE_TEXTSIZE(detailsLabel.text,detailsLabel.font, maxSize, detailsLabel.lineBreakMode);
totalSize.width =MAX(totalSize.width, detailsLabelSize.width);
totalSize.height += detailsLabelSize.height;
if (detailsLabelSize.height >0.f && (indicatorF.size.height >0.f || labelSize.height >0.f)) {
totalSize.height +=kPadding;
}
totalSize.width +=2 * margin;
totalSize.height +=2 * margin;
// Position elements
CGFloat yPos =round(((bounds.size.height - totalSize.height) / 2)) + margin +yOffset;
CGFloat xPos =xOffset;
indicatorF.origin.y = yPos;
indicatorF.origin.x =round((bounds.size.width - indicatorF.size.width) / 2) + xPos;
indicator.frame = indicatorF;
yPos += indicatorF.size.height;
if (labelSize.height >0.f && indicatorF.size.height >0.f) {
yPos += kPadding;
}
CGRect labelF;
labelF.origin.y = yPos;
labelF.origin.x =round((bounds.size.width - labelSize.width) / 2) + xPos;
labelF.size = labelSize;
label.frame = labelF;
yPos += labelF.size.height;
if (detailsLabelSize.height >0.f && (indicatorF.size.height >0.f || labelSize.height >0.f)) {
yPos += kPadding;
}
CGRect detailsLabelF;
detailsLabelF.origin.y = yPos;
detailsLabelF.origin.x =round((bounds.size.width - detailsLabelSize.width) / 2) + xPos;
detailsLabelF.size = detailsLabelSize;
detailsLabel.frame = detailsLabelF;
// Enforce minsize and quare rules
if (square) {
CGFloat max =MAX(totalSize.width, totalSize.height);
if (max <= bounds.size.width -2 * margin) {
totalSize.width = max;
}
if (max <= bounds.size.height -2 * margin) {
totalSize.height = max;
}
}
if (totalSize.width <minSize.width) {
totalSize.width =minSize.width;
}
if (totalSize.height <minSize.height) {
totalSize.height =minSize.height;
}
size = totalSize;
}
#pragma mark BG Drawing
- (void)drawRect:(CGRect)rect {
CGContextRef context =UIGraphicsGetCurrentContext();
UIGraphicsPushContext(context);
if (self.dimBackground) {
//Gradient colours
size_t gradLocationsNum =2;
CGFloat gradLocations[2] = {0.0f,1.0f};
CGFloat gradColors[8] = {0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.0f,0.75f};
CGColorSpaceRef colorSpace =CGColorSpaceCreateDeviceRGB();
CGGradientRef gradient =CGGradientCreateWithColorComponents(colorSpace, gradColors, gradLocations, gradLocationsNum);
CGColorSpaceRelease(colorSpace);
//Gradient center
CGPoint gradCenter=CGPointMake(self.bounds.size.width/2,self.bounds.size.height/2);
//Gradient radius
float gradRadius =MIN(self.bounds.size.width , self.bounds.size.height) ;
//Gradient draw
CGContextDrawRadialGradient (context, gradient, gradCenter,
0, gradCenter, gradRadius,
kCGGradientDrawsAfterEndLocation);
CGGradientRelease(gradient);
}
// Set background rect color
if (self.color) {
CGContextSetFillColorWithColor(context,self.color.CGColor);
} else {
CGContextSetGrayFillColor(context,0.0f, self.opacity);
}
// Center HUD
CGRect allRect =self.bounds;
// Draw rounded HUD backgroud rect
CGRect boxRect =CGRectMake(round((allRect.size.width - size.width) /2) + self.xOffset,
round((allRect.size.height -size.height) /2) + self.yOffset,size.width,size.height);
float radius =self.cornerRadius;
CGContextBeginPath(context);
CGContextMoveToPoint(context,CGRectGetMinX(boxRect) + radius,CGRectGetMinY(boxRect));
CGContextAddArc(context,CGRectGetMaxX(boxRect) - radius,CGRectGetMinY(boxRect) + radius, radius,3 * (float)M_PI /2, 0,0);
CGContextAddArc(context,CGRectGetMaxX(boxRect) - radius,CGRectGetMaxY(boxRect) - radius, radius,0, (float)M_PI /2, 0);
CGContextAddArc(context,CGRectGetMinX(boxRect) + radius,CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI /2, (float)M_PI,0);
CGContextAddArc(context,CGRectGetMinX(boxRect) + radius,CGRectGetMinY(boxRect) + radius, radius, (float)M_PI,3 * (float)M_PI /2, 0);
CGContextClosePath(context);
CGContextFillPath(context);
UIGraphicsPopContext();
}
#pragma mark - KVO
- (void)registerForKVO {
for (NSString *keyPathin [selfobservableKeypaths]) {
[selfaddObserver:selfforKeyPath:keyPath options:NSKeyValueObservingOptionNewcontext:NULL];
}
}
- (void)unregisterFromKVO {
for (NSString *keyPathin [selfobservableKeypaths]) {
[selfremoveObserver:selfforKeyPath:keyPath];
}
}
- (NSArray *)observableKeypaths {
return [NSArrayarrayWithObjects:@"mode",@"customView", @"labelText",@"labelFont", @"labelColor",
@"detailsLabelText",@"detailsLabelFont", @"detailsLabelColor", @"progress",@"activityIndicatorColor",nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
if (![NSThreadisMainThread]) {
[selfperformSelectorOnMainThread:@selector(updateUIForKeypath:)withObject:keyPath waitUntilDone:NO];
} else {
[selfupdateUIForKeypath:keyPath];
}
}
- (void)updateUIForKeypath:(NSString *)keyPath {
if ([keyPathisEqualToString:@"mode"] || [keyPathisEqualToString:@"customView"] ||
[keyPath isEqualToString:@"activityIndicatorColor"]) {
[selfupdateIndicators];
} elseif ([keyPath isEqualToString:@"labelText"]) {
label.text =self.labelText;
} elseif ([keyPath isEqualToString:@"labelFont"]) {
label.font =self.labelFont;
} elseif ([keyPath isEqualToString:@"labelColor"]) {
label.textColor =self.labelColor;
} elseif ([keyPath isEqualToString:@"detailsLabelText"]) {
detailsLabel.text =self.detailsLabelText;
} elseif ([keyPath isEqualToString:@"detailsLabelFont"]) {
detailsLabel.font =self.detailsLabelFont;
} elseif ([keyPath isEqualToString:@"detailsLabelColor"]) {
detailsLabel.textColor =self.detailsLabelColor;
} elseif ([keyPath isEqualToString:@"progress"]) {
if ([indicatorrespondsToSelector:@selector(setProgress:)]) {
[(id)indicatorsetValue:@(progress)forKey:@"progress"];
}
return;
}
[selfsetNeedsLayout];
[selfsetNeedsDisplay];
}
#pragma mark - Notifications
- (void)registerForNotifications {
NSNotificationCenter *nc = [NSNotificationCenterdefaultCenter];
[nc addObserver:selfselector:@selector(statusBarOrientationDidChange:)
name:UIApplicationDidChangeStatusBarOrientationNotificationobject:nil];
}
- (void)unregisterFromNotifications {
NSNotificationCenter *nc = [NSNotificationCenterdefaultCenter];
[nc removeObserver:selfname:UIApplicationDidChangeStatusBarOrientationNotificationobject:nil];
}
- (void)statusBarOrientationDidChange:(NSNotification *)notification {
UIView *superview =self.superview;
if (!superview) {
return;
} elseif ([selfshouldPerformOrientationTransform]) {
[selfsetTransformForCurrentOrientation:YES];
} else {
self.frame =self.superview.bounds;
[selfsetNeedsDisplay];
}
}
- (void)setTransformForCurrentOrientation:(BOOL)animated {
// Stay in sync with the superview
if (self.superview) {
self.bounds =self.superview.bounds;
[selfsetNeedsDisplay];
}
UIInterfaceOrientation orientation = [UIApplicationsharedApplication].statusBarOrientation;
CGFloat radians =0;
if (UIInterfaceOrientationIsLandscape(orientation)) {
if (NSFoundationVersionNumber <=NSFoundationVersionNumber_iOS_7_1)
{
if (orientation ==UIInterfaceOrientationLandscapeLeft) { radians = -(CGFloat)M_PI_2; }
else { radians = (CGFloat)M_PI_2; }
}
// Window coordinates differ!
self.bounds =CGRectMake(0,0, self.bounds.size.height,self.bounds.size.width);
} else {
if (orientation ==UIInterfaceOrientationPortraitUpsideDown) { radians = (CGFloat)M_PI; }
else { radians =0; }
}
rotationTransform =CGAffineTransformMakeRotation(radians);
if (animated) {
[UIViewbeginAnimations:nilcontext:nil];
[UIViewsetAnimationDuration:0.3];
}
[selfsetTransform:rotationTransform];
if (animated) {
[UIViewcommitAnimations];
}
}
@end
@implementation MBRoundProgressView
#pragma mark - Lifecycle
- (id)init {
return [selfinitWithFrame:CGRectMake(0.f,0.f, 37.f, 37.f)];
}
- (id)initWithFrame:(CGRect)frame {
self = [superinitWithFrame:frame];
if (self) {
self.backgroundColor = [UIColorclearColor];
self.opaque =NO;
_progress =0.f;
_annular =NO;
_progressTintColor = [[UIColoralloc] initWithWhite:1.falpha:1.f];
_backgroundTintColor = [[UIColoralloc] initWithWhite:1.falpha:.1f];
[selfregisterForKVO];
}
returnself;
}
- (void)dealloc {
[selfunregisterFromKVO];
#if !__has_feature(objc_arc)
[_progressTintColor release];
[_backgroundTintColor release];
[super dealloc];
#endif
}
#pragma mark - Drawing
- (void)drawRect:(CGRect)rect {
CGRect allRect =self.bounds;
CGRect circleRect =CGRectInset(allRect, 2.0f, 2.0f);
CGContextRef context =UIGraphicsGetCurrentContext();
if (_annular) {
// Draw background
BOOL isPreiOS7 =NSFoundationVersionNumber <kCFCoreFoundationVersionNumber_iOS_7_0;
CGFloat lineWidth = isPreiOS7 ?5.f : 2.f;
UIBezierPath *processBackgroundPath = [UIBezierPathbezierPath];
processBackgroundPath.lineWidth = lineWidth;
processBackgroundPath.lineCapStyle =kCGLineCapButt;
CGPoint center =CGPointMake(self.bounds.size.width/2,self.bounds.size.height/2);
CGFloat radius = (self.bounds.size.width - lineWidth)/2;
CGFloat startAngle = - ((float)M_PI /2); // 90 degrees
CGFloat endAngle = (2 * (float)M_PI) + startAngle;
[processBackgroundPath addArcWithCenter:centerradius:radius startAngle:startAngleendAngle:endAngle clockwise:YES];
[_backgroundTintColorset];
[processBackgroundPath stroke];
// Draw progress
UIBezierPath *processPath = [UIBezierPathbezierPath];
processPath.lineCapStyle = isPreiOS7 ?kCGLineCapRound : kCGLineCapSquare;
processPath.lineWidth = lineWidth;
endAngle = (self.progress *2 * (float)M_PI) + startAngle;
[processPath addArcWithCenter:centerradius:radius startAngle:startAngleendAngle:endAngle clockwise:YES];
[_progressTintColorset];
[processPath stroke];
} else {
// Draw background
[_progressTintColorsetStroke];
[_backgroundTintColorsetFill];
CGContextSetLineWidth(context,2.0f);
CGContextFillEllipseInRect(context, circleRect);
CGContextStrokeEllipseInRect(context, circleRect);
// Draw progress
CGPoint center =CGPointMake(allRect.size.width /2, allRect.size.height /2);
CGFloat radius = (allRect.size.width -4) / 2;
CGFloat startAngle = - ((float)M_PI /2); // 90 degrees
CGFloat endAngle = (self.progress *2 * (float)M_PI) + startAngle;
CGContextSetRGBFillColor(context,1.0f, 1.0f,1.0f, 1.0f);// white
CGContextMoveToPoint(context, center.x, center.y);
CGContextAddArc(context, center.x, center.y, radius, startAngle, endAngle, 0);
CGContextClosePath(context);
CGContextFillPath(context);
}
}
#pragma mark - KVO
- (void)registerForKVO {
for (NSString *keyPathin [selfobservableKeypaths]) {
[selfaddObserver:selfforKeyPath:keyPath options:NSKeyValueObservingOptionNewcontext:NULL];
}
}
- (void)unregisterFromKVO {
for (NSString *keyPathin [selfobservableKeypaths]) {
[selfremoveObserver:selfforKeyPath:keyPath];
}
}
- (NSArray *)observableKeypaths {
return [NSArrayarrayWithObjects:@"progressTintColor",@"backgroundTintColor", @"progress", @"annular",nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[selfsetNeedsDisplay];
}
@end
@implementation MBBarProgressView
#pragma mark - Lifecycle
- (id)init {
return [selfinitWithFrame:CGRectMake(.0f,.0f, 120.0f, 20.0f)];
}
- (id)initWithFrame:(CGRect)frame {
self = [superinitWithFrame:frame];
if (self) {
_progress =0.f;
_lineColor = [UIColorwhiteColor];
_progressColor = [UIColorwhiteColor];
_progressRemainingColor = [UIColorclearColor];
self.backgroundColor = [UIColorclearColor];
self.opaque =NO;
[selfregisterForKVO];
}
returnself;
}
- (void)dealloc {
[selfunregisterFromKVO];
#if !__has_feature(objc_arc)
[_lineColor release];
[_progressColor release];
[_progressRemainingColor release];
[super dealloc];
#endif
}
#pragma mark - Drawing
- (void)drawRect:(CGRect)rect {
CGContextRef context =UIGraphicsGetCurrentContext();
CGContextSetLineWidth(context,2);
CGContextSetStrokeColorWithColor(context,[_lineColorCGColor]);
CGContextSetFillColorWithColor(context, [_progressRemainingColorCGColor]);
// Draw background
float radius = (rect.size.height /2) - 2;
CGContextMoveToPoint(context,2, rect.size.height/2);
CGContextAddArcToPoint(context,2, 2, radius +2, 2, radius);
CGContextAddLineToPoint(context, rect.size.width - radius -2, 2);
CGContextAddArcToPoint(context, rect.size.width -2, 2, rect.size.width -2, rect.size.height /2, radius);
CGContextAddArcToPoint(context, rect.size.width -2, rect.size.height -2, rect.size.width - radius -2, rect.size.height -2, radius);
CGContextAddLineToPoint(context, radius +2, rect.size.height -2);
CGContextAddArcToPoint(context,2, rect.size.height -2, 2, rect.size.height/2, radius);
CGContextFillPath(context);
// Draw border
CGContextMoveToPoint(context,2, rect.size.height/2);
CGContextAddArcToPoint(context,2, 2, radius +2, 2, radius);
CGContextAddLineToPoint(context, rect.size.width - radius -2, 2);
CGContextAddArcToPoint(context, rect.size.width -2, 2, rect.size.width -2, rect.size.height /2, radius);
CGContextAddArcToPoint(context, rect.size.width -2, rect.size.height -2, rect.size.width - radius -2, rect.size.height -2, radius);
CGContextAddLineToPoint(context, radius +2, rect.size.height -2);
CGContextAddArcToPoint(context,2, rect.size.height -2, 2, rect.size.height/2, radius);
CGContextStrokePath(context);
CGContextSetFillColorWithColor(context, [_progressColorCGColor]);
radius = radius - 2;
float amount =self.progress * rect.size.width;
// Progress in the middle area
if (amount >= radius +4 && amount <= (rect.size.width - radius -4)) {
CGContextMoveToPoint(context,4, rect.size.height/2);
CGContextAddArcToPoint(context,4, 4, radius +4, 4, radius);
CGContextAddLineToPoint(context, amount,4);
CGContextAddLineToPoint(context, amount, radius +4);
CGContextMoveToPoint(context,4, rect.size.height/2);
CGContextAddArcToPoint(context,4, rect.size.height -4, radius + 4, rect.size.height - 4, radius);
CGContextAddLineToPoint(context, amount, rect.size.height -4);
CGContextAddLineToPoint(context, amount, radius +4);
CGContextFillPath(context);
}
// Progress in the right arc
else if (amount > radius + 4) {
float x = amount - (rect.size.width - radius -4);
CGContextMoveToPoint(context,4, rect.size.height/2);
CGContextAddArcToPoint(context,4, 4, radius +4, 4, radius);
CGContextAddLineToPoint(context, rect.size.width - radius -4, 4);
float angle = -acos(x/radius);
if (isnan(angle)) angle =0;
CGContextAddArc(context, rect.size.width - radius -4, rect.size.height/2, radius,M_PI, angle, 0);
CGContextAddLineToPoint(context, amount, rect.size.height/2);
CGContextMoveToPoint(context,4, rect.size.height/2);
CGContextAddArcToPoint(context,4, rect.size.height -4, radius + 4, rect.size.height - 4, radius);
CGContextAddLineToPoint(context, rect.size.width - radius -4, rect.size.height -4);
angle = acos(x/radius);
if (isnan(angle)) angle =0;
CGContextAddArc(context, rect.size.width - radius -4, rect.size.height/2, radius, -M_PI, angle, 1);
CGContextAddLineToPoint(context, amount, rect.size.height/2);
CGContextFillPath(context);
}
// Progress is in the left arc
else if (amount < radius + 4 && amount >0) {
CGContextMoveToPoint(context,4, rect.size.height/2);
CGContextAddArcToPoint(context,4, 4, radius +4, 4, radius);
CGContextAddLineToPoint(context, radius +4, rect.size.height/2);
CGContextMoveToPoint(context,4, rect.size.height/2);
CGContextAddArcToPoint(context,4, rect.size.height -4, radius + 4, rect.size.height - 4, radius);
CGContextAddLineToPoint(context, radius +4, rect.size.height/2);
CGContextFillPath(context);
}
}
#pragma mark - KVO
- (void)registerForKVO {
for (NSString *keyPathin [selfobservableKeypaths]) {
[selfaddObserver:selfforKeyPath:keyPath options:NSKeyValueObservingOptionNewcontext:NULL];
}
}
- (void)unregisterFromKVO {
for (NSString *keyPathin [selfobservableKeypaths]) {
[selfremoveObserver:selfforKeyPath:keyPath];
}
}
- (NSArray *)observableKeypaths {
return [NSArrayarrayWithObjects:@"lineColor",@"progressRemainingColor",@"progressColor", @"progress", nil];
}
- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[selfsetNeedsDisplay];
}
@end