diff --git a/Demo/Classes/HudDemoViewController.m b/Demo/Classes/HudDemoViewController.m
index 3a54be67e..df1971635 100644
--- a/Demo/Classes/HudDemoViewController.m
+++ b/Demo/Classes/HudDemoViewController.m
@@ -188,6 +188,20 @@ - (IBAction)showWithGradient:(id)sender {
[HUD showWhileExecuting:@selector(myTask) onTarget:self withObject:nil animated:YES];
}
+- (IBAction)showTextOnly:(id)sender {
+
+ MBProgressHUD *hud = [MBProgressHUD showHUDAddedTo:self.navigationController.view animated:YES];
+
+ // Configure for text only and offset down
+ hud.mode = MBProgressHUDModeText;
+ hud.labelText = @"Some message...";
+ hud.margin = 10.f;
+ hud.yOffset = 150.f;
+ hud.removeFromSuperViewOnHide = YES;
+
+ [hud hide:YES afterDelay:3];
+}
+
#pragma mark -
#pragma mark Execution code
diff --git a/Demo/en.lproj/HudDemoViewController.xib b/Demo/en.lproj/HudDemoViewController.xib
index 44847e713..77216a43c 100644
--- a/Demo/en.lproj/HudDemoViewController.xib
+++ b/Demo/en.lproj/HudDemoViewController.xib
@@ -299,13 +299,37 @@
{{20, 499}, {280, 40}}
+
NO
NO
IBCocoaTouchFramework
0
3
1
- With Gradient
+ Dim background
+
+
+
+
+
+
+
- {320, 546}
+ {320, 607}
@@ -329,7 +353,7 @@
IBCocoaTouchFramework
- {320, 546}
+ {320, 607}
@@ -448,6 +472,15 @@
108
+
+
+ showTextOnly:
+
+
+ 7
+
+ 113
+
@@ -496,6 +529,7 @@
+
@@ -554,6 +588,11 @@
+
+ 111
+
+
+
@@ -566,6 +605,7 @@
-2.IBPluginDependency
10.IBPluginDependency
106.IBPluginDependency
+ 111.IBPluginDependency
16.IBPluginDependency
20.IBPluginDependency
43.IBPluginDependency
@@ -597,6 +637,7 @@
com.apple.InterfaceBuilder.IBCocoaTouchPlugin
com.apple.InterfaceBuilder.IBCocoaTouchPlugin
com.apple.InterfaceBuilder.IBCocoaTouchPlugin
+ com.apple.InterfaceBuilder.IBCocoaTouchPlugin
@@ -611,7 +652,7 @@
- 110
+ 113
diff --git a/MBProgressHUD.h b/MBProgressHUD.h
index 4ee195791..63a43cffe 100755
--- a/MBProgressHUD.h
+++ b/MBProgressHUD.h
@@ -1,6 +1,6 @@
//
// MBProgressHUD.h
-// Version 0.4
+// Version 0.5
// Created by Matej Bukovinski on 2.4.09.
//
@@ -32,16 +32,18 @@
@protocol MBProgressHUDDelegate;
-/////////////////////////////////////////////////////////////////////////////////////////////
typedef enum {
/** Progress is shown using an UIActivityIndicatorView. This is the default. */
MBProgressHUDModeIndeterminate,
- /** Progress is shown using a MBRoundProgressView. */
+ /** Progress is shown using a round, pie-chart like, progress view. */
MBProgressHUDModeDeterminate,
+ /** Progress is shown using a ring-shaped progress view. */
MBProgressHUDModeAnnularDeterminate,
/** Shows a custom view */
- MBProgressHUDModeCustomView
+ MBProgressHUDModeCustomView,
+ /** Shows only labels */
+ MBProgressHUDModeText
} MBProgressHUDMode;
typedef enum {
@@ -51,7 +53,25 @@ typedef enum {
MBProgressHUDAnimationZoom
} MBProgressHUDAnimation;
-/////////////////////////////////////////////////////////////////////////////////////////////
+
+#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
+
/**
* Displays a simple HUD window containing a progress indicator and two optional labels for short messages.
@@ -61,9 +81,10 @@ typedef enum {
* 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 witch resizes depending on the user specified content.
*
- * This view supports three modes of operation:
+ * This view supports four modes of operation:
* - MBProgressHUDModeIndeterminate - shows a UIActivityIndicatorView
- * - MBProgressHUDModeDeterminate - shows a custom round progress indicator (MBRoundProgressView)
+ * - 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:
@@ -71,62 +92,7 @@ typedef enum {
* indicator view.
* - If also the detailsLabelText property is set then another label is placed below the first label.
*/
-@interface MBProgressHUD : UIView {
-
- MBProgressHUDMode mode;
- MBProgressHUDAnimation animationType;
-
- SEL methodForExecution;
- id targetForExecution;
- id objectForExecution;
- BOOL useAnimation;
-
- float yOffset;
- float xOffset;
-
- float width;
- float height;
-
- CGSize minSize;
- BOOL square;
-
- float margin;
-
- BOOL dimBackground;
-
- BOOL taskInProgress;
- float graceTime;
- float minShowTime;
- NSTimer *graceTimer;
- NSTimer *minShowTimer;
- NSDate *showStarted;
-
- UIView *indicator;
- UILabel *label;
- UILabel *detailsLabel;
-
- float progress;
-
-#if __has_feature(objc_arc_weak)
- id __weak delegate;
-#elif __has_feature(objc_arc)
- id __unsafe_unretained delegate;
-#else
- id delegate;
-#endif
- NSString *labelText;
- NSString *detailsLabelText;
- float opacity;
- UIFont *labelFont;
- UIFont *detailsLabelFont;
-
- BOOL isFinished;
- BOOL removeFromSuperViewOnHide;
-
- UIView *customView;
-
- CGAffineTransform rotationTransform;
-}
+@interface MBProgressHUD : UIView
/**
* Creates a new HUD, adds it to provided view and shows it. The counterpart to this method is hideHUDForView:animated:.
@@ -137,11 +103,12 @@ typedef enum {
* @return A reference to the created HUD.
*
* @see hideHUDForView:animated:
+ * @see animationType
*/
+ (MBProgressHUD *)showHUDAddedTo:(UIView *)view animated:(BOOL)animated;
/**
- * Finds a HUD subview and hides it. The counterpart to this method is showHUDAddedTo:animated:.
+ * Finds the tompost 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
@@ -149,46 +116,93 @@ typedef enum {
* @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. The counterpart to this method is showHUDAddedTo: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 HUD will disappear using the current animationType. If set to NO the HUD will not use
+ * @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 HUD found in the subviews and removed.
+ * @return the number of HUDs found and removed.
*
* @see hideAllHUDForView:animated:
+ * @see animationType
*/
+ (NSUInteger)hideAllHUDsForView:(UIView *)view animated:(BOOL)animated;
/**
- * Finds a HUD subview and returns it. This is used internally by hideHUDForFiew:animated:, but can also be useful externally.
+ * Finds the topomost HUD subview and returns it.
*
- * @param view The view that is going to be searched for a HUD subview.
+ * @param view The view that is going to be searched.
* @return A reference to the last HUD subview discovered.
- *
- * @see hideHUDForView:animated:
*/
+ (MBProgressHUD *)HUDForView:(UIView *)view;
/**
- * Finds all HUD subviews and returns them. This is used internally by hideAllHUDsForView:animated:, but can also be useful externally.
+ * Finds all HUD subviews and returns them.
*
- * @param view The view that is going to be searched for HUD subviews.
+ * @param view The view that is going to be searched.
* @return All found HUD views (array of MBProgressHUD objects).
- *
- * @see hideAllHUDsForView:animated:
*/
+ (NSArray *)allHUDsForView:(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 disappear using the current animationType. If set to NO the HUD will not use
+ * animations while disappearing.
+ *
+ * @see animationType
+ */
+- (void)show:(BOOL)animated;
+
+/**
+ * Hide the HUD. This still calls the hudWasHidden: delegate. This is the counterpart of the hide: 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 hide: 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 secons 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 NSAutoreleasePools 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 disappear using the current animationType. If set to NO the HUD will not use
+ * animations while disappearing.
+ */
+- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;
+
/**
* 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 probably be the same instance as
+ * @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;
@@ -197,24 +211,13 @@ typedef enum {
* 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 probably be the same instance as
+ * @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;
-/**
- * The UIView (i.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 build in indicator bounds).
- */
-#if __has_feature(objc_arc)
-@property (strong) UIView *customView;
-#else
-@property (retain) UIView *customView;
-#endif
-
/**
- * MBProgressHUD operation mode. Switches between indeterminate (MBProgressHUDModeIndeterminate) and determinate
- * progress (MBProgressHUDModeDeterminate). The default is MBProgressHUDModeIndeterminate.
+ * MBProgressHUD operation mode. The default is MBProgressHUDModeIndeterminate.
*
* @see MBProgressHUDMode
*/
@@ -227,18 +230,18 @@ typedef enum {
*/
@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 build in indicator bounds).
+ */
+@property (MB_STRONG) UIView *customView;
+
/**
- * The HUD delegate object. If set the delegate will receive hudWasHidden callbacks when the HUD was hidden. The
- * delegate should conform to the MBProgressHUDDelegate protocol and implement the hudWasHidden method. The delegate
- * object will not be retained.
+ * The HUD delegate object.
+ *
+ * @see MBProgressHUDDelegate
*/
-#if __has_feature(objc_arc_weak)
-@property (weak) id delegate;
-#elif __has_feature(objc_arc)
-@property (unsafe_unretained) id delegate;
-#else
-@property (assign) id delegate;
-#endif
+@property (MB_WEAK) id delegate;
/**
* An optional short message to be displayed below the activity indicator. The HUD is automatically resized to fit
@@ -249,7 +252,7 @@ typedef enum {
/**
* 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 (@"").
+ * property is also set and is different from an empty string (@""). The details text can span multiple lines.
*/
@property (copy) NSString *detailsLabelText;
@@ -269,8 +272,7 @@ typedef enum {
@property (assign) float yOffset;
/**
- * The amounth of space between the HUD edge and the HUD elements (labels, indicators or custom views).
- *
+ * The amounth of space between the HUD edge and the HUD elements (labels, indicators or custom views).
* Defaults to 20.0
*/
@property (assign) float margin;
@@ -291,7 +293,6 @@ typedef enum {
*/
@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.
@@ -318,20 +319,12 @@ typedef enum {
/**
* Font to be used for the main label. Set this property if the default is not adequate.
*/
-#if __has_feature(objc_arc)
-@property (strong) UIFont* labelFont;
-#else
-@property (retain) UIFont* labelFont;
-#endif
+@property (MB_STRONG) UIFont* labelFont;
/**
* Font to be used for the details label. Set this property if the default is not adequate.
*/
-#if __has_feature(objc_arc)
-@property (strong) UIFont* detailsLabelFont;
-#else
-@property (retain) UIFont* detailsLabelFont;
-#endif
+@property (MB_STRONG) UIFont* detailsLabelFont;
/**
* The progress of the progress indicator, from 0.0 to 1.0. Defaults to 0.0.
@@ -339,7 +332,7 @@ typedef enum {
@property (assign) float progress;
/**
- * The minimum size of the HUD bezel. Defaults to CGSizeZero.
+ * The minimum size of the HUD bezel. Defaults to CGSizeZero (no minimum size).
*/
@property (assign) CGSize minSize;
@@ -348,57 +341,8 @@ typedef enum {
*/
@property (assign, getter = isSquare) BOOL square;
-/**
- * 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).
- *
- * If you need to perform a blocking thask on the main thread, you can try spining the run loop imeidiately after calling this
- * method by using:
- *
- * [[NSRunLoop currentRunLoop] runUntilDate:[NSDate distantPast]];
- *
- * @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.
- */
-- (void)show:(BOOL)animated;
-
-/**
- * Hide the HUD. This still calls the hudWasHidden delegate. This is the counterpart of the hide: 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.
- */
-- (void)hide:(BOOL)animated;
-
-/**
- * Hide the HUD after a delay. This still calls the hudWasHidden delegate. This is the counterpart of the hide: 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 secons until the HUD is hidden.
- */
-- (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 NSAutoreleasePools 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 disappear using the current animationType. If set to NO the HUD will not use
- * animations while disappearing.
- */
-- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated;
-
@end
-/////////////////////////////////////////////////////////////////////////////////////////////
@protocol MBProgressHUDDelegate
@@ -409,33 +353,22 @@ typedef enum {
*/
- (void)hudWasHidden:(MBProgressHUD *)hud;
-/**
- * @deprecated use hudWasHidden: instead
- * @see hudWasHidden:
- */
-- (void)hudWasHidden __attribute__ ((deprecated));
-
@end
-/////////////////////////////////////////////////////////////////////////////////////////////
/**
* A progress view for showing definite progress by filling up a circle (pie chart).
*/
-@interface MBRoundProgressView : UIView {
-@private
- float _progress;
- BOOL _isAnnular;
-}
+@interface MBRoundProgressView : UIView
/**
* Progress (0.0 to 1.0)
*/
@property (nonatomic, assign) float progress;
-@property (nonatomic, assign) BOOL isAnnular;
+/*
+ * Display mode - NO = round or YES = annular. Defaults to round.
+ */
+@property (nonatomic, assign, getter = isAnnular) BOOL annular;
@end
-
-/////////////////////////////////////////////////////////////////////////////////////////////
-
diff --git a/MBProgressHUD.m b/MBProgressHUD.m
index 9a512ec9d..f4168add7 100755
--- a/MBProgressHUD.m
+++ b/MBProgressHUD.m
@@ -1,19 +1,40 @@
//
// MBProgressHUD.m
-// Version 0.4
+// Version 0.5
// Created by Matej Bukovinski on 2.4.09.
//
#import "MBProgressHUD.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
+
+
+static const CGFloat kPadding = 4.f;
+static const CGFloat kLabelFontSize = 16.f;
+static const CGFloat kDetailsLabelFontSize = 12.f;
+
+
@interface MBProgressHUD ()
+- (void)setupLabels;
+- (void)registerForKVO;
+- (void)unregisterFromKVO;
+- (NSArray *)observableKeypaths;
+- (void)registerForNotifications;
+- (void)unregisterFromNotifications;
+- (void)updateUIForKeypath:(NSString *)keyPath;
- (void)hideUsingAnimation:(BOOL)animated;
- (void)showUsingAnimation:(BOOL)animated;
- (void)done;
-- (void)updateLabelText:(NSString *)newText;
-- (void)updateDetailsLabelText:(NSString *)newText;
-- (void)updateProgress;
- (void)updateIndicators;
- (void)handleGraceTimer:(NSTimer *)theTimer;
- (void)handleMinShowTimer:(NSTimer *)theTimer;
@@ -23,209 +44,61 @@ - (void)launchExecution;
- (void)deviceOrientationDidChange:(NSNotification *)notification;
- (void)hideDelayed:(NSNumber *)animated;
-#if __has_feature(objc_arc)
-@property (strong) UIView *indicator;
-@property (strong) NSTimer *graceTimer;
-@property (strong) NSTimer *minShowTimer;
-@property (strong) NSDate *showStarted;
-#else
-@property (retain) UIView *indicator;
-@property (retain) NSTimer *graceTimer;
-@property (retain) NSTimer *minShowTimer;
-@property (retain) NSDate *showStarted;
-#endif
-
-@property (assign) float width;
-@property (assign) float height;
+@property (MB_STRONG) UIView *indicator;
+@property (MB_STRONG) NSTimer *graceTimer;
+@property (MB_STRONG) NSTimer *minShowTimer;
+@property (MB_STRONG) NSDate *showStarted;
+@property (assign) CGSize size;
@end
-@implementation MBProgressHUD
+@implementation MBProgressHUD {
+ BOOL useAnimation;
+ SEL methodForExecution;
+ id targetForExecution;
+ id objectForExecution;
+ UILabel *label;
+ UILabel *detailsLabel;
+ BOOL isFinished;
+ CGAffineTransform rotationTransform;
+}
-#pragma mark -
-#pragma mark Accessors
+#pragma mark - Properties
@synthesize animationType;
-
@synthesize delegate;
@synthesize opacity;
@synthesize labelFont;
@synthesize detailsLabelFont;
-
@synthesize indicator;
-
-@synthesize width;
-@synthesize height;
@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;
-- (void)setMode:(MBProgressHUDMode)newMode {
- // Dont change mode if it wasn't actually changed to prevent flickering
- if (mode && (mode == newMode)) {
- return;
- }
-
- mode = newMode;
-
- if ([NSThread isMainThread]) {
- [self updateIndicators];
- [self setNeedsLayout];
- [self setNeedsDisplay];
- } else {
- [self performSelectorOnMainThread:@selector(updateIndicators) withObject:nil waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
- }
-}
-
-- (MBProgressHUDMode)mode {
- return mode;
-}
-
-- (void)setLabelText:(NSString *)newText {
- if ([NSThread isMainThread]) {
- [self updateLabelText:newText];
- [self setNeedsLayout];
- [self setNeedsDisplay];
- } else {
- [self performSelectorOnMainThread:@selector(updateLabelText:) withObject:newText waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
- }
-}
-
-- (NSString *)labelText {
- return labelText;
-}
-
-- (void)setDetailsLabelText:(NSString *)newText {
- if ([NSThread isMainThread]) {
- [self updateDetailsLabelText:newText];
- [self setNeedsLayout];
- [self setNeedsDisplay];
- } else {
- [self performSelectorOnMainThread:@selector(updateDetailsLabelText:) withObject:newText waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
- }
-}
-
-- (NSString *)detailsLabelText {
- return detailsLabelText;
-}
-
-- (void)setProgress:(float)newProgress {
- progress = newProgress;
-
- // Update display ony if showing the determinate progress view
- if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) {
- if ([NSThread isMainThread]) {
- [self updateProgress];
- [self setNeedsDisplay];
- } else {
- [self performSelectorOnMainThread:@selector(updateProgress) withObject:nil waitUntilDone:NO];
- [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
- }
- }
-}
-
-- (float)progress {
- return progress;
-}
-
-#pragma mark -
-#pragma mark Accessor helpers
-
-- (void)updateLabelText:(NSString *)newText {
- if (labelText != newText) {
-#if !__has_feature(objc_arc)
- [labelText release];
-#endif
- labelText = [newText copy];
- }
-}
-
-- (void)updateDetailsLabelText:(NSString *)newText {
- if (detailsLabelText != newText) {
-#if !__has_feature(objc_arc)
- [detailsLabelText release];
-#endif
- detailsLabelText = [newText copy];
- }
-}
-
-- (void)updateProgress {
- [(MBRoundProgressView *)indicator setProgress:progress];
-}
-
-- (void)updateIndicators {
- if (indicator) {
- [indicator removeFromSuperview];
- }
-
- if (mode == MBProgressHUDModeDeterminate || mode == MBProgressHUDModeAnnularDeterminate) {
-#if __has_feature(objc_arc)
- self.indicator = [[MBRoundProgressView alloc] init];
-#else
- self.indicator = [[[MBRoundProgressView alloc] init] autorelease];
-#endif
- if (mode == MBProgressHUDModeAnnularDeterminate) {
- [(MBRoundProgressView *)self.indicator setIsAnnular:YES];
- }
- }
- else if (mode == MBProgressHUDModeCustomView && self.customView != nil){
- self.indicator = self.customView;
- } else {
-#if __has_feature(objc_arc)
- self.indicator = [[UIActivityIndicatorView alloc]
- initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge];
-#else
- self.indicator = [[[UIActivityIndicatorView alloc]
- initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
-#endif
- [(UIActivityIndicatorView *)indicator startAnimating];
- }
-
-
- [self addSubview:indicator];
-}
-
-#pragma mark -
-#pragma mark Constants
-
-#define PADDING 4.0f
-
-#define LABELFONTSIZE 16.0f
-#define LABELDETAILSFONTSIZE 12.0f
-
-#pragma mark -
-#pragma mark Class methods
+#pragma mark - Class methods
+ (MBProgressHUD *)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:view];
[view addSubview:hud];
[hud show:animated];
-#if __has_feature(objc_arc)
- return hud;
-#else
- return [hud autorelease];
-#endif
+ return MB_AUTORELEASE(hud);
}
+ (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
@@ -271,38 +144,7 @@ + (NSArray *)allHUDsForView:(UIView *)view {
return [NSArray arrayWithArray:huds];
}
-#pragma mark -
-#pragma mark Lifecycle methods
-
-- (id)initWithWindow:(UIWindow *)window {
- return [self initWithView:window];
-}
-
-- (id)initWithView:(UIView *)view {
- // Let's check if the view is nil (this is a common error when using the windw initializer above)
- if (!view) {
- [NSException raise:@"MBProgressHUDViewIsNillException"
- format:@"The view used in the MBProgressHUD initializer is nil."];
- }
- id me = [self initWithFrame:view.bounds];
- // We need to take care of rotation ourselfs if we're adding the HUD to a window
- if ([view isKindOfClass:[UIWindow class]]) {
- [self setTransformForCurrentOrientation:NO];
- }
- [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:)
- name:UIDeviceOrientationDidChangeNotification object:nil];
-
- return me;
-}
-
-- (void)removeFromSuperview {
- [[NSNotificationCenter defaultCenter] removeObserver:self
- name:UIDeviceOrientationDidChangeNotification
- object:nil];
-
- [super removeFromSuperview];
-}
-
+#pragma mark - Lifecycle
- (id)initWithFrame:(CGRect)frame {
self = [super initWithFrame:frame];
@@ -313,8 +155,8 @@ - (id)initWithFrame:(CGRect)frame {
self.labelText = nil;
self.detailsLabelText = nil;
self.opacity = 0.8f;
- self.labelFont = [UIFont boldSystemFontOfSize:LABELFONTSIZE];
- self.detailsLabelFont = [UIFont boldSystemFontOfSize:LABELDETAILSFONTSIZE];
+ self.labelFont = [UIFont boldSystemFontOfSize:kLabelFontSize];
+ self.detailsLabelFont = [UIFont boldSystemFontOfSize:kDetailsLabelFontSize];
self.xOffset = 0.0f;
self.yOffset = 0.0f;
self.dimBackground = NO;
@@ -324,31 +166,43 @@ - (id)initWithFrame:(CGRect)frame {
self.removeFromSuperViewOnHide = NO;
self.minSize = CGSizeZero;
self.square = NO;
-
- self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
-
+ self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin
+ | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
+
// Transparent background
self.opaque = NO;
self.backgroundColor = [UIColor clearColor];
-
- // Make invisible for now
+ // Make it invisible for now
self.alpha = 0.0f;
- // Add label
- label = [[UILabel alloc] initWithFrame:self.bounds];
-
- // Add details label
- detailsLabel = [[UILabel alloc] initWithFrame:self.bounds];
-
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.");
+ id me = [self initWithFrame:view.bounds];
+ // We need to take care of rotation ourselfs if we're adding the HUD to a window
+ if ([view isKindOfClass:[UIWindow class]]) {
+ [self setTransformForCurrentOrientation:NO];
+ }
+ return me;
+}
+
+- (id)initWithWindow:(UIWindow *)window {
+ return [self initWithView:window];
+}
+
- (void)dealloc {
- [[NSNotificationCenter defaultCenter] removeObserver:self];
-
+ [self unregisterFromNotifications];
+ [self unregisterFromKVO];
#if !__has_feature(objc_arc)
[indicator release];
[label release];
@@ -363,136 +217,14 @@ - (void)dealloc {
#endif
}
-#pragma mark -
-#pragma mark Layout
-
-- (void)layoutSubviews {
- CGRect frame = self.bounds;
-
- // Compute HUD dimensions based on indicator size (add margin to HUD border)
- CGRect indFrame = indicator.bounds;
- self.width = indFrame.size.width + 2 * margin;
- self.height = indFrame.size.height + 2 * margin;
-
- // Position the indicator
- indFrame.origin.x = floorf((frame.size.width - indFrame.size.width) / 2) + self.xOffset;
- indFrame.origin.y = floorf((frame.size.height - indFrame.size.height) / 2) + self.yOffset;
- indicator.frame = indFrame;
-
- // Add label if label text was set
- if (nil != self.labelText) {
- // Get size of label text
- CGSize dims = [self.labelText sizeWithFont:self.labelFont];
-
- // Compute label dimensions based on font metrics if size is larger than max then clip the label width
- float lHeight = dims.height;
- float lWidth;
- if (dims.width <= (frame.size.width - 4 * margin)) {
- lWidth = dims.width;
- }
- else {
- lWidth = frame.size.width - 4 * margin;
- }
-
- // Set label properties
- label.font = self.labelFont;
- label.adjustsFontSizeToFitWidth = NO;
- label.textAlignment = UITextAlignmentCenter;
- label.opaque = NO;
- label.backgroundColor = [UIColor clearColor];
- label.textColor = [UIColor whiteColor];
- label.text = self.labelText;
-
- // Update HUD size
- if (self.width < (lWidth + 2 * margin)) {
- self.width = lWidth + 2 * margin;
- }
- self.height = self.height + lHeight + PADDING;
-
- // Move indicator to make room for the label
- indFrame.origin.y -= (floorf(lHeight / 2 + PADDING / 2));
- indicator.frame = indFrame;
-
- // Set the label position and dimensions
- CGRect lFrame = CGRectMake(floorf((frame.size.width - lWidth) / 2) + xOffset,
- floorf(indFrame.origin.y + indFrame.size.height + PADDING),
- lWidth, lHeight);
- label.frame = lFrame;
-
- [self addSubview:label];
-
- // Add details label delatils text was set
- if (nil != self.detailsLabelText) {
-
- // Set label properties
- detailsLabel.font = self.detailsLabelFont;
- detailsLabel.adjustsFontSizeToFitWidth = NO;
- detailsLabel.textAlignment = UITextAlignmentCenter;
- detailsLabel.opaque = NO;
- detailsLabel.backgroundColor = [UIColor clearColor];
- detailsLabel.textColor = [UIColor whiteColor];
- detailsLabel.text = self.detailsLabelText;
- detailsLabel.numberOfLines = 0;
-
- CGFloat maxHeight = frame.size.height - self.height - 2*margin;
- CGSize labelSize = [detailsLabel.text sizeWithFont:detailsLabel.font constrainedToSize:CGSizeMake(frame.size.width - 4*margin, maxHeight) lineBreakMode:detailsLabel.lineBreakMode];
- lHeight = labelSize.height;
- lWidth = labelSize.width;
-
- // Update HUD size
- if (self.width < lWidth) {
- self.width = lWidth + 2 * margin;
- }
- self.height = self.height + lHeight + PADDING;
-
- // Move indicator to make room for the new label
- indFrame.origin.y -= (floorf(lHeight / 2 + PADDING / 2));
- indicator.frame = indFrame;
-
- // Move first label to make room for the new label
- lFrame.origin.y -= (floorf(lHeight / 2 + PADDING / 2));
- label.frame = lFrame;
-
- // Set label position and dimensions
- CGRect lFrameD = CGRectMake(floorf((frame.size.width - lWidth) / 2) + xOffset,
- lFrame.origin.y + lFrame.size.height + PADDING, lWidth, lHeight);
- detailsLabel.frame = lFrameD;
-
- [self addSubview:detailsLabel];
- }
- }
-
- if (square) {
- CGFloat max = MAX(self.width, self.height);
- if (max <= frame.size.width - 2*margin) {
- self.width = max;
- }
- if (max <= frame.size.height - 2*margin) {
- self.height = max;
- }
- }
-
- if (self.width < minSize.width) {
- self.width = minSize.width;
- }
- if (self.height < minSize.height) {
- self.height = minSize.height;
- }
-}
-
-#pragma mark -
-#pragma mark Showing and execution
+#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];
+ self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime target:self
+ selector:@selector(handleGraceTimer:) userInfo:nil repeats:NO];
}
// ... otherwise show the HUD imediately
else {
@@ -503,21 +235,16 @@ - (void)show:(BOOL)animated {
- (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];
+ 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];
}
@@ -530,6 +257,8 @@ - (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) {
@@ -542,88 +271,13 @@ - (void)handleMinShowTimer:(NSTimer *)theTimer {
[self hideUsingAnimation:useAnimation];
}
-- (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
-
- methodForExecution = method;
-#if __has_feature(objc_arc)
- targetForExecution = target;
- objectForExecution = object;
-#else
- targetForExecution = [target retain];
- objectForExecution = [object retain];
-#endif
-
- // Launch execution in new thread
- taskInProgress = YES;
- [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil];
-
- // Show HUD view
- [self show:animated];
-}
-
-- (void)launchExecution {
-#if !__has_feature(objc_arc)
- NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
-#endif
-#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];
-
-#if !__has_feature(objc_arc)
- [pool release];
-#endif
-}
-
-- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
- [self done];
-}
-
-- (void)done {
- isFinished = YES;
-
- // If delegate was set make the callback
- self.alpha = 0.0f;
-
- if(delegate != nil) {
- if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
- [delegate performSelector:@selector(hudWasHidden:) withObject:self];
- } else if ([delegate respondsToSelector:@selector(hudWasHidden)]) {
- [delegate performSelector:@selector(hudWasHidden)];
- }
- }
-
- if (removeFromSuperViewOnHide) {
- [self removeFromSuperview];
- }
-}
-
-- (void)cleanUp {
- taskInProgress = NO;
-
- self.indicator = nil;
-
-#if !__has_feature(objc_arc)
- [targetForExecution release];
- [objectForExecution release];
-#endif
-
- [self hide:useAnimation];
-}
-
-#pragma mark -
-#pragma mark Fade in and Fade out
+#pragma mark - Internal show & hide operations
- (void)showUsingAnimation:(BOOL)animated {
self.alpha = 0.0f;
if (animated && animationType == MBProgressHUDAnimationZoom) {
self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5f, 1.5f));
}
-
self.showStarted = [NSDate date];
// Fade in
if (animated) {
@@ -646,7 +300,7 @@ - (void)hideUsingAnimation:(BOOL)animated {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.30];
[UIView setAnimationDelegate:self];
- [UIView setAnimationDidStopSelector:@selector(animationFinished: finished: context:)];
+ [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 == MBProgressHUDAnimationZoom) {
@@ -662,6 +316,201 @@ - (void)hideUsingAnimation:(BOOL)animated {
self.showStarted = nil;
}
+- (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
+ [self done];
+}
+
+- (void)done {
+ isFinished = YES;
+ self.alpha = 0.0f;
+ if ([delegate respondsToSelector:@selector(hudWasHidden:)]) {
+ [delegate performSelector:@selector(hudWasHidden:) withObject:self];
+ }
+ if (removeFromSuperViewOnHide) {
+ [self removeFromSuperview];
+ }
+}
+
+#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];
+}
+
+- (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;
+ self.indicator = nil;
+#if !__has_feature(objc_arc)
+ [targetForExecution release];
+ [objectForExecution release];
+#endif
+ [self hide:useAnimation];
+}
+
+#pragma mark - UI
+
+- (void)setupLabels {
+ label = [[UILabel alloc] initWithFrame:self.bounds];
+ label.adjustsFontSizeToFitWidth = NO;
+ label.textAlignment = UITextAlignmentCenter;
+ label.opaque = NO;
+ label.backgroundColor = [UIColor clearColor];
+ label.textColor = [UIColor whiteColor];
+ 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 = UITextAlignmentCenter;
+ detailsLabel.opaque = NO;
+ detailsLabel.backgroundColor = [UIColor clearColor];
+ detailsLabel.textColor = [UIColor whiteColor];
+ detailsLabel.numberOfLines = 0;
+ 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 && !isActivityIndicator) {
+ // Update to indeterminate indicator
+ [indicator removeFromSuperview];
+ self.indicator = MB_AUTORELEASE([[UIActivityIndicatorView alloc]
+ initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge]);
+ [(UIActivityIndicatorView *)indicator startAnimating];
+ [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 {
+
+ 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 = [label.text sizeWithFont: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 = [detailsLabel.text sizeWithFont:detailsLabel.font
+ constrainedToSize:maxSize lineBreakMode: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 = roundf(((bounds.size.height - totalSize.height) / 2)) + margin + yOffset;
+ CGFloat xPos = xOffset;
+ indicatorF.origin.y = yPos;
+ indicatorF.origin.x = roundf((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 = roundf((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 = roundf((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;
+ }
+
+ self.size = totalSize;
+}
+
#pragma mark BG Drawing
- (void)drawRect:(CGRect)rect {
@@ -676,7 +525,6 @@ - (void)drawRect:(CGRect)rect {
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
@@ -691,11 +539,9 @@ - (void)drawRect:(CGRect)rect {
// Center HUD
CGRect allRect = self.bounds;
// Draw rounded HUD bacgroud rect
- CGRect boxRect = CGRectMake(roundf((allRect.size.width - self.width) / 2) + self.xOffset,
- roundf((allRect.size.height - self.height) / 2) + self.yOffset, self.width, self.height);
- // Corner radius
+ CGRect boxRect = CGRectMake(roundf((allRect.size.width - size.width) / 2) + self.xOffset,
+ roundf((allRect.size.height - size.height) / 2) + self.yOffset, size.width, size.height);
float radius = 10.0f;
-
CGContextBeginPath(context);
CGContextSetGrayFillColor(context, 0.0f, self.opacity);
CGContextMoveToPoint(context, CGRectGetMinX(boxRect) + radius, CGRectGetMinY(boxRect));
@@ -707,17 +553,71 @@ - (void)drawRect:(CGRect)rect {
CGContextFillPath(context);
}
-#pragma mark -
-#pragma mark Manual oritentation change
+#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];
+ }
+}
-#define RADIANS(degrees) ((degrees * (float)M_PI) / 180.0f)
+- (NSArray *)observableKeypaths {
+ return [NSArray arrayWithObjects:@"mode", @"customView", @"labelText", @"labelFont",
+ @"detailsLabelText", @"detailsLabelFont", @"progress", nil];
+}
-- (void)deviceOrientationDidChange:(NSNotification *)notification {
- if (!self.superview) {
+- (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"]) {
+ [self updateIndicators];
+ } else if ([keyPath isEqualToString:@"labelText"]) {
+ label.text = self.labelText;
+ } else if ([keyPath isEqualToString:@"labelFont"]) {
+ label.font = self.labelFont;
+ } else if ([keyPath isEqualToString:@"detailsLabelText"]) {
+ detailsLabel.text = self.detailsLabelText;
+ } else if ([keyPath isEqualToString:@"detailsLabelFont"]) {
+ detailsLabel.font = self.detailsLabelFont;
+ } else if ([keyPath isEqualToString:@"progress"]) {
+ if ([indicator respondsToSelector:@selector(setProgress:)]) {
+ [(id)indicator setProgress:progress];
+ }
return;
}
-
- if ([self.superview isKindOfClass:[UIWindow class]]) {
+ [self setNeedsLayout];
+ [self setNeedsDisplay];
+}
+
+#pragma mark - Notifications
+
+- (void)registerForNotifications {
+ NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
+ [nc addObserver:self selector:@selector(deviceOrientationDidChange:)
+ name:UIDeviceOrientationDidChangeNotification object:nil];
+}
+
+- (void)unregisterFromNotifications {
+ [[NSNotificationCenter defaultCenter] removeObserver:self];
+}
+
+- (void)deviceOrientationDidChange:(NSNotification *)notification {
+ UIView *superview = self.superview;
+ if (!superview) {
+ return;
+ } else if ([superview isKindOfClass:[UIWindow class]]) {
[self setTransformForCurrentOrientation:YES];
} else {
self.bounds = self.superview.bounds;
@@ -725,27 +625,25 @@ - (void)deviceOrientationDidChange:(NSNotification *)notification {
}
}
-- (void)setTransformForCurrentOrientation:(BOOL)animated {
- UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
- NSInteger degrees = 0;
-
+- (void)setTransformForCurrentOrientation:(BOOL)animated {
// Stay in sync with the superview
if (self.superview) {
self.bounds = self.superview.bounds;
[self setNeedsDisplay];
}
+ UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
+ float radians = 0;
if (UIInterfaceOrientationIsLandscape(orientation)) {
- if (orientation == UIInterfaceOrientationLandscapeLeft) { degrees = -90; }
- else { degrees = 90; }
+ if (orientation == UIInterfaceOrientationLandscapeLeft) { radians = -M_PI_2; }
+ else { radians = M_PI_2; }
// Window coordinates differ!
self.bounds = CGRectMake(0, 0, self.bounds.size.height, self.bounds.size.width);
} else {
- if (orientation == UIInterfaceOrientationPortraitUpsideDown) { degrees = 180; }
- else { degrees = 0; }
+ if (orientation == UIInterfaceOrientationPortraitUpsideDown) { radians = M_PI; }
+ else { radians = 0; }
}
-
- rotationTransform = CGAffineTransformMakeRotation(RADIANS(degrees));
+ rotationTransform = CGAffineTransformMakeRotation(radians);
if (animated) {
[UIView beginAnimations:nil context:nil];
@@ -758,14 +656,13 @@ - (void)setTransformForCurrentOrientation:(BOOL)animated {
@end
-/////////////////////////////////////////////////////////////////////////////////////////////
-@implementation MBRoundProgressView
-
-@synthesize isAnnular = _isAnnular;
+@implementation MBRoundProgressView {
+ float _progress;
+ BOOL _annular;
+}
-#pragma mark -
-#pragma mark Accessors
+#pragma mark - Accessors
- (float)progress {
return _progress;
@@ -776,11 +673,19 @@ - (void)setProgress:(float)progress {
[self setNeedsDisplay];
}
-#pragma mark -
-#pragma mark Lifecycle
+- (BOOL)isAnnular {
+ return _annular;
+}
+
+- (void)setAnnular:(BOOL)annular {
+ _annular = annular;
+ [self setNeedsDisplay];
+}
+
+#pragma mark - Lifecycle
- (id)init {
- return [self initWithFrame:CGRectMake(0.0f, 0.0f, 37.0f, 37.0f)];
+ return [self initWithFrame:CGRectMake(0.f, 0.f, 37.f, 37.f)];
}
- (id)initWithFrame:(CGRect)frame {
@@ -788,24 +693,22 @@ - (id)initWithFrame:(CGRect)frame {
if (self) {
self.backgroundColor = [UIColor clearColor];
self.opaque = NO;
- self.isAnnular = NO;
+ _progress = 0.f;
+ _annular = NO;
}
return self;
}
-#pragma mark -
-#pragma mark Drawing
+#pragma mark - Drawing
- (void)drawRect:(CGRect)rect {
CGRect allRect = self.bounds;
CGRect circleRect = CGRectInset(allRect, 2.0f, 2.0f);
-
CGContextRef context = UIGraphicsGetCurrentContext();
- if (_isAnnular) {
+ if (_annular) {
// Draw background
-
CGFloat lineWidth = 5.f;
UIBezierPath *processBackgroundPath = [UIBezierPath bezierPath];
processBackgroundPath.lineWidth = lineWidth;
@@ -817,7 +720,6 @@ - (void)drawRect:(CGRect)rect {
[processBackgroundPath addArcWithCenter:center radius:radius startAngle:startAngle endAngle:endAngle clockwise:YES];
[[UIColor colorWithRed:1 green:1 blue:1 alpha:0.1] set];
[processBackgroundPath stroke];
-
// Draw progress
UIBezierPath *processPath = [UIBezierPath bezierPath];
processPath.lineCapStyle = kCGLineCapRound;
@@ -833,7 +735,6 @@ - (void)drawRect:(CGRect)rect {
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;
@@ -848,5 +749,3 @@ - (void)drawRect:(CGRect)rect {
}
@end
-
-/////////////////////////////////////////////////////////////////////////////////////////////
diff --git a/README.mdown b/README.mdown
index e4336f6d5..fb11cd78e 100644
--- a/README.mdown
+++ b/README.mdown
@@ -1,15 +1,15 @@
MBProgressHUD
=============
-MBProgressHUD is an iPhone drop-in class that displays a translucent HUD with a progress indicator and some optional labels while work is being done in a background thread. The HUD is meant as a replacement for the undocumented, private UIKit UIProgressHUD with some additional features.
-
-MBProgressHUD is iOS4 and iPad compatible and released under the MIT license (see MBProgressHUD.h).
+MBProgressHUD is an iOS drop-in class that displays a translucent HUD with a progress indicator and some optional labels while work is being done in a background thread. The HUD is meant as a replacement for the undocumented, private UIKit UIProgressHUD with some additional features.
[](http://dl.dropbox.com/u/378729/MBProgressHUD/1.png)
[](http://dl.dropbox.com/u/378729/MBProgressHUD/2.png)
[](http://dl.dropbox.com/u/378729/MBProgressHUD/3.png)
[](http://dl.dropbox.com/u/378729/MBProgressHUD/4.png)
[](http://dl.dropbox.com/u/378729/MBProgressHUD/5.png)
+[](http://dl.dropbox.com/u/378729/MBProgressHUD/6.png)
+[](http://dl.dropbox.com/u/378729/MBProgressHUD/7.png)
Adding MBProgressHUD to your project
====================================
@@ -52,6 +52,18 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
Change-log
==========
+**Version 0.5** @ 22.03.12
+
+- Major source code modernization and cleanup (KVO, layout code, instance vars, etc.).
+- New annular determinate mode.
+- New text only mode.
+- Added a static library project and Xcode 4 workspace.
+- Added methods to find and return HUD(s) on a view.
+- Various bug fixes.
+- Various demo project enhancements (hi-res rescues, new samples).
+
+IMPORTANT: Requires LLVM 3+.
+
**Version 0.41** @ 03.01.12
- Support for ARC.