对MBProgressHUD进行二次封装并精简使用
对MBProgressHUD进行二次封装并精简使用
https://github.com/jdg/MBProgressHUD
几个效果图:
以下源码是MBProgressHUD支持最新的iOS8的版本,没有任何的警告信息
MBProgressHUD.h 与 MBProgressHUD.m
//
// MBProgressHUD.h
// Version 0.9
// Created by Matej Bukovinski on 2.4.09.
// // This code is distributed under the terms and conditions of the MIT license. // Copyright (c) 2013 Matej Bukovinski
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE. #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.h
//
// MBProgressHUD.m
// Version 0.9
// Created by Matej Bukovinski on 2.4.09.
// #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 const CGFloat kPadding = .f;
static const CGFloat kLabelFontSize = .f;
static const CGFloat kDetailsLabelFontSize = .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 = [[self alloc] initWithView:view];
hud.removeFromSuperViewOnHide = YES;
[view addSubview:hud];
[hud show:animated];
return MB_AUTORELEASE(hud);
} + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
MBProgressHUD *hud = [self HUDForView:view];
if (hud != nil) {
hud.removeFromSuperViewOnHide = YES;
[hud hide:animated];
return YES;
}
return NO;
} + (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated {
NSArray *huds = [MBProgressHUD allHUDsForView:view];
for (MBProgressHUD *hud in huds) {
hud.removeFromSuperViewOnHide = YES;
[hud hide:animated];
}
return [huds count];
} + (MB_INSTANCETYPE)HUDForView:(UIView *)view {
NSEnumerator *subviewsEnum = [view.subviews reverseObjectEnumerator];
for (UIView *subview in subviewsEnum) {
if ([subview isKindOfClass:self]) {
return (MBProgressHUD *)subview;
}
}
return nil;
} + (NSArray *)allHUDsForView:(UIView *)view {
NSMutableArray *huds = [NSMutableArray array];
NSArray *subviews = view.subviews;
for (UIView *aView in subviews) {
if ([aView isKindOfClass:self]) {
[huds addObject:aView];
}
}
return [NSArray arrayWithArray:huds];
} #pragma mark - Lifecycle - (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame: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 = [UIFont boldSystemFontOfSize:kLabelFontSize];
self.labelColor = [UIColor whiteColor];
self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize];
self.detailsLabelColor = [UIColor whiteColor];
self.activityIndicatorColor = [UIColor whiteColor];
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 = [UIColor clearColor];
// Make it invisible for now
self.alpha = 0.0f; taskInProgress = NO;
rotationTransform = CGAffineTransformIdentity; [self setupLabels];
[self updateIndicators];
[self registerForKVO];
[self registerForNotifications];
}
return self;
} - (id)initWithView:(UIView *)view {
NSAssert(view, @"View must not be nil.");
return [self initWithFrame:view.bounds];
} - (id)initWithWindow:(UIWindow *)window {
return [self initWithView:window];
} - (void)dealloc {
[self unregisterFromNotifications];
[self unregisterFromKVO];
#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 = [NSTimer scheduledTimerWithTimeInterval:self.graceTime target:self
selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
}
// ... otherwise show the HUD imediately
else {
[self setNeedsDisplay];
[self showUsingAnimation: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 = [[NSDate date] timeIntervalSinceDate:showStarted];
if (interv < self.minShowTime) {
self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv) target:self
selector:@selector(handleMinShowTimer:) userInfo:nil repeats:NO];
return;
}
}
// ... otherwise hide the HUD immediately
[self hideUsingAnimation:useAnimation];
} - (void)hide:(BOOL)animated afterDelay:(NSTimeInterval)delay {
[self performSelector:@selector(hideDelayed:) withObject:[NSNumber numberWithBool:animated] afterDelay:delay];
} - (void)hideDelayed:(NSNumber *)animated {
[self hide:[animated boolValue]];
} #pragma mark - Timer callbacks - (void)handleGraceTimer:(NSTimer *)theTimer {
// Show the HUD only if the task is still running
if (taskInProgress) {
[self setNeedsDisplay];
[self showUsingAnimation:useAnimation];
}
} - (void)handleMinShowTimer:(NSTimer *)theTimer {
[self hideUsingAnimation: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.superview isKindOfClass:[UIWindow class]];
} - (void)didMoveToSuperview {
if ([self shouldPerformOrientationTransform]) {
[self setTransformForCurrentOrientation:NO];
}
} #pragma mark - Internal show & hide operations - (void)showUsingAnimation:(BOOL)animated {
if (animated && animationType == MBProgressHUDAnimationZoomIn) {
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f));
} else if (animated && animationType == MBProgressHUDAnimationZoomOut) {
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f));
}
self.showStarted = [NSDate date];
// Fade in
if (animated) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.30];
self.alpha = 1.0f;
if (animationType == MBProgressHUDAnimationZoomIn || animationType == MBProgressHUDAnimationZoomOut) {
self.transform = rotationTransform;
}
[UIView commitAnimations];
}
else {
self.alpha = 1.0f;
}
} - (void)hideUsingAnimation:(BOOL)animated {
// Fade out
if (animated && showStarted) {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.30];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:@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));
} else if (animationType == MBProgressHUDAnimationZoomOut) {
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5f, 0.5f));
} self.alpha = 0.02f;
[UIView commitAnimations];
}
else {
self.alpha = 0.0f;
[self done];
}
self.showStarted = nil;
} - (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
[self done];
} - (void)done {
[NSObject cancelPreviousPerformRequestsWithTarget:self];
isFinished = YES;
self.alpha = 0.0f;
if (removeFromSuperViewOnHide) {
[self removeFromSuperview];
}
#if NS_BLOCKS_AVAILABLE
if (self.completionBlock) {
self.completionBlock();
self.completionBlock = NULL;
}
#endif
if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
[delegate performSelector:@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;
[NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil];
// Show HUD view
[self show: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, );
[self showAnimated: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, );
[self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock:completion];
} - (void)showAnimated:(BOOL)animated whileExecutingBlock:(dispatch_block_t)block onQueue:(dispatch_queue_t)queue {
[self showAnimated:animated whileExecutingBlock:block onQueue:queue completionBlock: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) {
[self cleanUp];
});
});
[self show:animated];
} #endif - (void)launchExecution {
@autoreleasepool {
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Warc-performSelector-leaks"
// Start executing the requested task
[targetForExecution performSelector:methodForExecution withObject:objectForExecution];
#pragma clang diagnostic pop
// Task completed, update view in main thread (note: view operations should
// be done only in the main thread)
[self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
}
} - (void)cleanUp {
taskInProgress = NO;
#if !__has_feature(objc_arc)
[targetForExecution release];
[objectForExecution release];
#else
targetForExecution = nil;
objectForExecution = nil;
#endif
[self hide:useAnimation];
} #pragma mark - UI - (void)setupLabels {
label = [[UILabel alloc] initWithFrame:self.bounds];
label.adjustsFontSizeToFitWidth = NO;
label.textAlignment = MBLabelAlignmentCenter;
label.opaque = NO;
label.backgroundColor = [UIColor clearColor];
label.textColor = self.labelColor;
label.font = self.labelFont;
label.text = self.labelText;
[self addSubview:label]; detailsLabel = [[UILabel alloc] initWithFrame:self.bounds];
detailsLabel.font = self.detailsLabelFont;
detailsLabel.adjustsFontSizeToFitWidth = NO;
detailsLabel.textAlignment = MBLabelAlignmentCenter;
detailsLabel.opaque = NO;
detailsLabel.backgroundColor = [UIColor clearColor];
detailsLabel.textColor = self.detailsLabelColor;
detailsLabel.numberOfLines = ;
detailsLabel.font = self.detailsLabelFont;
detailsLabel.text = self.detailsLabelText;
[self addSubview:detailsLabel];
} - (void)updateIndicators { BOOL isActivityIndicator = [indicator isKindOfClass:[UIActivityIndicatorView class]];
BOOL isRoundIndicator = [indicator isKindOfClass:[MBRoundProgressView class]]; if (mode == MBProgressHUDModeIndeterminate) {
if (!isActivityIndicator) {
// Update to indeterminate indicator
[indicator removeFromSuperview];
self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc]
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]);
[(UIActivityIndicatorView *)indicator startAnimating];
[self addSubview:indicator];
}
#if __IPHONE_OS_VERSION_MIN_REQUIRED >= 50000
[(UIActivityIndicatorView *)indicator setColor:self.activityIndicatorColor];
#endif
}
else if (mode == MBProgressHUDModeDeterminateHorizontalBar) {
// Update to bar determinate indicator
[indicator removeFromSuperview];
self.indicator = MB_AUTORELEASE([[MBBarProgressView alloc] init]);
[self addSubview:indicator];
}
else if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) {
if (!isRoundIndicator) {
// Update to determinante indicator
[indicator removeFromSuperview];
self.indicator = MB_AUTORELEASE([[MBRoundProgressView alloc] init]);
[self addSubview:indicator];
}
if (mode == MBProgressHUDModeAnnularDeterminate) {
[(MBRoundProgressView *)indicator setAnnular:YES];
}
}
else if (mode == MBProgressHUDModeCustomView && customView != indicator) {
// Update custom view indicator
[indicator removeFromSuperview];
self.indicator = customView;
[self addSubview:indicator];
} else if (mode == MBProgressHUDModeText) {
[indicator removeFromSuperview];
self.indicator = nil;
}
} #pragma mark - Layout - (void)layoutSubviews {
[super layoutSubviews]; // Entirely cover the parent view
UIView *parent = self.superview;
if (parent) {
self.frame = parent.bounds;
}
CGRect bounds = self.bounds; // Determine the total width and height needed
CGFloat maxWidth = CGRectGetWidth(bounds) - * margin;
CGSize totalSize = CGSizeZero; CGRect indicatorF = indicator.bounds;
indicatorF.size.width = MIN(CGRectGetWidth(indicatorF), maxWidth);
totalSize.width = MAX(totalSize.width, CGRectGetWidth(indicatorF));
totalSize.height += CGRectGetHeight(indicatorF); 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 > .f && CGRectGetHeight(indicatorF) > .f) {
totalSize.height += kPadding;
} CGFloat remainingHeight = CGRectGetHeight(bounds) - totalSize.height - kPadding - * 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 > .f && (indicatorF.size.height > .f || labelSize.height > .f)) {
totalSize.height += kPadding;
} totalSize.width += * margin;
totalSize.height += * margin; // Position elements
CGFloat yPos = round(((CGRectGetHeight(bounds) - totalSize.height) / )) + margin + yOffset;
CGFloat xPos = xOffset;
indicatorF.origin.y = yPos;
indicatorF.origin.x = round((CGRectGetWidth(bounds) - CGRectGetWidth(indicatorF)) / ) + xPos;
indicator.frame = indicatorF;
yPos += CGRectGetHeight(indicatorF); if (labelSize.height > .f && CGRectGetHeight(indicatorF) > .f) {
yPos += kPadding;
}
CGRect labelF;
labelF.origin.y = yPos;
labelF.origin.x = round((CGRectGetWidth(bounds) - labelSize.width) / ) + xPos;
labelF.size = labelSize;
label.frame = labelF;
yPos += labelF.size.height; if (detailsLabelSize.height > .f && (CGRectGetHeight(indicatorF) > .f || labelSize.height > .f)) {
yPos += kPadding;
}
CGRect detailsLabelF;
detailsLabelF.origin.y = yPos;
detailsLabelF.origin.x = round((CGRectGetWidth(bounds) - detailsLabelSize.width) / ) + 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 - * margin) {
totalSize.width = max;
}
if (max <= bounds.size.height - * 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 = ;
CGFloat gradLocations[] = {0.0f, 1.0f};
CGFloat gradColors[] = {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(CGRectGetWidth(self.bounds)/, CGRectGetHeight(self.bounds)/);
//Gradient radius
float gradRadius = MIN(CGRectGetWidth(self.bounds), CGRectGetHeight(self.bounds)) ;
//Gradient draw
CGContextDrawRadialGradient (context, gradient, gradCenter,
, 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((CGRectGetWidth(allRect) - size.width) / ) + self.xOffset,
round((CGRectGetHeight(allRect) - size.height) / ) + 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, * (float)M_PI / , , );
CGContextAddArc(context, CGRectGetMaxX(boxRect) - radius, CGRectGetMaxY(boxRect) - radius, radius, , (float)M_PI / , );
CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMaxY(boxRect) - radius, radius, (float)M_PI / , (float)M_PI, );
CGContextAddArc(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect) + radius, radius, (float)M_PI, * (float)M_PI / , );
CGContextClosePath(context);
CGContextFillPath(context); UIGraphicsPopContext();
} #pragma mark - KVO - (void)registerForKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
}
} - (void)unregisterFromKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self removeObserver:self forKeyPath:keyPath];
}
} - (NSArray *)observableKeypaths {
return [NSArray arrayWithObjects:@"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 (![NSThread isMainThread]) {
[self performSelectorOnMainThread:@selector(updateUIForKeypath:) withObject:keyPath waitUntilDone:NO];
} else {
[self updateUIForKeypath:keyPath];
}
} - (void)updateUIForKeypath:(NSString *)keyPath {
if ([keyPath isEqualToString:@"mode"] || [keyPath isEqualToString:@"customView"] ||
[keyPath isEqualToString:@"activityIndicatorColor"]) {
[self updateIndicators];
} else if ([keyPath isEqualToString:@"labelText"]) {
label.text = self.labelText;
} else if ([keyPath isEqualToString:@"labelFont"]) {
label.font = self.labelFont;
} else if ([keyPath isEqualToString:@"labelColor"]) {
label.textColor = self.labelColor;
} else if ([keyPath isEqualToString:@"detailsLabelText"]) {
detailsLabel.text = self.detailsLabelText;
} else if ([keyPath isEqualToString:@"detailsLabelFont"]) {
detailsLabel.font = self.detailsLabelFont;
} else if ([keyPath isEqualToString:@"detailsLabelColor"]) {
detailsLabel.textColor = self.detailsLabelColor;
} else if ([keyPath isEqualToString:@"progress"]) {
if ([indicator respondsToSelector:@selector(setProgress:)]) {
[(id)indicator setValue:@(progress) forKey:@"progress"];
}
return;
}
[self setNeedsLayout];
[self setNeedsDisplay];
} #pragma mark - Notifications - (void)registerForNotifications {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter]; [nc addObserver:self selector:@selector(statusBarOrientationDidChange:)
name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
} - (void)unregisterFromNotifications {
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
[nc removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil];
} - (void)statusBarOrientationDidChange:(NSNotification *)notification {
UIView *superview = self.superview;
if (!superview) {
return;
} else if ([self shouldPerformOrientationTransform]) {
[self setTransformForCurrentOrientation:YES];
} else {
self.frame = self.superview.bounds;
[self setNeedsDisplay];
}
} - (void)setTransformForCurrentOrientation:(BOOL)animated {
// Stay in sync with the superview
if (self.superview) {
self.bounds = self.superview.bounds;
[self setNeedsDisplay];
} // Window coordinates differ below iOS8
// In iOS8 the UIScreen's bounds now interface-oriented
// more see https://developer.apple.com/videos/wwdc/2014/#214
CGFloat radians = ;
if (NSFoundationVersionNumber < kCFCoreFoundationVersionNumber_iOS_8_0) {
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
if (UIInterfaceOrientationIsLandscape(orientation)) {
if (orientation == UIInterfaceOrientationLandscapeLeft) {
radians = -(CGFloat)M_PI_2;
} else {
radians = (CGFloat)M_PI_2;
}
self.bounds = CGRectMake(, , CGRectGetHeight(self.bounds), CGRectGetWidth(self.bounds));
} else {
if (orientation == UIInterfaceOrientationPortraitUpsideDown) {
radians = (CGFloat)M_PI;
} else {
radians = ;
}
}
}
rotationTransform = CGAffineTransformMakeRotation(radians); if (animated) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.3];
}
[self setTransform:rotationTransform];
if (animated) {
[UIView commitAnimations];
}
} @end @implementation MBRoundProgressView #pragma mark - Lifecycle - (id)init {
return [self initWithFrame:CGRectMake(.f, .f, .f, .f)];
} - (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
_progress = .f;
_annular = NO;
_progressTintColor = [[UIColor alloc] initWithWhite:.f alpha:.f];
_backgroundTintColor = [[UIColor alloc] initWithWhite:.f alpha:.1f];
[self registerForKVO];
}
return self;
} - (void)dealloc {
[self unregisterFromKVO];
#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 ? .f : .f;
UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath];
processBackgroundPath.lineWidth = lineWidth;
processBackgroundPath.lineCapStyle = kCGLineCapButt;
CGPoint center = CGPointMake(CGRectGetWidth(self.bounds)/, CGRectGetHeight(self.bounds)/);
CGFloat radius = (CGRectGetWidth(self.bounds) - lineWidth)/;
CGFloat startAngle = - ((float)M_PI / ); // 90 degrees
CGFloat endAngle = ( * (float)M_PI) + startAngle;
[processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[_backgroundTintColor set];
[processBackgroundPath stroke];
// Draw progress
UIBezierPath *processPath = [UIBezierPath bezierPath];
processPath.lineCapStyle = isPreiOS7 ? kCGLineCapRound : kCGLineCapSquare;
processPath.lineWidth = lineWidth;
endAngle = (self.progress * * (float)M_PI) + startAngle;
[processPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[_progressTintColor set];
[processPath stroke];
} else {
// Draw background
[_progressTintColor setStroke];
[_backgroundTintColor setFill];
CGContextSetLineWidth(context, 2.0f);
CGContextFillEllipseInRect(context, circleRect);
CGContextStrokeEllipseInRect(context, circleRect);
// Draw progress
CGPoint center = CGPointMake(CGRectGetWidth(allRect) / , CGRectGetHeight(allRect) / );
CGFloat radius = (CGRectGetWidth(allRect) - ) / ;
CGFloat startAngle = - ((float)M_PI / ); // 90 degrees
CGFloat endAngle = (self.progress * * (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, );
CGContextClosePath(context);
CGContextFillPath(context);
}
} #pragma mark - KVO - (void)registerForKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
}
} - (void)unregisterFromKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self removeObserver:self forKeyPath:keyPath];
}
} - (NSArray *)observableKeypaths {
return [NSArray arrayWithObjects:@"progressTintColor", @"backgroundTintColor", @"progress", @"annular", nil];
} - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[self setNeedsDisplay];
} @end @implementation MBBarProgressView #pragma mark - Lifecycle - (id)init {
return [self initWithFrame:CGRectMake(.0f, .0f, 120.0f, 20.0f)];
} - (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
if (self) {
_progress = .f;
_lineColor = [UIColor whiteColor];
_progressColor = [UIColor whiteColor];
_progressRemainingColor = [UIColor clearColor];
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
[self registerForKVO];
}
return self;
} - (void)dealloc {
[self unregisterFromKVO];
#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, );
CGContextSetStrokeColorWithColor(context,[_lineColor CGColor]);
CGContextSetFillColorWithColor(context, [_progressRemainingColor CGColor]); // Draw background
float radius = (CGRectGetHeight(rect) / ) - ;
CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , , radius + , , radius);
CGContextAddLineToPoint(context, CGRectGetWidth(rect) - radius - , );
CGContextAddArcToPoint(context, CGRectGetWidth(rect) - , , CGRectGetWidth(rect) - , CGRectGetHeight(rect) / , radius);
CGContextAddArcToPoint(context, CGRectGetWidth(rect) - , CGRectGetHeight(rect) - , CGRectGetWidth(rect) - radius - , CGRectGetHeight(rect) - , radius);
CGContextAddLineToPoint(context, radius + , CGRectGetHeight(rect) - );
CGContextAddArcToPoint(context, , CGRectGetHeight(rect) - , , CGRectGetHeight(rect)/, radius);
CGContextFillPath(context); // Draw border
CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , , radius + , , radius);
CGContextAddLineToPoint(context, CGRectGetWidth(rect) - radius - , );
CGContextAddArcToPoint(context, CGRectGetWidth(rect) - , , CGRectGetWidth(rect) - , CGRectGetHeight(rect) / , radius);
CGContextAddArcToPoint(context, CGRectGetWidth(rect) - , CGRectGetHeight(rect) - , CGRectGetWidth(rect) - radius - , CGRectGetHeight(rect) - , radius);
CGContextAddLineToPoint(context, radius + , CGRectGetHeight(rect) - );
CGContextAddArcToPoint(context, , CGRectGetHeight(rect) - , , CGRectGetHeight(rect)/, radius);
CGContextStrokePath(context); CGContextSetFillColorWithColor(context, [_progressColor CGColor]);
radius = radius - ;
float amount = self.progress * CGRectGetWidth(rect); // Progress in the middle area
if (amount >= radius + && amount <= (CGRectGetWidth(rect) - radius - )) {
CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , , radius + , , radius);
CGContextAddLineToPoint(context, amount, );
CGContextAddLineToPoint(context, amount, radius + ); CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , CGRectGetHeight(rect) - , radius + , CGRectGetHeight(rect) - , radius);
CGContextAddLineToPoint(context, amount, CGRectGetHeight(rect) - );
CGContextAddLineToPoint(context, amount, radius + ); CGContextFillPath(context);
} // Progress in the right arc
else if (amount > radius + ) {
float x = amount - (CGRectGetWidth(rect) - radius - ); CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , , radius + , , radius);
CGContextAddLineToPoint(context, CGRectGetWidth(rect) - radius - , );
float angle = -acos(x/radius);
if (isnan(angle)) angle = ;
CGContextAddArc(context, CGRectGetWidth(rect) - radius - , CGRectGetHeight(rect)/, radius, M_PI, angle, );
CGContextAddLineToPoint(context, amount, CGRectGetHeight(rect)/); CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , CGRectGetHeight(rect) - , radius + , CGRectGetHeight(rect) - , radius);
CGContextAddLineToPoint(context, CGRectGetWidth(rect) - radius - , CGRectGetHeight(rect) - );
angle = acos(x/radius);
if (isnan(angle)) angle = ;
CGContextAddArc(context, CGRectGetWidth(rect) - radius - , CGRectGetHeight(rect)/, radius, -M_PI, angle, );
CGContextAddLineToPoint(context, amount, CGRectGetHeight(rect)/); CGContextFillPath(context);
} // Progress is in the left arc
else if (amount < radius + && amount > ) {
CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , , radius + , , radius);
CGContextAddLineToPoint(context, radius + , CGRectGetHeight(rect)/); CGContextMoveToPoint(context, , CGRectGetHeight(rect)/);
CGContextAddArcToPoint(context, , CGRectGetHeight(rect) - , radius + , CGRectGetHeight(rect) - , radius);
CGContextAddLineToPoint(context, radius + , CGRectGetHeight(rect)/); CGContextFillPath(context);
}
} #pragma mark - KVO - (void)registerForKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self addObserver:self forKeyPath:keyPath options:NSKeyValueObservingOptionNew context:NULL];
}
} - (void)unregisterFromKVO {
for (NSString *keyPath in [self observableKeypaths]) {
[self removeObserver:self forKeyPath:keyPath];
}
} - (NSArray *)observableKeypaths {
return [NSArray arrayWithObjects:@"lineColor", @"progressRemainingColor", @"progressColor", @"progress", nil];
} - (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary *)change context:(void *)context {
[self setNeedsDisplay];
} @end
MBProgressHUD.m
以下是本人在MBProgressHUD基础上封装的类,觉得部分的使用基于block
ShowHUD.h 与 ShowHUD.m
//
// ShowHUD.h
// TestHUD
//
// Created by YouXianMing on 14-9-29.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
// #import <Foundation/Foundation.h>
#import "MBProgressHUD.h"
@class ShowHUD; // 定义block
typedef void (^ConfigShowHUDBlock)(ShowHUD *config);
typedef UIView *(^ConfigShowHUDCustomViewBlock)(); // 定义枚举值
typedef enum {
Fade = MBProgressHUDAnimationFade,
Zoom = MBProgressHUDAnimationZoom,
ZoomOut = MBProgressHUDAnimationZoomOut,
ZoomIn = MBProgressHUDAnimationZoomIn,
} HUDAnimationType; @interface ShowHUD : NSObject // 动画效果
@property (nonatomic, assign) HUDAnimationType animationStyle; // 动画样式 // 文本加菊花
@property (nonatomic, strong) NSString *text; // 文本
@property (nonatomic, strong) UIFont *textFont; // 文本字体 // 自定义view
@property (nonatomic, strong) UIView *customView; // 自定义view 37x37尺寸 // 只显示文本的相关设置
@property (nonatomic, assign) BOOL showTextOnly; // 只显示文本 // 边缘留白
@property (nonatomic, assign) float margin; // 边缘留白 // 颜色设置(设置了颜色之后,透明度就会失效)
@property (nonatomic, strong) UIColor *backgroundColor; // 背景颜色
@property (nonatomic, strong) UIColor *labelColor; // 文本颜色 // 透明度
@property (nonatomic, assign) float opacity; // 透明度 // 圆角
@property (nonatomic, assign) float cornerRadius; // 圆角 // 仅仅显示文本并持续几秒的方法
/* - 使用示例 -
[ShowHUD showTextOnly:@"请稍后,显示不了..."
configParameter:^(ShowHUD *config) {
config.margin = 10.f; // 边缘留白
config.opacity = 0.7f; // 设定透明度
config.cornerRadius = 2.f; // 设定圆角
} duration:3 inView:self.view];
*/
+ (void)showTextOnly:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
duration:(NSTimeInterval)sec
inView:(UIView *)view; // 显示文本与菊花并持续几秒的方法(文本为nil时只显示菊花)
/* - 使用示例 -
[ShowHUD showText:@"请稍后,显示不了..."
configParameter:^(ShowHUD *config) {
config.margin = 10.f; // 边缘留白
config.opacity = 0.7f; // 设定透明度
config.cornerRadius = 2.f; // 设定圆角
} duration:3 inView:self.view];
*/
+ (void)showText:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
duration:(NSTimeInterval)sec
inView:(UIView *)view; // 加载自定义view并持续几秒的方法
/* - 使用示例 -
[ShowHUD showText:@"请稍后,显示不了..."
configParameter:^(ShowHUD *config) {
config.margin = 10.f; // 边缘留白
config.opacity = 0.7f; // 设定透明度
config.cornerRadius = 2.f; // 设定圆角
} duration:3 inView:self.view];
*/
+ (void)showCustomView:(ConfigShowHUDCustomViewBlock)viewBlock
configParameter:(ConfigShowHUDBlock)config
duration:(NSTimeInterval)sec
inView:(UIView *)view; + (instancetype)showTextOnly:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
inView:(UIView *)view;
+ (instancetype)showText:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
inView:(UIView *)view;
+ (instancetype)showCustomView:(ConfigShowHUDCustomViewBlock)viewBlock
configParameter:(ConfigShowHUDBlock)config
inView:(UIView *)view;
- (void)hide; @end
//
// ShowHUD.m
// TestHUD
//
// Created by YouXianMing on 14-9-29.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
// #import "ShowHUD.h" #ifdef DEBUG
#define ShowHUD_DLog(fmt, ...) NSLog((@"ShowHUD.m:%s:%d" fmt), __PRETTY_FUNCTION__, __LINE__, ##__VA_ARGS__);
#else
#define ShowHUD_DLog(...)
#endif @interface ShowHUD ()<MBProgressHUDDelegate> {
MBProgressHUD *_hud;
} @end @implementation ShowHUD - (instancetype)initWithView:(UIView *)view
{
if (view == nil) {
return nil;
} self = [super init];
if (self) {
_hud = [[MBProgressHUD alloc] initWithView:view];
_hud.delegate = self; // 设置代理
_hud.animationType = MBProgressHUDAnimationZoom; // 默认动画样式
_hud.removeFromSuperViewOnHide = YES; // 该视图隐藏后则自动从父视图移除掉 [view addSubview:_hud];
}
return self;
} - (void)hide:(BOOL)hide afterDelay:(NSTimeInterval)delay
{
[_hud hide:hide afterDelay:delay];
} - (void)hide
{
[_hud hide:YES];
} - (void)show:(BOOL)show
{
// 根据属性判断是否要显示文本
if (_text != nil && _text.length != ) {
_hud.labelText = _text;
} // 设置文本字体
if (_textFont) {
_hud.labelFont = _textFont;
} // 如果设置这个属性,则只显示文本
if (_showTextOnly == YES && _text != nil && _text.length != ) {
_hud.mode = MBProgressHUDModeText;
} // 设置背景色
if (_backgroundColor) {
_hud.color = _backgroundColor;
} // 文本颜色
if (_labelColor) {
_hud.labelColor = _labelColor;
} // 设置圆角
if (_cornerRadius) {
_hud.cornerRadius = _cornerRadius;
} // 设置透明度
if (_opacity) {
_hud.opacity = _opacity;
} // 自定义view
if (_customView) {
_hud.mode = MBProgressHUDModeCustomView;
_hud.customView = _customView;
} // 边缘留白
if (_margin > ) {
_hud.margin = _margin;
} [_hud show:show];
} #pragma mark - HUD代理方法
- (void)hudWasHidden:(MBProgressHUD *)hud
{
[_hud removeFromSuperview];
_hud = nil;
} #pragma mark - 重写setter方法
@synthesize animationStyle = _animationStyle;
- (void)setAnimationStyle:(HUDAnimationType)animationStyle
{
_animationStyle = animationStyle;
_hud.animationType = (MBProgressHUDAnimation)_animationStyle;
}
- (HUDAnimationType)animationStyle
{
return _animationStyle;
} #pragma mark - 便利的方法
+ (void)showTextOnly:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
duration:(NSTimeInterval)sec
inView:(UIView *)view
{
ShowHUD *hud = [[ShowHUD alloc] initWithView:view];
hud.text = text;
hud.showTextOnly = YES;
hud.margin = .f; // 配置额外的参数
config(hud); // 显示
[hud show:YES]; // 延迟sec后消失
[hud hide:YES afterDelay:sec];
} + (void)showText:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
duration:(NSTimeInterval)sec
inView:(UIView *)view
{
ShowHUD *hud = [[ShowHUD alloc] initWithView:view];
hud.text = text;
hud.margin = .f; // 配置额外的参数
config(hud); // 显示
[hud show:YES]; // 延迟sec后消失
[hud hide:YES afterDelay:sec];
} + (void)showCustomView:(ConfigShowHUDCustomViewBlock)viewBlock
configParameter:(ConfigShowHUDBlock)config
duration:(NSTimeInterval)sec
inView:(UIView *)view
{
ShowHUD *hud = [[ShowHUD alloc] initWithView:view];
hud.margin = .f; // 配置额外的参数
config(hud); // 自定义View
hud.customView = viewBlock(); // 显示
[hud show:YES]; [hud hide:YES afterDelay:sec];
} + (instancetype)showTextOnly:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
inView:(UIView *)view
{
ShowHUD *hud = [[ShowHUD alloc] initWithView:view];
hud.text = text;
hud.showTextOnly = YES;
hud.margin = .f; // 配置额外的参数
config(hud); // 显示
[hud show:YES]; return hud;
} + (instancetype)showText:(NSString *)text
configParameter:(ConfigShowHUDBlock)config
inView:(UIView *)view
{
ShowHUD *hud = [[ShowHUD alloc] initWithView:view];
hud.text = text;
hud.margin = .f; // 配置额外的参数
config(hud); // 显示
[hud show:YES]; return hud;
} + (instancetype)showCustomView:(ConfigShowHUDCustomViewBlock)viewBlock
configParameter:(ConfigShowHUDBlock)config
inView:(UIView *)view
{
ShowHUD *hud = [[ShowHUD alloc] initWithView:view];
hud.margin = .f; // 配置额外的参数
config(hud); // 自定义View
hud.customView = viewBlock(); // 显示
[hud show:YES]; return hud;
} - (void)dealloc
{
ShowHUD_DLog(@"资源释放了,没有泄露^_^");
} @end
使用时候的源码如下:
//
// ViewController.m
// TestHUD
//
// Created by YouXianMing on 14-9-29.
// Copyright (c) 2014年 YouXianMing. All rights reserved.
// #import "ViewController.h"
#import "ShowHUD.h" // 引入头文件 typedef enum : NSUInteger {
CASE_1, // 显示文本和菊花,延时3秒后消失
CASE_2, // 仅仅显示文本,延时3秒后消失
CASE_3, // 加载自定义view,3秒后消失
} E_CASE; @interface ViewController ()<MBProgressHUDDelegate> @property (nonatomic, assign) NSInteger caseType; @end @implementation ViewController - (void)showHUD
{
UIWindow *window = [UIApplication sharedApplication].keyWindow; switch (_caseType++ % ) { case CASE_1: {
[ShowHUD showText:@"YouXianMing"
configParameter:^(ShowHUD *config) {
config.margin = .f; // 边缘留白
config.opacity = 0.7f; // 设定透明度
config.cornerRadius = .f; // 设定圆角
config.textFont = [UIFont systemFontOfSize:.f];
} duration: inView:window];
} break; case CASE_2: {
[ShowHUD showTextOnly:@"YouXianMing"
configParameter:^(ShowHUD *config) {
config.animationStyle = ZoomOut; // 设置动画方式
config.margin = .f; // 边缘留白
config.opacity = 0.8f; // 设定透明度
config.cornerRadius = 0.1f; // 设定圆角
config.backgroundColor = [[UIColor redColor] colorWithAlphaComponent:0.8]; // 设置背景色
config.labelColor = [[UIColor whiteColor] colorWithAlphaComponent:1.0];// 设置文本颜色
} duration: inView:window];
} break; // case CASE_3: {
// BackgroundView *backView = [[BackgroundView alloc] initInView:window];
// backView.startDuration = 0.25;
// backView.endDuration = 0.25;
// [backView addToView];
//
// ShowHUD *hud = [ShowHUD showCustomView:^UIView *{
// // 返回一个自定义view即可,hud会自动根据你返回的view调整空间
// MulticolorView *showView = [[MulticolorView alloc] initWithFrame:CGRectMake(0, 0, 40, 40)];
// showView.lineWidth = 1.f;
// showView.sec = 1.5f;
// showView.colors = @[(id)[UIColor cyanColor].CGColor,
// (id)[UIColor yellowColor].CGColor,
// (id)[UIColor cyanColor].CGColor];
// [showView startAnimation];
// return showView;
// } configParameter:^(ShowHUD *config) {
// config.animationStyle = Zoom; // 设定动画方式
// config.margin = 10.f; // 边缘留白
// config.cornerRadius = 2.f; // 边缘圆角
// config.backgroundColor = [[UIColor blackColor] colorWithAlphaComponent:0.4f];
// } inView:window];
//
// // 延迟5秒后消失
// [GCDQueue executeInMainQueue:^{
// [hud hide];
// [backView removeSelf];
// } afterDelaySecs:5];
// } break; default:
break;
}
} - (void)viewDidLoad {
[super viewDidLoad]; _caseType = ; UIButton *button = [[UIButton alloc] initWithFrame:self.view.bounds];
[self.view addSubview:button];
[button addTarget:self
action:@selector(buttonEvent:)
forControlEvents:UIControlEventTouchUpInside];
} - (void)buttonEvent:(id)sender
{
[self showHUD];
} @end
以下是使用上的一些小细节
对MBProgressHUD进行二次封装并精简使用的更多相关文章
- iOS基于MBProgressHUD的二次封装,一行搞定,使用超简单
MBProgressHUD的使用,临时总结了几款最常用的使用场景: 1.提示消息 用法: [YJProgressHUD showMessage:@"显示文字,1s隐藏" inVie ...
- AFNetworking3.0+MBProgressHUD二次封装,一句话搞定网络提示
对AFNetworking3.0+MBProgressHUD的二次封装,使用更方便,适用性非常强: 一句话搞定网络提示: 再也不用担心网络库更新后,工程要修改很多地方了!网络库更新了只需要更新这个封装 ...
- 对百度WebUploader的二次封装,精简前端代码之图片预览上传(两句代码搞定上传)
前言 本篇文章上一篇: 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传) 此篇是在上面的基础上扩展出来专门上传图片的控件封装. 首先我们看看效果: 正文 使用方式同 ...
- ios MBProgressHUD 使用,及二次封装
MBProgressHUD是一个显示HUD窗口的第三方类库,用于在执行一些后台任务时,在程序中显示一个表示进度的loading视图和两个可选的文本提示的HUD窗口.MBProgressHUD 二次封装 ...
- 对百度WebUploader开源上传控件的二次封装,精简前端代码(两句代码搞定上传)
前言 首先声明一下,我这个是对WebUploader开源上传控件的二次封装,底层还是WebUploader实现的,只是为了更简洁的使用他而已. 下面先介绍一下WebUploader 简介: WebUp ...
- element-UI el-table二次封装
Part.1 为什么要二次封装? 这是 Element 网站的 table 示例: <template> <el-table :data="tableData" ...
- element el-table表格的vue组件二次封装(附表格高度自适应)
基于vue的el-table表格二次封装组件方法 前言 在公司实习使用vue+element-ui框架进行前端开发,使用表格el-table较为多,有些业务逻辑比较相似,有些地方使用的重复性高,如果多 ...
- iOS项目相关@AFN&SDWeb的二次封装
一,AFNetworking跟SDWebImge是功能强大且常用的第三方,然而在实际应用中需要封装用来复用今天就跟大家分享一下AFN&SDWeb的二次封装 1. HttpClient.h及.m ...
- Quick Cocos (2.2.5plus)CoinFlip解析(MenuScene display AdBar二次封装)
转载自:http://cn.cocos2d-x.org/tutorial/show?id=1621 从Samples中找到CoinFlip文件夹,复制其中的 res 和 script 文件夹覆盖新建工 ...
随机推荐
- 解决python3与python2的pip命令冲突问题冲突(window版)
解决方法再上一篇有大概讲解: python开发环境安装配置 这里做一些补充: 上一篇说过,删除python3和python2中的python.exe文件后关闭dos窗口,重新打开dos,就可以进行安装 ...
- 转--log4j.properties 详解与配置步骤
一.log4j.properties 的使用详解 1.输出级别的种类 ERROR.WARN.INFO.DEBUGERROR 为严重错误 主要是程序的错误WARN 为一般警告,比如session丢失IN ...
- php在浏览器禁止cookie后,仍然能使用session的方法
1.a.php页面 session_start(); $_SESSION['msg'] = "i love you"; $sn = session_id();//获取当前sessi ...
- C语言利用异或进行两个值的交换
异或有两个很重要的性质: 1. A^A = 0; 2.A^0 = A; 利用这两个性质,我们就能够利用异或进行两个值的交换. 代码如下: #include <stdio.h> int ma ...
- Spring IOC(DI)
软件152 余建强 1 什么是IOC IOC—Inversion of Control,即“控制反转”,不是什么技术,而是一种设计思想.在Java开发中,Ioc意味着将你设计好的对象交给容器控制,而不 ...
- 一张图解决Struts2添加源码
主要是选择的路径:F:/struts2/struts-2.3.31/src/core/src/main/java
- histoty显示时间戳
设置Linux可以查看历史命令的执行时间 大家都知道Linux平台上,可以通过history命令查看最近所执行过的命令,但history命令默认所显示的只有编号和命令的,只知道命令是最近所执行 ...
- 修改MVC视图默认搜索规则(IViewEngine)
前几天我自己在写一个系统,写到后台管理系统的时候,我突然有个想法就是:想在区域视图下新建文件,单独处理后台一些业务:Area/AdminManager/View/Content/Index.cshtm ...
- 《JavaWeb从入门到改行》JDBC经典秘方QueryRunner
目录: 基础篇_功能各自回顾 JDBC基础代码回顾(使用JdbcUtils工具简化) c3p0数据库连接池的使用(使用JdbcUtils工具简化) 大数据的插入(使用c3p0+JdbcUtils工具简 ...
- 通过ifrmae异步下载文档
//通过ifrmae异步下载文档 function iframeGetFile(opts) { var defaultOpts = { filePath: '', onload: function ( ...