I have 2 view controller and I play a music with AVAudioPlayer in the first view controller.
I go to second view controller and stop the music :
[audioPlayer stop];
[UIView beginAnimations:#"Curl View" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view cache:YES];
[self.view addSubview:secondController.view];
[UIView commitAnimations];
When I go back to first view controller again, I want to play my music again but the code doesn't touch viewDidLoad again.
Here is my code to go back :
[UIView beginAnimations:#"Flipping View" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view.superview cache:YES];
[self.view removeFromSuperview];
[UIView commitAnimations];
Please share me some solutions or what the code execute after that..Thanks in advance
This is happens Only because of you are calling your Music Playing code from viewDidLoad
And viewDidLoad method calls Only One time For ViewController.
You should Call your code(Playing Music) from viewWillAppear instead of viewDidLoad method.
I suggest you should read UIViewControler Documentation.
Updated Answer:As you want to Play the Music File at the time of loading and Coming back to View .
There may some problem regarding the Performance.
Because you calls the Music file immediately loading time of view.
So View below Lines of explaination.
ViewDidLoad - This method is called after the view controller has loaded its view hierarchy into memory. This method is called regardless of whether the view hierarchy was loaded from a nib file or created programmatically in the loadView method. You usually override this method to perform additional initialization on views that were loaded from nib files.
ViewWillAppear:When this gets called, it means that the iPhone is already ready to show the UIView to the user, and anything heavy you do here will impact performance in a very visible manner (like animations being delayed,or playing music etc).
ViewDidAppear: Finally,This Notifies the view controller that its view was added to a view hierarchy.so this method is good enough for such task Like for example playing music file.Note-->you must call super at some point in your implementation.
Write you play code in viewWillAppear: , it is called when ever your view is appeared.
viewDidLoad: is called only once for a view controller
Update
Use these line to remove your second view
[super viewWillAppear:animated];
UIView beginAnimations:#"Flipping View" context:nil];
[UIView setAnimationDuration:0.5];
[UIView setAnimationDelegate:self];
[UIView setAnimationDidStopSelector:#selector(animationEnded)];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view.superview cache:YES];
[self.view removeFromSuperview];
[UIView commitAnimations];
And this method will be called when view is removed
- (void)animationEnded{
NSURL *url = [NSURL fileURLWithPath:[NSString stringWithFormat:#"%#/BGMCover2.mp3", [[NSBundle mainBundle] resourcePath]]];
NSError *error; audioPlayer = [[AVAudioPlayer alloc] initWithContentsOfURL:url error:&error]; audioPlayer.numberOfLoops = -1;
[audioPlayer play];
}
Before doing your application please get deep knowledge of UIViewController life cycle. You can follow the following link :
UIViewController Life Cycle
Related
I need some help with some basic transition work. I think I don't understand this conceptually.
I load a main view which loads a 'log in screen' in its viewDidLoad.
The 'log in screen' is a custom xib + custom view controller.
It is loaded in the following way:
ISSplashScreenViewController* splashScreenController = [[ISSplashScreenViewController alloc] initWithNibName:#"ISSplashScreen" bundle:nil];
[UIView beginAnimations:nil context:nil];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:splashScreenController.view cache:YES];
[UIView setAnimationDuration: 1.5];
[splashScreenController viewWillAppear:YES];
[self.view addSubview:splashScreenController.view];
[splashScreenController viewDidAppear:YES];
[UIView commitAnimations];
All I can see is the status bar animating (and I think this is because it is hidden in the main window but I call for it in the log in screen's viewDidLoad).
The body of the log in screen 'just appears'.
I was wondering if someone could explain why this isn't working and perhaps suggest what i could do to make it work. I think I have to remove the main view from the application's sub views and then load the log in view.
I tried this also, but it doesnt work. The main view just sits there.
[splashScreenController viewWillAppear:YES];
[self.view.superview addSubview:splashScreenController.view];
[self.view.superview bringSubviewToFront:splashScreenController.view];
[self.view removeFromSuperview];
[splashScreenController viewDidAppear:YES];
Any help is much appreciated,
Thanks
Try calling -setAnimationTransition:forView:cache: with self.view rather than the splash-screen controller’s view.
How can I modify the animation for dismiss?
for present, I've used :
SlideShow *slider = [[SlideShow alloc] initWithNibName:#"SlideShow" bundle:nil];
slider.view.alpha = 0.0;
[self presentModalViewController: slider animated: NO];
[UIView beginAnimations: nil context: nil];
[UIView setAnimationDuration:1.5];
[UIView setAnimationCurve:UIViewAnimationCurveEaseIn];
slider.view.alpha = 1.0;
[UIView commitAnimations];
and it works..
But how about a way to dismiss it using a custom animation (I was looking for a Fade-Out animation for dismiss)
Thanks.
You are fading view controllers the old school way, since iOS 3 the easiest and best way to fade a view controller is to set its property: (ex. in the init method)
self.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
Your view controller will then fade nicely in and out.
presentModalViewController is essentially a method that serves up a pre-baked animation for your viewController.view. If you want to make a custom animation for dismissing or presenting a modal view, you have to handle it all on your own.
Is it possible to create a viewcontroller that could handle 5 views?
And is it possible to implement a different button on every view to make a transition to root view?
So my idea of the app is when I load it it takes me to main window, and on that window there will be 5 button that will take me to the 5 views, and after I'm in that view, among other buttons there will be just one button that will take me only to the MainView.
Let's say that some of those 5 views will be Options, Score, Statistics, something like that.
If it is possible to make an app like that using so much views, is it a good approach?
This would be possible, but from what you describe, it does not sound like a good idea. I would suggest instead making a Tab Bar app, and having a separate view controller for each of your 5 views.
If you do not want to make a tab bar app, you can certainly do what you describe, but I would recommend having a separate view controller instance for each view. You could have your 5 buttons in your main view, and each button could push a modal view with no animation. You could then add whatever transition animation you want. In your modal view, you could have a button that pops the modal view.
In your main view controller, you would do this:
- (IBAction)button1Click {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlUp forView:self.view cache:YES];
UIViewController *newController = [[UIViewController alloc] initWithNibName:#"View1" bundle:nil];
[self presentModalViewController:newController animated:NO];
[newController release];
[UIView commitAnimations];
}
And in your view 1 controller:
- (IBAction)backToMainClick {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionCurlDown forView:self.view cache:YES];
[self dismissModalViewControllerAnimated:NO];
[UIView commitAnimations];
}
I have a UIView in my class (besides the original view) made in interface builder.
#interface TimeLineGrid : UIViewController {
UIView *toggleView;
}
#property (nonatomic, retain) IBOutlet UIView *toggleView;
I have synthesized it as well. I have implemented a swipe gesture so that when swiped up, the toggle view is added and when swiped down the toggle view is removed.
-(void)swipedUp {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];
[self.view addSubview:self.toggleView];
[UIView commitAnimations];
}
-(void)swipedDown {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
[self.toggleView removeFromSuperview];
[UIView commitAnimations];
}
It works fine when I swipe up once and when I swipe down after that. But when i swipe up once again, it crashes with EXC_BAD_ACCESS error. I know this has something to do with the retain count increasing when I addSubview and reducing when I removeSubview. Can someone shed more light on this? How do I achieve this toggle?
EDIT:
My view hierarchy is as follows:
->UIView (toggleView)
->UIView (mainView to which toggleView is being added)
-->UIToolBar
Most likely, the view is being released when you call [self.toggleView removeFromSuperview];. I recommend that you restructure your code a little.
Since you are creating the view in IB, declare it in the header file as
IBOutlet UIView *toggleView;
Do not include the property call or the synthesize. Since you are not setting or getting the toggleView, just refer to it by the pointer.
In the implementation, set the pointer to nil in viewDidUnload and release it in dealloc. Then, adjust your toggle methods as follows:
-(void)swipedUp {
if (![toggleView superview]) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:NO];
[self.view addSubview:toggleView];
[UIView commitAnimations];
}
}
-(void)swipedDown {
if ([toggleView superview]) {
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:NO];
[toggleView removeFromSuperview];
[UIView commitAnimations];
}
}
Here, the if clause will catch the event that the user swipes up twice in a row and not respond to the second swipe. Notice also that this uses toggleView in place of self.toggleView.
This should resolve the problem.
Could you please apply such changes and tell which UIView is exactly has proble.
Open XCode/Product/Edit Scheme...
Move to Environment Variables and then click the plus to add variable
Add variable NSZombieEnables - value: YES
Add variable MallocStackLoggingNoCompact - value: 1
After starting the application, you will see, which exactly object was disposed, when you call it.
I suggest making the views you want to show/hide, be both subviews of a container view. Then, in your animation block you first remove a view that dissapears and add the view that you want to show. For example:
#interface TimeLineGrid : UIViewController {
// declare the views you want to flip between
UIView *mainView;
UIView *toggleView;
}
#property (nonatomic, retain) IBOutlet UIView *mainView;
#property (nonatomic, retain) IBOutlet UIView *toggleView;
In your implementation:
// self.view is the container view (an instance of UIView).
// Initially, self.mainView is a subview of self.view
-(void)transitionFromView:(UIView *)fromView toView:(UIView *)toView withAnimation:(UIViewAnimationTransition)animation {
if ([toView superview]) {
// toView already shown
return;
}
[UIView beginAnimations:nil context:nil];
[UIView setAnimationDuration:2.0f];
[UIView setAnimationTransition:animation forView:self.view cache:NO];
[self.view removeFromSuperview:fromView];
[self.view addSubview:toView];
[UIView commitAnimations];
}
-(void)swipedUp {
[self transitionFromView:self.mainView
toView:self.toggleView
withAnimation:UIViewAnimationTransitionFlipFromLeft];
}
-(void)swipedDown {
[self transitionFromView:self.toggleView
toView:self.mainView
withAnimation:UIViewAnimationTransitionFlipFromRight];
}
Note however, that use of the method setAnimationTransition:forView:cache: is now discouraged. Apple recommends using the UIView transitionWithView:duration:options:animations:completion: method (see the UIView reference).
I hope this helps!
I have made an application containing UITabbar and I got the same behavior but with UIButton.
That happens when you dont release the object on which you call removeFromSuperview, I have the same effect when I was removing a UIButton from my viewControllers view.
In my case I could still see the button and if I click on it, I get an exception like unrecognized selector send to object of type NSCFString.
But if I change the tab then return to my view controller where the button was showing previously after removing it from my view, then it was gone.
So my conclusion is that if you dont release the object on which your are calling removeFromSuperview then the app will show some unexpected behavior if you have the object as an instance variable of your class and added it to the view programmatically by addSubView method.
What are your options:-
You can call removeFromSuperview on a uiview or its subclass objects and call release on it or make it nil.
You can hide or unhide those objects using hidden property instead of removing them from superview.
(I haven't tried it exactly)You can create a UIView object in your class implementation and then add it as a subview and then assign it to your instance variable your class using dot operator and then release the previously created UIView object.
I dont know how my answer might help you but I think its good to share your experience with others.
Have a simple iPhone app with a single UIViewController and two Views in one xib.
the first view is very simple with a button and upon button press the second more complex view is loaded via setting the view property on the controller.
what I would like is to animate the view swap (flip the views).
The samples I have seen all require having multiple view controllers and building a hierachy, but that would be overkill in this case, any suggestions?
Make sure you declare IBOutlets for the two views in your view controller I am assuming that in your xib you have a 'container view' that occupies the whole screen, and two views of the same size that you add to this contatiner (one for each side of your 'flip'):
//Inside your .h:
IBOutlet UIView *firstView;
IBOutlet UIView *secondView;
Make sure on initial load you have the firstView show up:
-(void) viewDidLoad {
NSAssert(firstView && seconView, #"Whoops: Are first View and Second View Wired in IB?");
[self.view addSubview: firstView]; //Lets make sure that the first view is shown
[secondView removeFromSuperview]; //Lets make sure that the second View is not shown at first
}
Then you can wire up a button like this, make sure the button is wired to this metod in IB:
-(IBAction) flipButtonPressed:(id) sender {
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
if ([firstView superview]) {
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:self.view cache:YES];
[firstView removeFromSuperview];
[self.view addSubview:secondView];
}
else if ([secondView superview]) {
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.view cache:YES];
[secondView removeFromSuperview];
[self.view addSubview:firstView];
}
[UIView commitAnimations];
}