PageRenderTime 52ms CodeModel.GetById 19ms RepoModel.GetById 1ms app.codeStats 0ms

/WebServiceDemo/WebServiceTest/MBProgressHUD.m

https://gitlab.com/praveenvelanati/ios-demo
Objective C | 659 lines | 483 code | 124 blank | 52 comment | 78 complexity | c0c93c6a0ec837e6fbdd2cee2f0ff643 MD5 | raw file
  1. //
  2. // MBProgressHUD.m
  3. // Version 0.4
  4. // Created by Matej Bukovinski on 2.4.09.
  5. //
  6. #import "MBProgressHUD.h"
  7. @interface MBProgressHUD ()
  8. - (void)hideUsingAnimation:(BOOL)animated;
  9. - (void)showUsingAnimation:(BOOL)animated;
  10. - (void)fillRoundedRect:(CGRect)rect inContext:(CGContextRef)context;
  11. - (void)done;
  12. - (void)updateLabelText:(NSString *)newText;
  13. - (void)updateDetailsLabelText:(NSString *)newText;
  14. - (void)updateProgress;
  15. - (void)updateIndicators;
  16. - (void)handleGraceTimer:(NSTimer *)theTimer;
  17. - (void)handleMinShowTimer:(NSTimer *)theTimer;
  18. - (void)setTransformForCurrentOrientation:(BOOL)animated;
  19. @property (retain) UIView *indicator;
  20. @property (assign) float width;
  21. @property (assign) float height;
  22. @property (retain) NSTimer *graceTimer;
  23. @property (retain) NSTimer *minShowTimer;
  24. @property (retain) NSDate *showStarted;
  25. @end
  26. @implementation MBProgressHUD
  27. #pragma mark -
  28. #pragma mark Accessors
  29. @synthesize animationType;
  30. @synthesize delegate;
  31. @synthesize opacity;
  32. @synthesize labelFont;
  33. @synthesize detailsLabelFont;
  34. @synthesize indicator;
  35. @synthesize width;
  36. @synthesize height;
  37. @synthesize xOffset;
  38. @synthesize yOffset;
  39. @synthesize margin;
  40. @synthesize graceTime;
  41. @synthesize minShowTime;
  42. @synthesize graceTimer;
  43. @synthesize minShowTimer;
  44. @synthesize taskInProgress;
  45. @synthesize removeFromSuperViewOnHide;
  46. @synthesize customView;
  47. @synthesize showStarted;
  48. - (void)setMode:(MBProgressHUDMode)newMode {
  49. // Dont change mode if it wasn't actually changed to prevent flickering
  50. if (mode && (mode == newMode)) {
  51. return;
  52. }
  53. mode = newMode;
  54. if ([NSThread isMainThread]) {
  55. [self updateIndicators];
  56. [self setNeedsLayout];
  57. [self setNeedsDisplay];
  58. } else {
  59. [self performSelectorOnMainThread:@selector(updateIndicators) withObject:nil waitUntilDone:NO];
  60. [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
  61. [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
  62. }
  63. }
  64. - (MBProgressHUDMode)mode {
  65. return mode;
  66. }
  67. - (void)setLabelText:(NSString *)newText {
  68. if ([NSThread isMainThread]) {
  69. [self updateLabelText:newText];
  70. [self setNeedsLayout];
  71. [self setNeedsDisplay];
  72. } else {
  73. [self performSelectorOnMainThread:@selector(updateLabelText:) withObject:newText waitUntilDone:NO];
  74. [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
  75. [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
  76. }
  77. }
  78. - (NSString *)labelText {
  79. return labelText;
  80. }
  81. - (void)setDetailsLabelText:(NSString *)newText {
  82. if ([NSThread isMainThread]) {
  83. [self updateDetailsLabelText:newText];
  84. [self setNeedsLayout];
  85. [self setNeedsDisplay];
  86. } else {
  87. [self performSelectorOnMainThread:@selector(updateDetailsLabelText:) withObject:newText waitUntilDone:NO];
  88. [self performSelectorOnMainThread:@selector(setNeedsLayout) withObject:nil waitUntilDone:NO];
  89. [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
  90. }
  91. }
  92. - (NSString *)detailsLabelText {
  93. return detailsLabelText;
  94. }
  95. - (void)setProgress:(float)newProgress {
  96. progress = newProgress;
  97. // Update display ony if showing the determinate progress view
  98. if (mode == MBProgressHUDModeDeterminate) {
  99. if ([NSThread isMainThread]) {
  100. [self updateProgress];
  101. [self setNeedsDisplay];
  102. } else {
  103. [self performSelectorOnMainThread:@selector(updateProgress) withObject:nil waitUntilDone:NO];
  104. [self performSelectorOnMainThread:@selector(setNeedsDisplay) withObject:nil waitUntilDone:NO];
  105. }
  106. }
  107. }
  108. - (float)progress {
  109. return progress;
  110. }
  111. #pragma mark -
  112. #pragma mark Accessor helpers
  113. - (void)updateLabelText:(NSString *)newText {
  114. if (labelText != newText) {
  115. [labelText release];
  116. labelText = [newText copy];
  117. }
  118. }
  119. - (void)updateDetailsLabelText:(NSString *)newText {
  120. if (detailsLabelText != newText) {
  121. [detailsLabelText release];
  122. detailsLabelText = [newText copy];
  123. }
  124. }
  125. - (void)updateProgress {
  126. [(MBRoundProgressView *)indicator setProgress:progress];
  127. }
  128. - (void)updateIndicators {
  129. if (indicator) {
  130. [indicator removeFromSuperview];
  131. }
  132. if (mode == MBProgressHUDModeDeterminate) {
  133. self.indicator = [[[MBRoundProgressView alloc] initWithDefaultSize] autorelease];
  134. }
  135. else if (mode == MBProgressHUDModeCustomView && self.customView != nil){
  136. self.indicator = self.customView;
  137. } else {
  138. self.indicator = [[[UIActivityIndicatorView alloc]
  139. initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] autorelease];
  140. [(UIActivityIndicatorView *)indicator startAnimating];
  141. }
  142. [self addSubview:indicator];
  143. }
  144. #pragma mark -
  145. #pragma mark Constants
  146. #define PADDING 4.0
  147. #define LABELFONTSIZE 16.0
  148. #define LABELDETAILSFONTSIZE 12.0
  149. #define PI 3.14159265358979323846
  150. #pragma mark -
  151. #pragma mark Class methods
  152. + (MBProgressHUD *)showHUDAddedTo:(UIView *)view animated:(BOOL)animated {
  153. MBProgressHUD *hud = [[MBProgressHUD alloc] initWithView:view];
  154. [view addSubview:hud];
  155. [hud show:animated];
  156. return [hud autorelease];
  157. }
  158. + (BOOL)hideHUDForView:(UIView *)view animated:(BOOL)animated {
  159. UIView *viewToRemove = nil;
  160. for (UIView *v in [view subviews]) {
  161. if ([v isKindOfClass:[MBProgressHUD class]]) {
  162. viewToRemove = v;
  163. }
  164. }
  165. if (viewToRemove != nil) {
  166. MBProgressHUD *HUD = (MBProgressHUD *)viewToRemove;
  167. HUD.removeFromSuperViewOnHide = YES;
  168. [HUD hide:animated];
  169. return YES;
  170. } else {
  171. return NO;
  172. }
  173. }
  174. #pragma mark -
  175. #pragma mark Lifecycle methods
  176. - (id)initWithWindow:(UIWindow *)window {
  177. return [self initWithView:window];
  178. }
  179. - (id)initWithView:(UIView *)view {
  180. // Let's check if the view is nil (this is a common error when using the windw initializer above)
  181. if (!view) {
  182. [NSException raise:@"MBProgressHUDViewIsNillException"
  183. format:@"The view used in the MBProgressHUD initializer is nil."];
  184. }
  185. id me = [self initWithFrame:view.bounds];
  186. // We need to take care of rotation ourselfs if we're adding the HUD to a window
  187. if ([view isKindOfClass:[UIWindow class]]) {
  188. [self setTransformForCurrentOrientation:NO];
  189. }
  190. [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(deviceOrientationDidChange:)
  191. name:UIDeviceOrientationDidChangeNotification object:nil];
  192. return me;
  193. }
  194. - (id)initWithFrame:(CGRect)frame {
  195. self = [super initWithFrame:frame];
  196. if (self) {
  197. // Set default values for properties
  198. self.animationType = MBProgressHUDAnimationFade;
  199. self.mode = MBProgressHUDModeIndeterminate;
  200. self.labelText = nil;
  201. self.detailsLabelText = nil;
  202. self.opacity = 0.8;
  203. self.labelFont = [UIFont boldSystemFontOfSize:LABELFONTSIZE];
  204. self.detailsLabelFont = [UIFont boldSystemFontOfSize:LABELDETAILSFONTSIZE];
  205. self.xOffset = 0.0;
  206. self.yOffset = 0.0;
  207. self.margin = 20.0;
  208. self.graceTime = 0.0;
  209. self.minShowTime = 0.0;
  210. self.removeFromSuperViewOnHide = NO;
  211. self.autoresizingMask = UIViewAutoresizingFlexibleTopMargin | UIViewAutoresizingFlexibleBottomMargin | UIViewAutoresizingFlexibleLeftMargin | UIViewAutoresizingFlexibleRightMargin;
  212. // Transparent background
  213. self.opaque = NO;
  214. self.backgroundColor = [UIColor clearColor];
  215. // Make invisible for now
  216. self.alpha = 0.0;
  217. // Add label
  218. label = [[UILabel alloc] initWithFrame:self.bounds];
  219. // Add details label
  220. detailsLabel = [[UILabel alloc] initWithFrame:self.bounds];
  221. taskInProgress = NO;
  222. rotationTransform = CGAffineTransformIdentity;
  223. }
  224. return self;
  225. }
  226. - (void)dealloc {
  227. [[NSNotificationCenter defaultCenter] removeObserver:self];
  228. [indicator release];
  229. [label release];
  230. [detailsLabel release];
  231. [labelText release];
  232. [detailsLabelText release];
  233. [graceTimer release];
  234. [minShowTimer release];
  235. [showStarted release];
  236. [customView release];
  237. [super dealloc];
  238. }
  239. #pragma mark -
  240. #pragma mark Layout
  241. - (void)layoutSubviews {
  242. CGRect frame = self.bounds;
  243. // Compute HUD dimensions based on indicator size (add margin to HUD border)
  244. CGRect indFrame = indicator.bounds;
  245. self.width = indFrame.size.width + 2 * margin;
  246. self.height = indFrame.size.height + 2 * margin;
  247. // Position the indicator
  248. indFrame.origin.x = floor((frame.size.width - indFrame.size.width) / 2) + self.xOffset;
  249. indFrame.origin.y = floor((frame.size.height - indFrame.size.height) / 2) + self.yOffset;
  250. indicator.frame = indFrame;
  251. // Add label if label text was set
  252. if (nil != self.labelText) {
  253. // Get size of label text
  254. CGSize dims = [self.labelText sizeWithFont:self.labelFont];
  255. // Compute label dimensions based on font metrics if size is larger than max then clip the label width
  256. float lHeight = dims.height;
  257. float lWidth;
  258. if (dims.width <= (frame.size.width - 2 * margin)) {
  259. lWidth = dims.width;
  260. }
  261. else {
  262. lWidth = frame.size.width - 4 * margin;
  263. }
  264. // Set label properties
  265. label.font = self.labelFont;
  266. label.adjustsFontSizeToFitWidth = NO;
  267. label.textAlignment = UITextAlignmentCenter;
  268. label.opaque = NO;
  269. label.backgroundColor = [UIColor clearColor];
  270. label.textColor = [UIColor whiteColor];
  271. label.text = self.labelText;
  272. // Update HUD size
  273. if (self.width < (lWidth + 2 * margin)) {
  274. self.width = lWidth + 2 * margin;
  275. }
  276. self.height = self.height + lHeight + PADDING;
  277. // Move indicator to make room for the label
  278. indFrame.origin.y -= (floor(lHeight / 2 + PADDING / 2));
  279. indicator.frame = indFrame;
  280. // Set the label position and dimensions
  281. CGRect lFrame = CGRectMake(floor((frame.size.width - lWidth) / 2) + xOffset,
  282. floor(indFrame.origin.y + indFrame.size.height + PADDING),
  283. lWidth, lHeight);
  284. label.frame = lFrame;
  285. [self addSubview:label];
  286. // Add details label delatils text was set
  287. if (nil != self.detailsLabelText) {
  288. // Get size of label text
  289. dims = [self.detailsLabelText sizeWithFont:self.detailsLabelFont];
  290. // Compute label dimensions based on font metrics if size is larger than max then clip the label width
  291. lHeight = dims.height;
  292. if (dims.width <= (frame.size.width - 2 * margin)) {
  293. lWidth = dims.width;
  294. }
  295. else {
  296. lWidth = frame.size.width - 4 * margin;
  297. }
  298. // Set label properties
  299. detailsLabel.font = self.detailsLabelFont;
  300. detailsLabel.adjustsFontSizeToFitWidth = NO;
  301. detailsLabel.textAlignment = UITextAlignmentCenter;
  302. detailsLabel.opaque = NO;
  303. detailsLabel.backgroundColor = [UIColor clearColor];
  304. detailsLabel.textColor = [UIColor whiteColor];
  305. detailsLabel.text = self.detailsLabelText;
  306. // Update HUD size
  307. if (self.width < lWidth) {
  308. self.width = lWidth + 2 * margin;
  309. }
  310. self.height = self.height + lHeight + PADDING;
  311. // Move indicator to make room for the new label
  312. indFrame.origin.y -= (floor(lHeight / 2 + PADDING / 2));
  313. indicator.frame = indFrame;
  314. // Move first label to make room for the new label
  315. lFrame.origin.y -= (floor(lHeight / 2 + PADDING / 2));
  316. label.frame = lFrame;
  317. // Set label position and dimensions
  318. CGRect lFrameD = CGRectMake(floor((frame.size.width - lWidth) / 2) + xOffset,
  319. lFrame.origin.y + lFrame.size.height + PADDING, lWidth, lHeight);
  320. detailsLabel.frame = lFrameD;
  321. [self addSubview:detailsLabel];
  322. }
  323. }
  324. }
  325. #pragma mark -
  326. #pragma mark Showing and execution
  327. - (void)show:(BOOL)animated {
  328. useAnimation = animated;
  329. // If the grace time is set postpone the HUD display
  330. if (self.graceTime > 0.0) {
  331. self.graceTimer = [NSTimer scheduledTimerWithTimeInterval:self.graceTime
  332. target:self
  333. selector:@selector(handleGraceTimer:)
  334. userInfo:nil
  335. repeats:NO];
  336. }
  337. // ... otherwise show the HUD imediately
  338. else {
  339. [self setNeedsDisplay];
  340. [self showUsingAnimation:useAnimation];
  341. }
  342. }
  343. - (void)hide:(BOOL)animated {
  344. useAnimation = animated;
  345. // If the minShow time is set, calculate how long the hud was shown,
  346. // and pospone the hiding operation if necessary
  347. if (self.minShowTime > 0.0 && showStarted) {
  348. NSTimeInterval interv = [[NSDate date] timeIntervalSinceDate:showStarted];
  349. if (interv < self.minShowTime) {
  350. self.minShowTimer = [NSTimer scheduledTimerWithTimeInterval:(self.minShowTime - interv)
  351. target:self
  352. selector:@selector(handleMinShowTimer:)
  353. userInfo:nil
  354. repeats:NO];
  355. return;
  356. }
  357. }
  358. // ... otherwise hide the HUD immediately
  359. [self hideUsingAnimation:useAnimation];
  360. }
  361. - (void)handleGraceTimer:(NSTimer *)theTimer {
  362. // Show the HUD only if the task is still running
  363. if (taskInProgress) {
  364. [self setNeedsDisplay];
  365. [self showUsingAnimation:useAnimation];
  366. }
  367. }
  368. - (void)handleMinShowTimer:(NSTimer *)theTimer {
  369. [self hideUsingAnimation:useAnimation];
  370. }
  371. - (void)showWhileExecuting:(SEL)method onTarget:(id)target withObject:(id)object animated:(BOOL)animated {
  372. methodForExecution = method;
  373. targetForExecution = [target retain];
  374. objectForExecution = [object retain];
  375. // Launch execution in new thread
  376. taskInProgress = YES;
  377. [NSThread detachNewThreadSelector:@selector(launchExecution) toTarget:self withObject:nil];
  378. // Show HUD view
  379. [self show:animated];
  380. }
  381. - (void)launchExecution {
  382. NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
  383. // Start executing the requested task
  384. [targetForExecution performSelector:methodForExecution withObject:objectForExecution];
  385. // Task completed, update view in main thread (note: view operations should
  386. // be done only in the main thread)
  387. [self performSelectorOnMainThread:@selector(cleanUp) withObject:nil waitUntilDone:NO];
  388. [pool release];
  389. }
  390. - (void)animationFinished:(NSString *)animationID finished:(BOOL)finished context:(void*)context {
  391. [self done];
  392. }
  393. - (void)done {
  394. isFinished = YES;
  395. // If delegate was set make the callback
  396. self.alpha = 0.0;
  397. if(delegate != nil && [delegate conformsToProtocol:@protocol(MBProgressHUDDelegate)]) {
  398. if([delegate respondsToSelector:@selector(hudWasHidden)]) {
  399. [delegate performSelector:@selector(hudWasHidden)];
  400. }
  401. }
  402. if (removeFromSuperViewOnHide) {
  403. [self removeFromSuperview];
  404. }
  405. }
  406. - (void)cleanUp {
  407. taskInProgress = NO;
  408. self.indicator = nil;
  409. [targetForExecution release];
  410. [objectForExecution release];
  411. [self hide:useAnimation];
  412. }
  413. #pragma mark -
  414. #pragma mark Fade in and Fade out
  415. - (void)showUsingAnimation:(BOOL)animated {
  416. self.alpha = 0.0;
  417. if (animated && animationType == MBProgressHUDAnimationZoom) {
  418. self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(1.5, 1.5));
  419. }
  420. self.showStarted = [NSDate date];
  421. // Fade in
  422. if (animated) {
  423. [UIView beginAnimations:nil context:NULL];
  424. [UIView setAnimationDuration:0.30];
  425. self.alpha = 1.0;
  426. if (animationType == MBProgressHUDAnimationZoom) {
  427. self.transform = rotationTransform;
  428. }
  429. [UIView commitAnimations];
  430. }
  431. else {
  432. self.alpha = 1.0;
  433. }
  434. }
  435. - (void)hideUsingAnimation:(BOOL)animated {
  436. // Fade out
  437. if (animated) {
  438. [UIView beginAnimations:nil context:NULL];
  439. [UIView setAnimationDuration:0.30];
  440. [UIView setAnimationDelegate:self];
  441. [UIView setAnimationDidStopSelector:@selector(animationFinished: finished: context:)];
  442. // 0.02 prevents the hud from passing through touches during the animation the hud will get completely hidden
  443. // in the done method
  444. if (animationType == MBProgressHUDAnimationZoom) {
  445. self.transform = CGAffineTransformConcat(rotationTransform, CGAffineTransformMakeScale(0.5, 0.5));
  446. }
  447. self.alpha = 0.02;
  448. [UIView commitAnimations];
  449. }
  450. else {
  451. self.alpha = 0.0;
  452. [self done];
  453. }
  454. }
  455. #pragma mark BG Drawing
  456. - (void)drawRect:(CGRect)rect {
  457. // Center HUD
  458. CGRect allRect = self.bounds;
  459. // Draw rounded HUD bacgroud rect
  460. CGRect boxRect = CGRectMake(((allRect.size.width - self.width) / 2) + self.xOffset,
  461. ((allRect.size.height - self.height) / 2) + self.yOffset, self.width, self.height);
  462. CGContextRef ctxt = UIGraphicsGetCurrentContext();
  463. [self fillRoundedRect:boxRect inContext:ctxt];
  464. }
  465. - (void)fillRoundedRect:(CGRect)rect inContext:(CGContextRef)context {
  466. float radius = 10.0f;
  467. CGContextBeginPath(context);
  468. CGContextSetGrayFillColor(context, 0.0, self.opacity);
  469. CGContextMoveToPoint(context, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect));
  470. CGContextAddArc(context, CGRectGetMaxX(rect) - radius, CGRectGetMinY(rect) + radius, radius, 3 * M_PI / 2, 0, 0);
  471. CGContextAddArc(context, CGRectGetMaxX(rect) - radius, CGRectGetMaxY(rect) - radius, radius, 0, M_PI / 2, 0);
  472. CGContextAddArc(context, CGRectGetMinX(rect) + radius, CGRectGetMaxY(rect) - radius, radius, M_PI / 2, M_PI, 0);
  473. CGContextAddArc(context, CGRectGetMinX(rect) + radius, CGRectGetMinY(rect) + radius, radius, M_PI, 3 * M_PI / 2, 0);
  474. CGContextClosePath(context);
  475. CGContextFillPath(context);
  476. }
  477. #pragma mark -
  478. #pragma mark Manual oritentation change
  479. #define RADIANS(degrees) ((degrees * M_PI) / 180.0)
  480. - (void)deviceOrientationDidChange:(NSNotification *)notification {
  481. if (!self.superview) {
  482. return;
  483. }
  484. if ([self.superview isKindOfClass:[UIWindow class]]) {
  485. [self setTransformForCurrentOrientation:YES];
  486. }
  487. // Stay in sync with the parent view (make sure we cover it fully)
  488. self.frame = self.superview.bounds;
  489. [self setNeedsDisplay];
  490. }
  491. - (void)setTransformForCurrentOrientation:(BOOL)animated {
  492. UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation;
  493. NSInteger degrees = 0;
  494. if (UIInterfaceOrientationIsLandscape(orientation)) {
  495. if (orientation == UIInterfaceOrientationLandscapeLeft) { degrees = -90; }
  496. else { degrees = 90; }
  497. } else {
  498. if (orientation == UIInterfaceOrientationPortraitUpsideDown) { degrees = 180; }
  499. else { degrees = 0; }
  500. }
  501. rotationTransform = CGAffineTransformMakeRotation(RADIANS(degrees));
  502. if (animated) {
  503. [UIView beginAnimations:nil context:nil];
  504. }
  505. [self setTransform:rotationTransform];
  506. if (animated) {
  507. [UIView commitAnimations];
  508. }
  509. }
  510. @end
  511. @implementation MBRoundProgressView
  512. - (id)initWithDefaultSize {
  513. return [super initWithFrame:CGRectMake(0.0f, 0.0f, 37.0f, 37.0f)];
  514. }
  515. - (void)drawRect:(CGRect)rect {
  516. CGRect allRect = self.bounds;
  517. CGRect circleRect = CGRectMake(allRect.origin.x + 2, allRect.origin.y + 2, allRect.size.width - 4,
  518. allRect.size.height - 4);
  519. CGContextRef context = UIGraphicsGetCurrentContext();
  520. // Draw background
  521. CGContextSetRGBStrokeColor(context, 1.0, 1.0, 1.0, 1.0); // white
  522. CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 0.1); // translucent white
  523. CGContextSetLineWidth(context, 2.0);
  524. CGContextFillEllipseInRect(context, circleRect);
  525. CGContextStrokeEllipseInRect(context, circleRect);
  526. // Draw progress
  527. float x = (allRect.size.width / 2);
  528. float y = (allRect.size.height / 2);
  529. CGContextSetRGBFillColor(context, 1.0, 1.0, 1.0, 1.0); // white
  530. CGContextMoveToPoint(context, x, y);
  531. CGContextAddArc(context, x, y, (allRect.size.width - 4) / 2, -(PI / 2), (self.progress * 2 * PI) - PI / 2, 0);
  532. CGContextClosePath(context);
  533. CGContextFillPath(context);
  534. }
  535. @end