Created
February 24, 2012 17:01
-
-
Save nsantorello/1902037 to your computer and use it in GitHub Desktop.
Great modal loading animation for iPhone.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// LoadingView.h | |
// LoadingView | |
// | |
// Created by Matt Gallagher on 12/04/09. | |
// Copyright Matt Gallagher 2009. All rights reserved. | |
// | |
// Permission is given to use this source code file, free of charge, in any | |
// project, commercial or otherwise, entirely at your risk, with the condition | |
// that any redistribution (in part or whole) of source code must retain | |
// this copyright and permission notice. Attribution in compiled projects is | |
// appreciated but not required. | |
// | |
#import <UIKit/UIKit.h> | |
@interface LoadingView : UIView | |
{ | |
} | |
@property (nonatomic, retain) UILabel* loadingLabel; | |
+ (id)loadingViewInView:(UIView *)aSuperview; | |
- (void)removeView; | |
@end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// | |
// LoadingView.m | |
// LoadingView | |
// | |
// Created by Matt Gallagher on 12/04/09. | |
// Copyright Matt Gallagher 2009. All rights reserved. | |
// | |
// Permission is given to use this source code file, free of charge, in any | |
// project, commercial or otherwise, entirely at your risk, with the condition | |
// that any redistribution (in part or whole) of source code must retain | |
// this copyright and permission notice. Attribution in compiled projects is | |
// appreciated but not required. | |
// | |
#import "LoadingView.h" | |
#import <QuartzCore/QuartzCore.h> | |
// | |
// NewPathWithRoundRect | |
// | |
// Creates a CGPathRect with a round rect of the given radius. | |
// | |
CGPathRef NewPathWithRoundRect(CGRect rect, CGFloat cornerRadius) | |
{ | |
// | |
// Create the boundary path | |
// | |
CGMutablePathRef path = CGPathCreateMutable(); | |
CGPathMoveToPoint(path, NULL, | |
rect.origin.x, | |
rect.origin.y + rect.size.height - cornerRadius); | |
// Top left corner | |
CGPathAddArcToPoint(path, NULL, | |
rect.origin.x, | |
rect.origin.y, | |
rect.origin.x + rect.size.width, | |
rect.origin.y, | |
cornerRadius); | |
// Top right corner | |
CGPathAddArcToPoint(path, NULL, | |
rect.origin.x + rect.size.width, | |
rect.origin.y, | |
rect.origin.x + rect.size.width, | |
rect.origin.y + rect.size.height, | |
cornerRadius); | |
// Bottom right corner | |
CGPathAddArcToPoint(path, NULL, | |
rect.origin.x + rect.size.width, | |
rect.origin.y + rect.size.height, | |
rect.origin.x, | |
rect.origin.y + rect.size.height, | |
cornerRadius); | |
// Bottom left corner | |
CGPathAddArcToPoint(path, NULL, | |
rect.origin.x, | |
rect.origin.y + rect.size.height, | |
rect.origin.x, | |
rect.origin.y, | |
cornerRadius); | |
// Close the path at the rounded rect | |
CGPathCloseSubpath(path); | |
return path; | |
} | |
@implementation LoadingView | |
@synthesize loadingLabel; | |
// | |
// loadingViewInView: | |
// | |
// Constructor for this view. Creates and adds a loading view for covering the | |
// provided aSuperview. | |
// | |
// Parameters: | |
// aSuperview - the superview that will be covered by the loading view | |
// | |
// returns the constructed view, already added as a subview of the aSuperview | |
// (and hence retained by the superview) | |
// | |
+ (id)loadingViewInView:(UIView *)aSuperview | |
{ | |
LoadingView *loadingView = | |
[[[LoadingView alloc] initWithFrame:[aSuperview bounds]] autorelease]; | |
if (!loadingView) | |
{ | |
return nil; | |
} | |
loadingView.opaque = NO; | |
loadingView.autoresizingMask = | |
UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight; | |
[aSuperview addSubview:loadingView]; | |
const CGFloat DEFAULT_LABEL_WIDTH = 280.0; | |
const CGFloat DEFAULT_LABEL_HEIGHT = 50.0; | |
CGRect labelFrame = CGRectMake(0, 0, DEFAULT_LABEL_WIDTH, DEFAULT_LABEL_HEIGHT); | |
UILabel *loadingLabel = | |
[[[UILabel alloc] | |
initWithFrame:labelFrame] | |
autorelease]; | |
loadingView.loadingLabel = loadingLabel; | |
loadingLabel.text = NSLocalizedString(@"Communicating...", nil); | |
loadingLabel.textColor = [UIColor whiteColor]; | |
loadingLabel.backgroundColor = [UIColor clearColor]; | |
loadingLabel.textAlignment = UITextAlignmentCenter; | |
loadingLabel.font = [UIFont boldSystemFontOfSize:[UIFont labelFontSize]]; | |
loadingLabel.autoresizingMask = | |
UIViewAutoresizingFlexibleLeftMargin | | |
UIViewAutoresizingFlexibleRightMargin | | |
UIViewAutoresizingFlexibleTopMargin | | |
UIViewAutoresizingFlexibleBottomMargin; | |
[loadingView addSubview:loadingLabel]; | |
UIActivityIndicatorView *activityIndicatorView = | |
[[[UIActivityIndicatorView alloc] | |
initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleWhiteLarge] | |
autorelease]; | |
[loadingView addSubview:activityIndicatorView]; | |
activityIndicatorView.autoresizingMask = | |
UIViewAutoresizingFlexibleLeftMargin | | |
UIViewAutoresizingFlexibleRightMargin | | |
UIViewAutoresizingFlexibleTopMargin | | |
UIViewAutoresizingFlexibleBottomMargin; | |
[activityIndicatorView startAnimating]; | |
CGFloat totalHeight = | |
loadingLabel.frame.size.height + | |
activityIndicatorView.frame.size.height; | |
labelFrame.origin.x = floor(0.5 * (loadingView.frame.size.width - DEFAULT_LABEL_WIDTH)); | |
labelFrame.origin.y = floor(0.5 * (loadingView.frame.size.height - totalHeight)); | |
loadingLabel.frame = labelFrame; | |
CGRect activityIndicatorRect = activityIndicatorView.frame; | |
activityIndicatorRect.origin.x = | |
0.5 * (loadingView.frame.size.width - activityIndicatorRect.size.width); | |
activityIndicatorRect.origin.y = | |
loadingLabel.frame.origin.y + loadingLabel.frame.size.height; | |
activityIndicatorView.frame = activityIndicatorRect; | |
// Set up the fade-in animation | |
CATransition *animation = [CATransition animation]; | |
[animation setType:kCATransitionFade]; | |
[[aSuperview layer] addAnimation:animation forKey:@"layerAnimation"]; | |
return loadingView; | |
} | |
// | |
// removeView | |
// | |
// Animates the view out from the superview. As the view is removed from the | |
// superview, it will be released. | |
// | |
- (void)removeView | |
{ | |
UIView *aSuperview = [self superview]; | |
[super removeFromSuperview]; | |
// Set up the animation | |
CATransition *animation = [CATransition animation]; | |
[animation setType:kCATransitionFade]; | |
[[aSuperview layer] addAnimation:animation forKey:@"layerAnimation"]; | |
} | |
// | |
// drawRect: | |
// | |
// Draw the view. | |
// | |
- (void)drawRect:(CGRect)rect | |
{ | |
rect.size.height -= 1; | |
rect.size.width -= 1; | |
const CGFloat RECT_PADDING = 8.0; | |
rect = CGRectInset(rect, RECT_PADDING, RECT_PADDING); | |
const CGFloat ROUND_RECT_CORNER_RADIUS = 5.0; | |
CGPathRef roundRectPath = NewPathWithRoundRect(rect, ROUND_RECT_CORNER_RADIUS); | |
CGContextRef context = UIGraphicsGetCurrentContext(); | |
const CGFloat BACKGROUND_OPACITY = 0.55; | |
CGContextSetRGBFillColor(context, 0, 0, 0, BACKGROUND_OPACITY); | |
CGContextAddPath(context, roundRectPath); | |
CGContextFillPath(context); | |
const CGFloat STROKE_OPACITY = 0.15; | |
CGContextSetRGBStrokeColor(context, 1, 1, 1, STROKE_OPACITY); | |
CGContextAddPath(context, roundRectPath); | |
CGContextStrokePath(context); | |
CGPathRelease(roundRectPath); | |
} | |
// | |
// dealloc | |
// | |
// Release instance memory. | |
// | |
- (void)dealloc | |
{ | |
[super dealloc]; | |
} | |
@end |
Added ability for you to update the label on the loading view while it is active. Use
loadingView.loadingLabel.text = @"something different";
Also, note this is code modified from
http://cocoawithlove.com/2009/04/showing-message-over-iphone-keyboard.html
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
To cover the entire screen with the loading view, use this from the controller:
LoadingView *loadingView = [LoadingView loadingViewInView:self.view]; // do something [loadingView removeView]