Skip to content

Instantly share code, notes, and snippets.

@nsantorello
Created February 24, 2012 17:01
Show Gist options
  • Save nsantorello/1902037 to your computer and use it in GitHub Desktop.
Save nsantorello/1902037 to your computer and use it in GitHub Desktop.
Great modal loading animation for iPhone.
//
// 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
//
// 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
@nsantorello
Copy link
Author

To cover the entire screen with the loading view, use this from the controller:
LoadingView *loadingView = [LoadingView loadingViewInView:self.view]; // do something [loadingView removeView]

@nsantorello
Copy link
Author

Added ability for you to update the label on the loading view while it is active. Use
loadingView.loadingLabel.text = @"something different";

@nsantorello
Copy link
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment