I am having a problem to display a View. When a button is pressed in current view, following action is exected:
- (IBAction) vistaUser: (id)sender{
loginTabController *theInstance = [[loginTabController alloc] init];
[theInstance logIn:user.text :password.text];
}
then, following logIn function is called who have to show userViewControler view but it is not showed. View remains at current one. However, userViewController view is initialized and getData function from this view executed! I do not understand why called view is not displayed! Thanks for help!
- (void)logIn: (NSString *)strUser: (NSString *)strPass
{
[UIView beginAnimations:#"View Flip" context:nil];
[UIView setAnimationDuration:1.0];
[UIView setAnimationCurve: UIViewAnimationCurveEaseInOut];
if (self.controladorUser == nil)
{
userViewController *aController = [[userViewController alloc] initWithNibName:#"userViewController" bundle:nil];
self.controladorUser = aController;
[aController release];
}
[UIView setAnimationTransition: UIViewAnimationOptionCurveEaseIn forView:self.view cache:YES];
[self.controladorPass viewWillDisappear:YES];
[self.controladorUser viewWillAppear:YES];
[self.controladorPass.view removeFromSuperview];
[self.view insertSubview:controladorUser.view atIndex:0];
[self.controladorPass viewDidDisappear:YES];
[self.controladorUser viewDidAppear:YES];
[UIView commitAnimations];
//getData call
userViewController *theInstance = [[userViewController alloc] init];
[theInstance getData:strUser :strPass];
}
You are never showing your loginTabController's view. Therefore when you add the UserViewController's view to the tabViewController's view it doesn't do anything. Try this:
- (IBAction) vistaUser: (id)sender{
loginTabController *theInstance = [[loginTabController alloc] init];
[self.view addSubview:theInstance.view];
[theInstance logIn:user.text :password.text];
}
That should get it working, but there are some general code design issues that you may want to address:
Use the newer block animation functions in UIView instead of the older and more difficult "beginAnimations" "commitAnimations" methods.
It does not make sense to call a viewController that immediately calls another viewController. Skip the loginTabController and just go straight to the userViewController. If for some reason you want to keep the code the loginTabController is using as a separate class that's fine just don't use a viewController subclass for it.
Related
I have ViewController which is loaded from a .nib file. in the viewDidLoad method I create a subview and add it to the view hierarchy. How do I fade out that subview to show the view in .nib file?
(the subview is like a splash screen, which I want to fade out to show the view in the .nib, it's set up this way since it was easiest way for me.)
Here is some of my code (I tried to set a reference to the original view from the nib in the viewDidLoad but couldn't get it to work):
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"View did load");
//set reference to view in .nib here
UIView *currentView = self.view;
CGRect frame = [[UIScreen mainScreen] bounds];
splashView = [[splashView alloc] initWithFrame:frame];
[[self view] addSubview:splashView];
//transition did not work
[UIView transitionFromView:splashView toView:currentView duration:0.25 options:UIViewAnimationOptionTransitionCrossDissolve completion:^(BOOL finished) {
NSLog(#"transition finished");
}];
}
That code crashes. What am I doing wrong?
Try the following in place of your original code:
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"View did load");
CGRect frame = [[UIScreen mainScreen] bounds];
splashView = [[splashView alloc] initWithFrame:frame];
[[self view] addSubview:splashView];
[self.view bringSubviewToFront: splashView];
[UIView animateWithDuration: 2.0
delyay: 0.5 // omit if you don't need a delay
options: UIViewAnimationCurveEaseOut // check the documentation for other options
animations: ^{
splashView.alpha = 0;
}
completion: ^(BOOL finished) {
[splashView removeFromSuperView];
}];
I don't know if you're using ARC or not, or if you using storyboards or not!
If you're note using ARC, then memory management is wrong in this snippet.
How to achieve fade effect when going from one viewController to other using navigation Controller
normally we do to push :
DetailViewController *obj= [[DetailViewController alloc]initWithNibName:#"DetailView" bundle:nil];
[self.navigationController pushViewController:obj animated:YES];
and to pop :
UINavigationController *navController = self.navigationController;
// retain ourselves so that the controller will still exist once it's popped off
[[self retain] autorelease];
// Pop this controller and replace with another
[navController popViewControllerAnimated:YES];
But I want fading effect when I do pop or push .. plz suggest
this is not the exact code you want but you can get the way how to do the animation you want
First have to pass the parameter NO for any animation while push and pop view and have to give some custom animation like this
// Flash the screen white and fade it out to give UI feedback that a still image was taken
UIView *flashView = [[UIView alloc] initWithFrame:[[self videoPreviewView] frame]];
[flashView setBackgroundColor:[UIColor whiteColor]];
[[[self view] window] addSubview:flashView];
[UIView animateWithDuration:.4f
animations:^{
[flashView setAlpha:0.f];
}
completion:^(BOOL finished){
[flashView removeFromSuperview];
}
];
For more detail answer and use the block in proper way see this answer on other question on SO
Some of the code from that answer is as follow
For Push:
MainView *nextView = [[MainView alloc] init];
[UIView animateWithDuration:0.75
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[super pushViewController:nextView animated:NO];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromRight forView:self.navigationController.view cache:NO];
}];
For Pop:
[UIView animateWithDuration:0.75
animations:^{
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:transition forView:self.navigationController.view cache:NO];
}];
[self.navigationController popViewControllerAnimated:NO];
Thanks to #ijordan
Some other tips for the problem is here
This one is one excellent example for your use no use to do extra coding with this as it provides category for animation of navigation controller.
I rewrote The iOSDev's solution (thanks!) in Swift 5+ (without deprecation warnings etc.):
Push:
UIView.transition(with: navigationController.view, duration: 0.5, options: [.transitionCrossDissolve], animations: {
self.navigationController.pushViewController(viewControllerToBeShown, animated: false)
}) { _ in
completion()
}
Pop:
UIView.transition(with: navigationController.view, duration: 0.5, options: [.transitionCrossDissolve], animations: {
self.navigationController.popViewController(animated: false)
}) { _ in
completion()
}
I try to make an animation with an image in my view but it doesn't work: my image is at the final position without animation.
UIImage *myImg = [UIImage imageNamed : #"Img72.png"];
UIImageView *myImgView =[ [UIImageView alloc] initWithImage: myImg ];
myImgView.frame= CGRectMake(250,50,72,72);
[self.view addSubview:myImgView];
[UIView animateWithDuration:0.5
delay: 0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
[UIView setAnimationRepeatCount:100.0];
[UIView setAnimationRepeatAutoreverses:YES];
myImgView.frame= CGRectMake(50,250,72,72);
}
completion:NULL];
[myImgView release];
The same animation code work perfectly in another view. I finally find that it's come from the way I display the view with this code:
FlipsideViewController *controller = [[[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil] autorelease];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal; //KO
[self presentModalViewController:controller animated:YES];
The problem is the modalTransitionStyle. When I comment the line (with //KO) it finally works. I test the other transition style and all the other works (UIModalTransitionStyleCoverVertical, UIModalTransitionStyleCrossDissolve, UIModalTransitionStylePartialCurl)
I made an viewDidLoadProject (Utility App) and just add the animation code in the two view in viewDidLoad method.
Where is the problem? Is it an Apple bug? How can I have a flip transition AND my animation working in the second view?
Here is my example project: http://dl.dropbox.com/u/9204589/testFlipAnimation.zip
That seems more natural to start to play with the interface when all the system stuff is done, didAppear must be used for that purpose i believe (yes, it works :))
FlipsideViewController.m
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)viewDidAppear:(BOOL)animated
{
UIImage *myImg = [UIImage imageNamed : #"Img72.png"];
UIImageView *myImgView =[ [UIImageView alloc] initWithImage: myImg ];
myImgView.frame= CGRectMake(250,50,72,72);
[self.view addSubview:myImgView];
[UIView animateWithDuration:0.5
delay: 0.0
options: UIViewAnimationOptionCurveEaseInOut
animations:^{
[UIView setAnimationRepeatCount:100.0];
[UIView setAnimationRepeatAutoreverses:YES];
myImgView.frame= CGRectMake(50,250,72,72);
}
completion:NULL];
[myImgView release];
[super viewDidAppear:animated];
}
I have a view controller that displays the views of 2 sub view controllers in a given area of its view. The 2 sub view controllers are FlopVC and FipVC.
I want to animate the transition from one sub view to the other. The code I'm using is:
-(IBAction)flip:(id)sender{
UIViewController *newVC = nil;
if (self.isFlip) {
newVC = [[FlopVC alloc] initWithNibName:nil bundle:nil];
}else{
newVC = [[FipVC alloc] initWithNibName:nil bundle:nil];
}
newVC.view.frame = CGRectMake(120, 20, 240, 260);
[self.view addSubview:newVC.view];
[UIView transitionFromView:self.currentVC.view
toView:newVC.view
duration:0.9
options:UIViewAnimationTransitionFlipFromLeft
completion:^(BOOL finished) {
self.currentVC = newVC;
self.isFlip = ! self.isFlip;
}];
}
The sub views are swapped, but without any animation. What am I doing wrong?
PS the full project is here.
UIViewAnimationTransitionFlipFromLeft != UIViewAnimationOptionTransitionFlipFromLeft
if you are using the new iOS5 view container paradigm you need to do something along the lines of the following:
-(IBAction)flip:(id)sender{
UIViewController *newVC = nil;
if (self.isFlip) {
newVC = [[FlopVC alloc] initWithNibName:nil bundle:nil];
}else{
newVC = [[FipVC alloc] initWithNibName:nil bundle:nil];
}
newVC.view.frame = CGRectMake(120, 20, 240, 260);
// required for the new viewController container
self.currentVC willMoveToParentViewController:nil];
[self addChildViewController:newVC];
[self transitionFromViewController:self.currentVC
toViewViewController:newVC.view
duration:0.9
options: UIViewAnimationOptionTransitionFlipFromLeft
animations:nil
completion:^(BOOL finished) {
// required for the new viewController container
[self.currentVC removeFromParentViewController];
[newVC didMoveToParentViewController:self];
self.currentVC=newVC;
}];
}
reference the section Implementing a Container View Controller and the 2011 WWDC videos on UIViewController containers for more info.
Here is working code that (by sheer coincidence) does exactly what you're describing. My two child vc's are stored in self->swappers. The integer cur keeps track of which one is currently showing. The spot in my interface where the subview is to go is marked by a view outlet, panel.
UIViewController* fromvc = [self->swappers objectAtIndex:cur];
cur = (cur == 0) ? 1 : 0;
UIViewController* tovc = [self->swappers objectAtIndex:cur];
tovc.view.frame = self.panel.bounds;
// must have both as children before we can transition between them
[self addChildViewController:tovc]; // "will" called for us
// note: when we call remove, we must call "will" (with nil) beforehand
[fromvc willMoveToParentViewController:nil];
[self transitionFromViewController:fromvc
toViewController:tovc
duration:0.4
options:UIViewAnimationOptionTransitionFlipFromLeft
animations:nil
completion:^(BOOL done){
// note: when we call add, we must call "did" afterwards
[tovc didMoveToParentViewController:self];
[fromvc removeFromParentViewController]; // "did" called for us
}];
I got this error from XCode:
objc[8422]: FREED(id): message release sent to freed object=0x3b120c0
I googled and find that is related to the memory. But I don't know which line of code I go wrong, any ideas? After I launch my app in simulator, it prompts a second, than, no other error except the error above.
#implementation MyAppDelegate
#synthesize window;
#synthesize viewController;
- (void)applicationDidFinishLaunching:(UIApplication *)application {
// Override point for customization after app launch
[window addSubview:viewController.view];
[window makeKeyAndVisible];
[self changeScene:[MainGameMenuScene class]];
}
- (void)dealloc {
[viewController release];
[window release];
[super dealloc];
}
- (void) changeScene: (Class) scene
{
BOOL animateTransition = true;
if(animateTransition){
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:window cache:YES]; //does nothing without this line.
}
if( viewController.view != nil ) {
[viewController.view removeFromSuperview]; //remove view from window's subviews.
[viewController.view release]; //release gamestate
}
viewController.view = [[scene alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self];
//now set our view as visible
[window addSubview:viewController.view];
[window makeKeyAndVisible];
if(animateTransition){
[UIView commitAnimations];
}
}
[viewController.view release]; //release gamestate
That's an extra release (if you didn't alloc it, don't release it). A couple lines down:
viewController.view = [[scene alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self];
will release viewController.view again before retaining the new value, that will over-release the view and cause a crash (it sends the release message to an object that has already been dealloc'd / memory that has already been freed). Instead, try:
scene *view = [[scene alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self];
viewController.view = view; // setView will release the old/retain the new
[view release]; // so you don't need to worry about releasing it later
Got the solution:
- (void) changeScene: (Class) scene
{
BOOL animateTransition = true;
if(animateTransition){
[UIView beginAnimations:nil context:NULL];
[UIView setAnimationDuration:0.5];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft forView:window cache:YES]; //does nothing without this line.
}
if( viewController.view != nil ) {
[viewController.view retain]; //retain the view.
[viewController.view removeFromSuperview]; //remove view from window's subviews.
[viewController.view release]; //release gamestate
}
viewController.view = [[scene alloc] initWithFrame:CGRectMake(0, 0, IPHONE_WIDTH, IPHONE_HEIGHT) andManager:self];
//now set our view as visible
[window addSubview:viewController.view];
[window makeKeyAndVisible];
if(animateTransition){
[UIView commitAnimations];
}
}
It needs me to retain the view, but I don't know why this is necessary.
This line:
[viewController.view release];
Is most likely your problem. Never send release to a property of an object except in the class' dealloc method. The view controllers view property accessors will handle retaining and releasing for you.