I am trying to create an animation for switching views on iOS devices.
I have create an application with three views and I have some navigation buttons.
The way I use to switch views is this:
-(IBAction) loadThirdView:(id)sender {
[self clearView];
self.thirdViewController.view.frame = CGRectMake(0, 208, 160, 208);
[self.view insertSubview:thirdViewController.view atIndex:0];
}
As you can see this is the action that takes place once I press the button. What I would like is the new view to appear in an animated way.
Specifically I want it to start from the left hand side of the screen and slide to the right. I do not want it just to appear.
Is this possible? how can I do it?
Oh no! Ah, no! Please do not display UIViewControllers this way.
Present your UIViewController this way:
[self presentModalViewController:self.thirdViewController animated:YES]
Before presenting it, you can change the modalTransitionStyle property of the view controller to suit your needs.
If using a UINavigationController, use instead:
[yourNavController pushModalViewController:self.thirdViewController animated:YES]
This is a nice little article (if not a little too harsh): Abusing UIViewControllers
To animate it the way you specifically would like (as the UINavigationController style is sliding in from the right), you might want to use something like what is proposed in this SO question: iPhone Pushing View Controller in a left direction
You can try
[UIView transitionFromView:currView toView:nextView duration:0.5f options:UIViewAnimationOptionTransitionFlipFromLeft completion:nil];
if you want different type of animation. There're lots AnimationsOptions you can choose, just set the options:.
Sample Code :
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationDuration:0.6];
yourImageVieew.alpha=0.9;//insert here what you want
[UIView commitAnimations];
Related
I have a problem with UIViews to which I really don't know how to proceed.
It will be futile to describe my problem so here are the screenshots of before and after.
Somehow the UIView gets the layout that was defined in interfacebuilder AFTER an image is chosen. Before an image is chosen it doesn't obey to its defined layout for some reason.
Before using imagePicker for picking an image:..........................After Picking image:
|
So yeah that is basically the problem. The black squares are other images and you can tell by that how it should and how it shouldn't, one of the images is being cut (normally behind the "No SIM" label.) I just put them to hide the real images on the screenshots.
So maybe is something in relation to two things I do here.
I resize the image chosen to 320-480 and put it on a smaller UIImageView before uploading it to a server.
If the user is writing on a textField the entire view is animated up, so the keyboard won't hide the textFields.
UPDATE:
I noticed this happens on a UIView that does nothing related to resizing images or textFields. This is happening too on a UIView I have where there are only 3 buttons and 2 labels. Only 5 elements. The 3 buttons are in custom mode with images. So 3 image~Buttons and 2 labels....
Thank you for your help and suggestions fellow Stackoverflowers!!! (Stackoverflowerers?)
I really have no idea on how to proceed here, though I've been playing around transforming the UIView at the viewDidLoad to no avail.
UPDATE 2:
I started to think that maybe there is something wrong with the code I use to make the transition from view to view and has nothing to do with the elements that are contained in it. Since it is happening in all my views EXCEPT the first view. So here is the code I use for the transition of views:
- (void) flipToUploadView {
UploadViewController *aUploadView = [[UploadViewController alloc] initWithNibName:#"UploadView" bundle:nil];
[self setUploadViewController:aUploadView];
[aUploadView release];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:window cache:YES];
[uploadViewController viewWillAppear:YES];
[viewController viewWillDisappear:YES];
[viewController.view removeFromSuperview];
[self.window addSubview:[uploadViewController view]];
[viewController viewDidDisappear:YES];
[uploadViewController viewDidAppear:YES];
[UIView commitAnimations];
}
Sorry don't have enough reputation to comment, but
have both views the same nib?
if not, is it possible that you just forgot to simulate the status bar in InterfaceBuilder for the few which is drawn uncorrect? and thats why the positions are different?
And i think what Tommy means is that normally you use the ModalViewcontroller to change views
[self presentModalViewController:uploadViewController animated:YES];
than all the function calls (willappear,didappear,willdissappear...) are called automatically
but i think this is not the source of the wrong displaying
I've an application with a UITabBarController with five tabs.
Tests on real device show that switching from a tab to another, may take one or more seconds to load the views, because I also have to download some data from the Internet.
What I would like to do is to show a UIActivityIndicatorView while the view is loading, but I couldn't find a solution. Maybe I haven't searched the right way.
Could someone help me?
You should download any data with an asynchronous request, ASIHTTPRequest is a nice wrapper for this.
Then for the UIActivityIndicatorView these are popular options:
Show it on the tab, BEFORE actually
loading anything else in the view.
And when the data is ready just hide
it and show the complete info.
Show your incomplete view, and add
an overlay with the
UIActivityIndicatorView.
The way I do it :
Create a LoadingViewController Class with a UILabel, a UIActivityIndicator and black background .
In the ViewDidLoad method, i set :
[self.view setAlpha:0.0];
[self.activityIndicator startAnimating];
I implement two methods :
-(void)appear{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[self.view setAlpha:0.65];
[UIView commitAnimations];
}
-(void)disappear{
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[self.view setAlpha:0.0];
[UIView commitAnimations];
}
In the label you can set a custom text.
Import this class in the class you are working on and just call :
[loadingViewController appear];
and
[loadingViewController disappear];
I don't have a Mac with me right now and can't verify if i just wrote any mistakes but I hope you get the idea :)
I always prefer to make a custom class for this in case I'll need it at many places in my app.
I'm getting frustrated at this.
I want to create an iPhone application to show a list of events, one day for each 'screen'. I want a bar at the top with 'next' and 'prev' buttons that allow me to go to tomorrow or yesterday.
It is not a UINavigationController style navigation, because navigation is not hierarchical. Therefore I don't think I should use the pushViewController: method, as many examples and tutorials suggest.
I think that the appdelegate class should remove the current view and create a new viewcontroller and view and add it to the window. However I can't manage to get it working. Also I would like nice transitions.
Can someone point to a code sample that I can look at?
Thank you.
P.D. My question is similar to this one but there is no useful answer.
I wouldn't get hung up on the view controller so much. The view controller/view duality can sometimes get in the way of building custom interfaces.
What you need is a UIToolbar with two buttons, and a sorted array of UIView objects configured appropriately for your entities.
Then when the buttons are clicked, simple [UIVIew animations] should get the job done.
I'm not going to write the code for you. Any casual analysis of the build in UIView animation components will point you on your way.
The only real thing I can tell you is that, having built sophisticated interfaces for the iPhone, the biggest learning curve is knowing when and when not to use UIViewController as opposed to UIView. This is tricky because most of the standard apple components use Controller.
Now it works. Just some details were missing. I'll leave the answer here so that other people can comment on it or use it.
In the AppDelegate class I added this method:
-(void) navigateToDay:(NSDate*) newDay fromDay:(NSDate*) currentDay
{
UIViewAnimationTransition transition = ([newDay compare:currentDay]<0)? UIViewAnimationTransitionCurlDown :
UIViewAnimationTransitionCurlUp;
SequentialNavigationViewController* newController = [[SequentialNavigationViewController alloc] initWithNibName:#"SequentialNavigationViewController" bundle:nil];
newController.app = self;
newController.currentDay = newDay;
[newController.view setFrame:[[UIScreen mainScreen] applicationFrame]];
[UIView beginAnimations:#"transition" context:NULL];
[UIView setAnimationDuration:0.50];
[UIView setAnimationTransition:transition forView:self.window cache:YES];
[window addSubview:newController.view];
[self.viewController.view removeFromSuperview];
[UIView commitAnimations];
self.viewController = newController;
[newController release];
}
And I call this method from the SequentialNavigationViewController prevButtonClicked and nextButtonClicked methods.
Not so hard after all!
My iPhone app is tab bar-based, but I would like to fire an action which switches out the tab bar controller view completely and replaces everything in the window with a view from a different XIB file. I would guess this has to be done in the application delegate (since this is the "chief" class), but I don't know the right way to go from there. Does anyone know how to do what I am trying to do?
Thanks in advance!
Your tab view controller could have it's action method, such as -(IBAction)onChangeView and that method calls a method on the [[UIApplication sharedApplicaton] delegate], such as -(void)toggleScreen.
-(IBAction)onChangeView:(id)sender
{
MyAppDelegate *delegate = (MyAppDelegate *)[[UIApplication sharedApplication] delegate];
[delegate toggleScreen];
}
Then in your app delegate method do something like this:
-(void)toggleScreen
{
[[[window subviews] objectAtIndex:0] removeFromSuperview];
[window addSubview:otherView];
}
It may be different if you need transitions, however.
You don't really have to go all the way to the app delegate. You can easily remove your existing views and controllers and add new views. It really does depend on what you are doing. You could, for example, temporarily put aside the existing view structure and go with something totally different, and get back to the original scheme if you want (I'm not sure of the user experience though).
In my apps, I usually have a root view controller or I use my main window to add views to and remove views from. Some views will add other views to themselves or transition another view onto the rootview or main window. Some views close themselves to reveal the view below. The options are limitless, and depend on your needs and architecture.
Thanks guys! Nick, that's just the code I needed. In case anyone finds this handy, here's the code I used to add animation to switch the view. Just put this in a method in the app delegate:
AnotherViewController *anotherViewController = [[AnotherViewController alloc] initWithNibName:#"AnotherView" bundle:nil];
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:1.0];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.window cache:YES];
[[[window subviews] objectAtIndex:0] removeFromSuperview];
[window addSubview:[anotherViewController view]];
[UIView commitAnimations];
I have a View that has a UIWebView, and an OptionsPane (Custom UIViewController with Custom view).
I want when the view is shown, for the options pane (located on the top of the main view) to FLIP into place. I am using the code, and I am getting a strange result.
The FIRST time the view is shown, the options pane seems to already be visible... When I hit BACK on my navController, and pull up the View again, the animation works perfectly.
Can anyone shed some light on this topic?
- (void)viewDidLoad {
[super viewDidLoad];
optionsPane=[[OptionsPaneController alloc] initWithNibName:#"OptionsPane" bundle:nil];
}
- (void)viewWillAppear:(BOOL)animated {
[optionsPane.view removeFromSuperview];
[self checkOptionsVisible];
}
-(void)checkOptionsVisible{
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:[optionsPane view] cache:YES];
[[self view] addSubview:[optionsPane view]];
[theWebView setFrame:CGRectMake(0,87,320,230)];
[[optionsPane view] setFrame:CGRectMake(0,0,320,87)];
[UIView commitAnimations];
}
Hmm, I don't think the viewWillAppear message is getting sent the first time. There are two things that I read in the SDK. You should call super inside that message and there is a big warning that may apply to your first time:
Warning: If the view belonging to a view controller is added to a view hierarchy directly, the view controller will not receive this message. If you insert or add a view to the view hierarchy, and it has a view controller, you should send the associated view controller this message directly. Failing to send the view controller this message will prevent any associated animation from being displayed.
Ultimately, I would run through the debugger and make sure that viewWillAppear message is being sent when you think it is.
If I understand what your explaining, I had a very similar problem the other day.
What happening on the first load is that viewDidLoad fires first. loading the nib file takes a bit more time than it takes for the viewWillAppear to fire itself.
What we're getting is a nib loads after the viewWillApper already retired.
On any load after that, the viewDidLoad will not fire, letting the viewWillAppear to do its loyal flipping job.
What to do?
First, try to change your code to use "viewDidAppear". That should help, but you have to see if it looks good.
Another option (ugly one, I know) is to have a call to checkOptionsVisible on the viewDidLoad too.
If non of that help, I would consider a timer as a hack - if the requirements allow it.
I hope that make you closer to solve the problem.
Updated for your situation:
Instead have four views:
A backing view
The main View
The back view (options pane) 100 pixels
The front view (blank view) 100 pixels
Add the main view to the backing view as normal.
Add the front view to the backing view where you would like the options pane to appear.
make sure the front and back view have the same frame.
Use the same code as below using the methods flip the front and back views.
Original Answer
You need 3 views:
A backing view
The front View
The back view
The backing view just holds the other 2 as they flip back and forth Below are the flipping methods. I place them both in backingViewController:
- (void)displayBack{
//parent controller is an ivar so the sub-view controllers know who their daddy is
backController.parentController = self;
[UIView beginAnimations:nil context:#"flipTransitionToBack"];
[UIView setAnimationDuration:1.2];
//note self.view IS the backing view
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
//remove the front view
[[frontController view] removeFromSuperview];
//add the back view view
[self.view addSubview:[backController view]];
[UIView commitAnimations];
//giving a heads up to the view that is about to come on screen
[backController viewWillAppear:YES];
}
- (void)displayFront{
[UIView beginAnimations:nil context:#"flipTransitionToFront"];
[UIView setAnimationDuration:1.2];
[UIView setAnimationDelegate:self];
//I'm interested in knowing this has happened
[UIView setAnimationDidStopSelector:#selector(flipAnimationDidEndWithID:finished:context:)];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
//remove back view
[[backController view] removeFromSuperview];
//add the front view
[self.view addSubview:[frontController view]];
[UIView commitAnimations];
}
The view property on a UIViewController is lazily-loaded -- even when you're init-ing with a nib as you are here, the view itself doesn't actually get instantiated until the first time the property is accessed.
It's hard to know exactly what's happening without seeing more code, but you may get the results you want if you access optionsPane.view in viewDidLoad (you don't need to do anything with it, just access the property to force loading).