Creating a "loading..." view using iPhone SDK - iphone

How to create that black/gray modal popup kind of view that many apps use, when some long pending operation is in progress?
Like when using location based services, loading a webpage, the screen goes dim and there is a modal view showing a spinning icon "Please wait..."
Example in the following screenshot:

This is actually the undocumented (in 2.2.1 anyway) UIProgressHUD. Create one like this:
In your .h:
#interface UIProgressHUD : NSObject
- (UIProgressHUD *) initWithWindow: (UIView*)aWindow;
- (void) show: (BOOL)aShow;
- (void) setText: (NSString*)aText;
#end
In your .m:
- (void) killHUD: (id)aHUD
{
[aHUD show:NO];
[aHUD release];
}
- (void) presentSheet
{
id HUD = [[UIProgressHUD alloc] initWithWindow:[contentView superview]];
[HUD setText:#"Doing something slow. Please wait."];
[HUD show:YES];
[self performSelector:#selector(killHUD:) withObject:HUD afterDelay:5.0];
}

If you want to avoid undocumented api you can also take a look at MBProgressHUD. It's similar to UIProgressHUD and even has some additional features.

I think the simplest (a few lines of code), fully documented and most beautiful way is to use the UIAlertView with a UIActivityIndicatorView:
http://iosdevelopertips.com/user-interface/uialertview-without-buttons-please-wait-dialog.html
(source: iosdevelopertips.com)

If you add a UIView as a subview of the main window it will cover the entire UI. Make it partially transparent and partially translucent and it will look like a popup.
This example shows how to fade the Default.png splash screen, starting with that it's pretty straightforward to add a couple methods to your application delegate (that has a pointer to the main window) to present and dismiss the progress view.

Take a look at the Wordpress iPhone app (http://iphone.wordpress.org/) for an example of how to do this without using any undocumented API's.

I use LoadingHUDView for this purpose, and it works always.
get LoadingHUDView.m and LoadingHUDView.h and do the following in your base class (or whatever)
#pragma mark ActivityIndicator Methods
-(void) showModalActivityIndicator:(NSString *)message
{
loadingView = [[[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]retain];// origional
//loadingView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)]; //testing
loadingView.backgroundColor = [UIColor grayColor]; //[UIColor colorWithRed:1 green:1 blue:1 alpha:0.3];
LoadingHUDView *loadHud = [[LoadingHUDView alloc] initWithTitle:message];
loadHud.center = CGPointMake(160, 290);
[loadingView addSubview:loadHud];
[loadHud startAnimating];
[loadHud release];
[loadingView setAlpha:0.0];
[self.tableView addSubview:loadingView];
[UIView beginAnimations:#"fadeOutSync" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.5];
[loadingView setAlpha:0.5];
[UIView commitAnimations];
}
-(void) hideModalActivityIndicator {
if (loadingView) {
[UIView beginAnimations:#"fadeOutSync" context:NULL];
[UIView setAnimationDidStopSelector:#selector (removeTranparentView) ];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.5];
[loadingView setAlpha:0];
[UIView commitAnimations];
}
}
-(void)removeTranparentView
{
[loadingView removeFromSuperview];
[loadingView release];
loadingView = nil;
}
HOPE THIS HELPS.
thank you

In XIB file, place UIView and UIActivityIndicatorView.
Set ActivityIndicatorView Property SetAnimated to Yes.
#property (retain, nonatomic) IBOutlet UIView* m_LoadingView;
While Starting long operations, Add the LoadingView to the view
m_LoadingView.layer.cornerRadius = 10;
m_LoadingView.center = self.view.center;
[self.view addSubview:m_LoadingView];
After completing the process, Remove LoadingView from super view.
[m_LoadingView removeFromSuperView];

Related

Present Modal View with Animation Effect

In my iPhone App I need to display a modal view with transparent background and it should appear with animation like it is appearing from center of view and its size is increasing.
similar like "drawing something" iPhone App when we click on settings button.
How do I do this?
You can do one of 4 following transition styles:
viewController.modalTransitionStyle = UIModalTransitionStyleCoverVertical;
viewController.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
viewController.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
viewController.modalTransitionStyle = UIModalTransitionStylePartialCurl;
[self presentModalViewController:viewController animated:YES];
If you want something that is not included in these defaults you are going to have to build your own custom animation for presenting the modal view. Like the following but obviously for the style you want.
UIModalTransitionStyle horizontal movement
Let's say you have a viewController thats called aScoreSheet that you want to present. Try to define this method in the view controller that's going to do the presenting.
-(void) presentTransparentModalViewController: (ScoreSheet *) aViewController
{
scoreSheet = aViewController;
UIView *view = aViewController.view;
view.opaque = NO;
[view.subviews enumerateObjectsUsingBlock:^(id obj, NSUInteger idx, BOOL *stop) {
UIView *each = obj;
each.opaque = NO;
}];
[self.view addSubview:view];
view.center = CGPointMake(160, 800); //for iPhone
[UIView animateWithDuration:0.9 delay:0 options:UIViewAnimationCurveEaseInOut animations:^{
view.center = CGPointMake(160, 240);
} completion:^(BOOL finished) {
self.view.userInteractionEnabled=YES;
}];
}
and then to dismiss the controller:
-(void) dismissTransparentModalViewControllerAnimated:(BOOL) animated{
if (animated) {
[UIView animateWithDuration:0.4
animations:^{
scoreSheet.view.center = CGPointMake(scoreSheet.view.center.x, scoreSheet.view.center.y + 480);
} completion:^(BOOL finished) {
[scoreSheet.view removeFromSuperview];
scoreSheet = nil;
}];
}
}
Not a full answer, but maybe you can take a look at this open source library:
https://github.com/Split82/HMGLTransitions
It has some custom modal transitions, maybe not exactly the one you are looking for, but you can easily add your transition by subclassing HMGLTransition.
Hope this helps

presentModalViewController in CGRect

Is it possible to present a modal view controller in such a way that the modal view is confined to the space included in a CGRect?
If not, please explain how to replicate the cross-disolve modal view transition between two views.
Thanks.
To cross-dissolve to a regular view controller, you can set it's modalTransitionStyle to UIModalTransitionStyleCrossDissolve then present it modally.
To perform a cross-dissolve between some pair of subviews (confined to their frame CGRects), you can use this UIView method:
+ (void)transitionFromView:(UIView *)fromView toView:(UIView *)toView duration:(NSTimeInterval)duration options:(UIViewAnimationOptions)options completion:(void (^)(BOOL finished))completion.
Here's how you might use that in code:
#interface ViewController ()
#property(strong,nonatomic) UIView *redView;
#property(strong,nonatomic) UIView *blueView;
#end
#implementation ViewController
#synthesize redView=_redView;
#synthesize blueView=_blueView;
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
self.redView = [[UIView alloc] initWithFrame:CGRectMake(40.0, 40.0, 240.0, 100.0)];
self.redView.backgroundColor = [UIColor redColor];
[self.view addSubview:self.redView];
self.blueView = [[UIView alloc] initWithFrame:CGRectMake(40.0, 40.0, 240.0, 100.0)];
self.blueView.backgroundColor = [UIColor blueColor];
}
- (IBAction)crossDisolve:(id)sender {
UIView *fromView = (self.redView.superview)? self.redView : self.blueView;
UIView *toView = (fromView==self.redView)? self.blueView : self.redView;
[UIView transitionFromView:fromView
toView:toView
duration:1.0
options:UIViewAnimationOptionTransitionCrossDissolve
completion:^(BOOL finished) {NSLog(#"done!");}
];
// now the fromView has been removed from the hierarchy and the toView has been added
// please note that this code depends on ARC to release objects correctly
}
The harder part of your question is the idea of making that new sub-view "modal" by which I'm guessing you mean that covers only part of the display but takes input focus exclusively. The nearest thing to that in the SDK is UIAlertView.
How about you just use UIView animations:
UIView* view = [[UIView alloc] initWithFrame:CGRectMake(x,y,w,h)];
[view setAlpha:0];
[self.view addSubView:view];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[view setAlpha:1];
[UIView commitAnimations];
Voila! It fades in! :)

How to zoom image to fullscreen mode?

I have paging UIScrollView with images. I want to implement animated zooming of image to fullscreen on some gesture. And another animation to zoom image back to scroll view. Like in Photos app on iPad or like videos in Safari.
Of course it would not be UIImageView. It would be some wrapper class with image inside. The main question is how to present fullscreen view. Is it must be modal view or not.
Any help is appreciated.
Check on touching the image
if it is small convert into full size.
if it is large convert into small size.
- (void)touchesBegan:(NSSet *)touches withEvent:(UIEvent *)event {
if (isLarge) [self makeSmall];
else [self makeFull];
}
- (void)makeFull {
[[self superview] bringSubviewToFront:self];
isLarge = YES;
CGRect largeFrame = [self superview].bounds;
original = self.frame;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[self setFrame:largeFrame];
[internal setFrame:self.bounds];
[UIView commitAnimations];
}
- (void)makeSmall {
isLarge = NO;
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[self setFrame:original];
[internal setFrame:self.bounds];
[UIView commitAnimations];
}
I found a solution to this that involves both gesture recognizers and animated transitions. You remove the scrollview and add the fullscreen image. Then reverse that to return to the just the scrollview.
Use the frame of the window to determine size for the new UIImage.
The types of gesture recognizers can be adjusted to suit your needs!
-(void)viewDidLoad
{
[super viewDidLoad];
UITapGestureRecognizer *tapTwice = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapTwice:)];
tapTwice.numberOfTapsRequired = 2;
[self.imageView addGestureRecognizer:tapTwice];
}
- (void)tapOnce:(id)tapOnce {
[UIView transitionWithView:self.view
duration:0.7
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^ {
[self.fullScreenImage removeFromSuperview];
}
completion:nil];
}
- (void)tapTwice:(id)tapTwice {
if(self.fullScreenImage == nil){
self.fullScreenImage = [[UIImageView alloc] initWithFrame:self.view.window.frame];
UITapGestureRecognizer *tapOnce = [[UITapGestureRecognizer alloc] initWithTarget:self action:#selector(tapOnce:)];
tapOnce.numberOfTapsRequired = 1;
[tapOnce requireGestureRecognizerToFail:tapTwice];
[self.fullScreenImage addGestureRecognizer:tapOnce];
[self.fullScreenImage setUserInteractionEnabled:YES];
//self.fullScreenImage = [load your image here]
}
[UIView transitionWithView:self.view.window
duration:0.7
options:UIViewAnimationOptionTransitionCrossDissolve
animations:^ {
[self.view.window addSubview:self.fullScreenImage];
}
completion:nil];
}
Download this sample for Image gallery sample code and get through it. It would definitely helps you to understand how to implement your idea.
Like below you can use for zooming the image view.
UIView * viewForScroll;
UIImageView *imgviewForScroll;
UIScrollView *scrollToRead = [[UIScrollViewalloc]initWithFrame:CGRectMake(175, 5, 300, 311)];
scrollToRead.backgroundColor = [UIColordarkGrayColor];
scrollToRead.showsHorizontalScrollIndicator = YES;
scrollToRead.delegate = self;
[scrollToRead setContentSize:CGRectMake(0, 0, 300, 400).size];
scrollToRead.maximumZoomScale = 2;
scrollToRead.minimumZoomScale = 1;
[self.view addSubview:scrollToRead];
[scrollToRead release];
viewForScroll = [[UIViewalloc]initWithFrame:CGRectMake(0,0,300,400)];
[scrollToRead addSubview:viewForScroll];
[viewForScroll release];
imgviewForScroll = [[UIImageViewalloc]initWithFrame:CGRectMake(0,0,300,400)];
imgviewForScroll.image = [UIImageimageWithContentsOfFile:[arrayComicContentobjectAtIndex:0]];
[viewForScroll addSubview:imgviewForScroll];
[imgviewForScroll release];
//=========UIScrollView Delegate methods
- (UIView *)viewForZoomingInScrollView:(UIScrollView *)scrollView {
return viewForScroll;
}
Like to know if you need any further clarifications

Fade to black within a uinavigationcontroller?

I want to fade the whole screen (including navigation bar) to black when a user presses a button on a uinavigationcontroler, before showing a new view. (i don't want to push this new view, for various reasons).
How would I achieve this?
EDIT
Thanks to Mac and Eiko, I have figured it out. Here's the code I used. Not sure if it is optimal, but it does the trick.
// this is called from a programmatically constructed button.
// change (void) to (IBAction) if linking from IB.
- (void)fadeAndShow:(id)sender
{
// blackView is a #property which has been #synthesize-d
// do I really need to alloc and init this?
blackView = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
blackView.alpha = 0.0;
[blackView setBackgroundColor:[UIColor blackColor]];
[self.navigationController.navigationBar.superview addSubview:blackView];
[UIView beginAnimations:#"fadeAway" context:NULL];
[UIView setAnimationDelegate:self];
[UIView setAnimationDuration:0.75];
[UIView setAnimationDidStopSelector:#selector(showNewScreen:finished:context:)];
blackView.alpha = 1.0;
[UIView commitAnimations];
}
-(void)showNewScreen:(NSString *)animationID finished:(BOOL)finished context:(void *)context
{
// I guess you could fade in somewhere in the new view controller.
// don't know how to fade back in this view tho... viewDidAppear?
NewViewController *controller = [[NewViewController alloc] initWithNibName:#"NewView" bundle:nil];
[self.navigationController setNavigationBarHidden:YES];
controller.hidesBottomBarWhenPushed = YES;
[[self navigationController] pushViewController:controller animated:NO];
[blackView removeFromSuperview];
[controller release];
}
Off the top of my head (I haven't actually tested the following at all):
-(IBAction) buttonClicked:(id) sender
{
[UIView beginAnimations:#"myAnimation" context:nil];
[UIView setAnimationDuration:ANIMATION_DURATION];
blackView.alpha = 1.0;
[UIView commitAnimations];
}
Create a UIView in the navigationbar's superview (which I'm assuming is window-sized) that is the same size as the window.
Set that view's backgroundColor to [UIColor blackColor], and its alpha to 0.0.
In your button handler do something like the above (assuming your new UIView is blackView and ANIMATION_DURATION is your desired animation time in seconds).
Then, add your new view on top.
EDIT: too quick for me Eiko! Also, code at the top since the ordered list seems to screw around with the code formatting - sorry the answer reads a little odd.
You can add a black coloured UIView in screen size on top of your current view, and animate its alpha from 0 to 1. When the animation is done, add your new view. You can remove the black one then. Animate from 1 to 0 for the opposite effect - going from black to the content).

Fade from iPhone default bitmap into main app

What's the easiest/fastest/most efficient way to perform a gradual (0.5 sec) fade from Default.png to the initial app view?
My initial try, which doesn't work so well .. it's Saturday night, let's see if we can do better :)
UIImageView* whiteoutView = [[UIImageView alloc] initWithFrame:self.view.frame]; // dealloc this later ??
whiteoutView.image = [UIImage imageNamed:#"Default.png"];
whiteoutView.alpha = 1.0;
[self.view.frame addSubview:whiteoutView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDelay:0.5];
whiteoutView.alpha = 0;
[UIView commitAnimations];
What about:
UIImageView* whiteoutView = [[[UIImageView alloc] initWithFrame:self.view.frame] autorelease];
if (whiteoutView != nil)
{
whiteoutView.image = [UIImage imageNamed:#"Default.png"];
[self.view addSubview:whiteoutView];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration: 0.5];
whiteoutView.alpha = 0.0;
[UIView commitAnimations];
}
(The things you had wrong were setAnimationDelay vs setAnimationDuration, not properly releasing the view and trying to add the view to self.view.frame instead of self.view. The compiler should have caught that last one. Did it?)
Here's a simple view controller that fades out the default image and removes itself from the view hierarchy. The advantage to this approach is that you can use this without modifying your existing view controllers...
#interface LaunchImageTransitionController : UIViewController {}
#end
#implementation LaunchImageTransitionController
- (void)viewDidLoad {
[super viewDidLoad];
self.view = [[[UIImageView alloc] initWithImage:[UIImage imageNamed:#"Default.png"]] autorelease];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(imageDidFadeOut:finished:context:)];
self.view.alpha = 0.0;
[UIView commitAnimations];
}
- (void)imageDidFadeOut:(NSString *)animationID finished:(NSNumber *)finished context:(void *)context
{
[self.view removeFromSuperview];
//NOTE: This controller will automatically be released sometime after its view is removed from it' superview...
}
#end
Here is how you might use it in your app delegate:
- (void)applicationDidFinishLaunching:(UIApplication *)application {
//create your root view controller, etc...
UIViewController *rootController = ....
LaunchImageTransitionController *launchImgController = [[[LaunchImageTransitionController alloc] init] autorelease];
[window addSubview:rootController.view];
[window addSubview:launchImgController.view];
[window makeKeyAndVisible];
}
Other than using setAnimationDelay: instead of setAnimationDuration:, it looks pretty good. What don't you like about the results?
Edit: Wow beaten hard.