Hello World!
First off I would like to thank Matt for building this site for us and allowing us to contribute to the technical community. My name is Chason and to start off my blogging career I would like to showcase a simple loading screen for iOS devices.
This snippet of code is intended to be used in your app delegate and accessed by all view controllers that need it. The advantage to this structure is to cut down on redundant code and excessive IBOutlets in .xibs for every view controller. The same solution may also be found by setting up IBOutlets in the app delegate and adding the UI elements to the MainWindow.xib, but for the sake of learning and extensibility I will show you the programmatic way. I have also implemented rotation for the loadingView, but I will not include it in this post. It is however in the iOS project I have included and I recommend you check it out if interested.
Step 1:
For step one you need to create instance variables in your appDelegate.h file. The loadingView will be the rounded box in the middle of the screen and the dimView will be a mostly transparent black view behind our loadingView. The instance variables allow for easy manipulation of the UI elements after creation and also retains the elements so we dont lose them after they are removed from the window. We also want to create the method declarations for the loadingView so other viewControllers may call them.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | @interface LoadingTestAppDelegate : NSObject <UIApplicationDelegate> { UIView* loadingView; UIView* dimView; UILabel* label; } @property ( nonatomic, retain ) UIView* loadingView; @property ( nonatomic, retain ) UIView* dimView; @property ( nonatomic, retain ) UILabel* label; - (void) createLoading; - (void) showLoading: (NSString*) title; - (void) hideLoading; //Refer to iOS project for rotation. //- (void) rotateLoading; //- (void) animateRotation: (CGAffineTransform) transform; |
To actually use the getter and setter methods for the variables we need to synthesize the variables in the appDelegate.m file.
1 2 3 4 5 | @implementation LoadingTestAppDelegate @synthesize window = _window; @synthesize viewController = _viewController; @synthesize loadingView, dimView, label; // <-- Here |
Step 2:
Now that we have a way to grab a handle to our UI elements we need to setup methods that make showing and hiding our loading screen relatively easy.
Here we will define the methods declared earlier in the appDelegate.h file. There are three methods. “createLoading” which will give our UI elements values. “showLoading” which will calculate where on the screen the loading view should go. Finally, “hideLoading” which will remove the loading view from the window.
As you view the createLoading method you may notice something strange, and your probably wondering why is there another uiview in our loading view? The reason behind the extra view is so we may add elements to the loading view without the elements themselves becoming transparent. If you notice, we dont add the indicator and label to the transparent view because we want them to remain opaque.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 | - (void) createLoading { //create the loading view //The loadingView is retained by the appDelegate CGSize loadingSize = CGSizeMake( 150, 150 ); loadingView = [[UIView alloc] initWithFrame:CGRectMake(0,0,0,0)]; loadingView.backgroundColor = [UIColor clearColor]; //Round corners the corners of the loadingView //NOTE: you must #import <QuartzCore/QuartzCore.h> //for this to work [[loadingView layer] setCornerRadius:10]; //Any overflowing elements will be clipped. //No elements should overflow anyway [loadingView setClipsToBounds:YES]; //Create colored border using CALayer property [[loadingView layer] setBorderColor:[[UIColor whiteColor] CGColor]]; [[loadingView layer] setBorderWidth:2.75]; //create the semi-transparent view CGRect transparentViewFrame = CGRectMake( 0, 0, loadingSize.width, loadingSize.height ); UIView* transparentView = [[UIView alloc] initWithFrame:transparentViewFrame ]; transparentView.backgroundColor = [UIColor blackColor]; transparentView.alpha = 0.75; [loadingView addSubview:transparentView]; [transparentView release]; //create the activity indicator UIActivityIndicatorView* loadingIcon = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle: UIActivityIndicatorViewStyleWhiteLarge]; [loadingIcon startAnimating]; //Set the frame for the indicator CGRect liFrame = loadingIcon.frame; CGRect loadingIconFrame = CGRectMake( loadingSize.width/2 - liFrame.size.width/2, loadingSize.height/2 - 20 - liFrame.size.height/2, liFrame.size.width, liFrame.size.height ); loadingIcon.frame = loadingIconFrame; [loadingView addSubview:loadingIcon]; [loadingIcon release]; //Create the text to place in the loading view. //Label will also be retained by the appDelegate //so we may change the title CGRect labelFrame = CGRectMake( 10, loadingSize.height - 80, loadingSize.width - 20, 55 ); label = [[UILabel alloc] initWithFrame:labelFrame]; label.textColor = [UIColor whiteColor]; label.textAlignment = UITextAlignmentCenter; label.backgroundColor = [UIColor clearColor]; label.font = [UIFont boldSystemFontOfSize:50]; label.adjustsFontSizeToFitWidth = YES; [loadingView addSubview:label]; //create the view to dim the screen //Also retained by the appDelegate dimView = [[UIView alloc] initWithFrame:CGRectMake(0,0,0,0) ]; dimView.backgroundColor = [UIColor blackColor]; dimView.alpha = 0.25; } |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | - (void) showLoading: (NSString*) title { //Grab application frames CGRect appFrame = [[UIScreen mainScreen] bounds]; //Calculate the loading view frame CGSize loadingSize = CGSizeMake( 150, 150 ); CGRect loadingFrame = CGRectMake( appFrame.size.width/2 - loadingSize.width/2, appFrame.size.height/2 - loadingSize.height/2, loadingSize.width, loadingSize.height ); loadingView.frame = loadingFrame; label.text = title; CGRect dimViewFrame = CGRectMake( 0, 0, appFrame.size.width, appFrame.size.height ); dimView.frame = dimViewFrame; //Refer to the included iOS project for this method //[self rotateLoading]; //Add the loadingView and dimView to the window [[[UIApplication sharedApplication] keyWindow] addSubview:dimView]; [[[UIApplication sharedApplication] keyWindow] addSubview:loadingView]; } |
1 2 3 4 5 6 7 8 9 10 | - (void) hideLoading { [loadingView removeFromSuperview]; [dimView removeFromSuperview]; //For rotation refer to iOS project for complete details //CGAffineTransform rotationTransform = CGAffineTransformIdentity; //rotationTransform = CGAffineTransformRotate(rotationTransform, degreesToRadians(0)); //loadingView.transform = rotationTransform; } |
Now we need to call the createLoading method when the application fires up. I simply add the method after the appDelegate is ready.
1 2 3 4 5 6 7 8 9 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { // Override point for customization after application launch. self.window.rootViewController = self.viewController; [self.window makeKeyAndVisible]; [self createLoading]; // <-- Here return YES; } |
Step: 3
Alright, now that we have the loading methods setup and the loadingView created, we may call the methods from any view controller whenever we want. Keep in mind even on view changes the loadingView will remain visible so be sure to hide when necessary.
So in any viewController you wish to show the loadingView just make calls like this:
1 2 3 4 5 6 7 8 9 10 11 | //Whatever function you want here - (void) viewDidLoad { //Grab a handle to the appDelegate LoadingTestAppDelegate* appDelegate = [[UIApplication sharedApplication] delegate]; //Maybe do some stuff here [appDelegate showLoading: @"Loading Content..." ]; //Churning... //Little more Churning... [appDelegate hideLoading]; } |
Summary
Thats it for the simple iOS loading indicator. With the code supplied you should be able to make a decent loading indicator that looks great in portrait orientation. If you want to support multiple orientations refer to the supplied iOS project for full details.
Thanks everyone!


