UIViewController Won't Unload - ios

I have been researching this question almost since I started learning to program for iOS (February 2012). I have read lots of posts on here which seem to be asking the same question and I have tried to implement the answers into my application to no avail. I am sure I am missing something simple.
I have a view switching test application. There are three views: orange, blue, yellow. It starts out on the orange view with two buttons - switch to blue view and switch to yellow view. When I click on switch to yellow view - the views revolve against a white background. The yellow view also has two buttons - switch to orange view and switch to blue view. When I click on switch to orange view the view flips back but instead of a white background the orange view is the background. How do I make that orange view not be there?
This is the code that I use to do the transition:
-(IBAction)switchToYellowView:(id)sender {
YellowViewController *myViewController = [[YellowViewController alloc]
initWithNibName:#"YellowViewController"
bundle:nil];
[UIView beginAnimations:#"flipview" context:nil];
[UIView setAnimationDuration:2];
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut];
[UIView setAnimationTransition:UIViewAnimationTransitionFlipFromLeft
forView:self.view cache:YES];
[self.view addSubview:myViewController.view];
[UIView commitAnimations];
}
From what I have read, I thought I needed to remove the orange view from the superview. But when I use
[OrangeViewController.view removeFromSuperView]
I get an error saying that "property view is not found on object OrangeViewController."
And if I switch from the yellow view to the blue view the orange view is still in the background. And then switching back to orange from blue, yellow is still in the background.
I read somewhere else, that I need to release these views also by adding
[myViewController release]
after I commit the animations. I thought that this was unnecessary when using ARC (which I am using). And when I do this, trying to go back to the orange view causes a Bad Access crash.
Perhaps I need to do something with rootViewController? I did set the OrangeView as a subview of "window" in the app delegate.m:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
// Add the view controller's view to the window and display.
[self.window addSubview:viewController2.view];
[self.window makeKeyAndVisible];
return YES;
}
viewController2 is a pointer to the OrangeViewController.
Because of the first comment, I started to look around for switching out rootViewController - and found Ken Anderson's lecture notes about switching the rootviewcontroller programatically. I can get the yellow to change in, but it isn't animating.
The next two comments are leading me in other directions - might the best thing be to use a containercontroller - like UITabBarController? Except use my own buttons and never display a tab bar?
I can, of course, provide the entire application for perusal. Thank you in advance!

Try to use:
[self transitionFromViewController:currentViewController toViewController:firstViewNav duration: options: animations:^{
} completion:^(BOOL finished){
}];

Inside switchToYellowView:, you are adding the yellow view as a subview of your current view, which is the orange view. Thus if you try to remove the orange view with [OrangeViewController.view removeFromSuperView] (which probably isn't working because view isn't a public property of OrangeViewController), then you would be removing the orange view which has the yellow view as a subview, effectively removing both from the window. I think what you want to do inside switchToYellowView is something like this:
[self.view removeFromSuperview]; //remove the orange view
[window addSubview:myViewController.view]; //replace it with the yellow view

Related

Autolayout - Compressing UINavigationController at the same time as pushing a new view controller

I am working on an iOS app. The root view controller contains a UINavigationController which wraps up the main contents of the app, and a footerViewController (audio player) that will compress the main content when it animates up into view.
I’m using auto layout to show and hide this footer like so:
_footerVisibleConstraints = [… #“V:|[navControllerView][footerView(==90)]|" …];
_footerHiddenConstraints = [… #“V:|[navControllerView][footerView(==0)]|" …];
Generally this works well. But I’m struggling with one issue. I have a situation where I need to push a new view on the UINavigationController stack and animate my footer into view the same time:
[self.view layoutIfNeeded];
[UIView animateWithDuration:1.5f animations:^{
[[self view] removeConstraints:_footerHiddenConstraints];
[[self view] addConstraints:_footVisibleConstraints];
[[self view] layoutIfNeeded];
}];
[navigationController pushViewController:newViewController animated:YES];
The problem in this situation is that newViewController is animating in snapped to it's final (compressed) state, and not beginning from the full starting height of the view. So there is a gap at the bottom while the footer animates in.
I’ve slowed down the animation and posted a video here to demonstrate what I am describing.
Also, notice how when I pop back to the root view controller the content in the UINavigationController isn’t compressed either.
So, can someone explain to me what’s going on here? Is there a way to accomplish what I am after?
Just add a variable to the .h of your VC to stipulate whether the footer needs to open or not. Then add the footer animation to the didAppear method with a check on the variable. This will result in performing the actions in the order you want them to happen.
If you want both animations to happen at the same time you will need to subclass a segue and add a custom animation.

Methods gets called when app goes to the background

my app consists of a table view controller and a view controller. when i press a cell in the table view, the toolbar at that view slips with animation down outside the screen and when i'm in the view controller and press back, the toolbar bar slips upwards to it's original position. My problem is, i figured out a bug that when i'm in the view controller and press the home button to exit the app and then come back. the app resumes where i left but when i go back to the table view, the toolbar shifts upwards beyond it's original position. the sliding of the toolbar works fine when i'm in the app before exiting. so there's like something is being called to reset the toolbar to it's origin and thus adding the additional y-axis point to shift more upwards. does anybody know what are those methods?
Code:
i have this in the viewWillAppear method of the view controller:
[UIView animateWithDuration:0.7 animations:^{
self.navigationController.toolbar.center = CGPointMake(self.navigationController.toolbar.center.x, self.navigationController.toolbar.center.y + self.navigationController.toolbar.frame.size.height);
} completion:^(BOOL finished){
self.navigationController.toolbar.hidden = YES;
}];
and in the same view when it needs to disappear i added this in the viewWillDisappear:
[[self.navigationController toolbar] setHidden:NO];
[UIView animateWithDuration:1 animations:^{
self.navigationController.toolbar.center = CGPointMake(self.navigationController.toolbar.center.x, self.navigationController.toolbar.center.y - self.navigationController.toolbar.frame.size.height);
} completion:^(BOOL finished){
}];
i tried this as another way to animate the hiding of the toolbar but there is no animation:
- (void) viewWillAppear:(BOOL)animated
{
[self.picker setHidden:YES];
[self.navigationController setToolbarHidden:YES animated:YES];
}
- (void) viewWillDisappear:(BOOL)animated
{
[self.navigationController setToolbarHidden:NO animated:YES];
[self.course setValue:self.nameTextField.text forKey:#"courseName"];
[self.course setValue:[NSNumber numberWithInt:[self.creditsTextfield.text integerValue]] forKey:#"courseCredits"];
[self.course setValue:[NSNumber numberWithInt:[self.chaptersTextfield.text integerValue]] forKey:#"courseChapters"];
[self.course setValue:self.gradeTextfield.text forKey:#"courseGrade"];
}
For one thing, you should use frame instead of center, but replace the viewWillDisappear animation line with this:
self.navigationController.toolbar.frame = CGRectMake(0,0,self.navigationController.toolbar.frame.size.width, self.navigationController.toolbar.frame.size.height);
and tell me what happens...
That should fix your problem.
Since you are using the toolbar belonging to a UINavigationController (and not a standalone UIToolbar instantiated and added to a UIView by your own controller), it's better to use the methods that UINavigationController exposes, because you don't know how it manages and move its UIToolbar.
Try to put just this in viewWillAppear:, instead of the entire animation block
[self.navigationController setToolbarHidden:NO animated:YES];
and this in viewWillDisappear:
[self.navigationController setToolbarHidden:YES animated:YES];
i fixed it! i aded the following lines of code in viewWillDisappear:
self.navigationController.toolbar.center = CGPointMake(self.navigationController.toolbar.center.x, 458);
self.navigationController.toolbar.center = CGPointMake(self.navigationController.toolbar.center.x, self.navigationController.toolbar.center.y + self.navigationController.toolbar.frame.size.height);
since the problem seems that when the app goes background then foreground the toolbar resets to it's original position and thus after navigating back to the table view the toolbar is shifted beyond it's original position. therefore the first line i added resets the toolbar to it's original position while still hidden then shift it down. after that the block of animation is done. i did this so that the animation works on the following cases:
1. the user enters the detail view from the table view then goes back to the tableview without exiting the app.
2. the user enters the detail view from the tableview then exits the app and then resume the app and goes back to the table view.

Slide the whole screen of your app that uses UITabbarController as rootcontroller

I'm using a tabbarcontroller in my app with several viewcontrollers inside it, just normal standard stuff. Lately I need to add the ability to slide the whole screen when I click a button from my content view.
This is what my appdelegate does:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window.root = self.tabBarController; //tabBarController is IBOutlet to the tabbar
}
And in one of my viewcontroller I do this:
- (IBAction)filterButtonTapped:(id)sender {
[UIView animateWithDuration:0.2 delay:0.0f options:UIViewAnimationOptionCurveEaseInOut | UIViewAnimationOptionBeginFromCurrentState animations:^{
//slide everything to the right?
self.navigationController.view = CGAffineTransformMakeTranslation(260.0f, 0.0f);
} completion:^(BOOL finished) {
//do something, possibly show the view that comes up from the left
}];
You might ask why does the button needs to be inside the contentview, well because my apps want to be designed that way I guess?
Now, the content of the tab bar does slide but not the tab bar below, I know it's because the self.navigationController.view is for the contentview inside the tab bar.
I've been trying to find a way to slide/animate the whole thing but from inside the contentview is it possible to get to the root?
What's your suggestion to do this?
You can access your tab bar controller view from any VC inside using
self.tabBarController.view
Then just animate that view.

How to hide custom tab bar button when hidesBottomBarWhenPushed is "TRUE"

I am using the code snippet from Tito to add a custom button to my tab bar:
https://github.com/tciuro/CustomTabBar
(Subclassing UITabbarController and adding a custom button using
// .. created a UIButton *button
[self.view addSubview:button];
)
This works great with my storyboard-based app except for the case of a subview within a navigation controller with the option "Hides bottom bar on push" enabled.
This hides the tab bar as promised, but not the custom button.
Seems like the button should be added as a subview to the tab bar itself?
I tried this ugly code which did not even make the button show up:
for(UIView *view in self.view.subviews)
{
if([view isKindOfClass:[UITabBar class]])
{
[view addSubview:button];
break;
}
}
Any ideas?
UPDATE:
My solution:
In my ApplicationDelegate i define the following methods, which i call whenever needed in the viewWillAppear or viewWillDisappear methods:
-(void)hideCenterButton:(BOOL)animated
{
if(animated){
[UIView animateWithDuration:0.3
delay:0.0f
options:UIViewAnimationCurveLinear
animations:^{
CGRect frame = self.centerButton.frame;
frame.origin.x = -100;
self.centerButton.frame = frame;
}
completion:^(BOOL finished){
}];
}
}
-(void)showCenterButton:(BOOL)animated
{
if(animated){
[UIView animateWithDuration:0.35
delay:0.0f
options:UIViewAnimationCurveLinear
animations:^{
CGRect frame = self.centerButton.frame;
frame.origin.x = (self.view.superview.frame.size.width / 2) - (self.centerButton.frame.size.width / 2);
self.centerButton.frame = frame;
}
completion:^(BOOL finished){
}];
}
}
I had to set the animation's duration to 0.35s to get a smooth effect in harmony with the tab bar.
Why don't you make button your tabbar's part.
tabBarController.tabBar.addSubView(yourButton)
everything would be solve. cheers!
One easy way to handle this would be to create an instance of the button in .h of your file.
UIButton *customTabButton;
When calling the hides bottom bar on push set the button property to hidden and reset it again in the other views if the bottom bar is visible.
shareFbButton.hidden=YES;
You can check this is the viewDidLoad of all the files and put this line of code if needed to make sure you are displaying the button and hiding the button on all the pages you need.
if(self.tabBarController.tabBar.isHidden){
// set or reset the custom button visibility here
}
This is one way.
I think there are 2 ways you can got with this.
1) try to get the button into a view that is above the old top view controller and the tab bar BUT below the new top view controller that is pushed.
2) animate away the button when the new view controller is pushed.
The first will require mucking with the iOS proprietary view hierarchy which is undocumented, unsupported and could change anytime.
The second will be a matter of making the animation appear smooth enough for your user not to notice. It's not entirely a matter of behaving perfect, just appearing appropriately.
I would personally recommend an animation of the the button disappearing (animate it's alpha to 0) and reappearing based on if your view controller that goes over the tab bar is appearing or disappearing.
The animation for a navigation is (I believe) 0.3 seconds. If the button is in the middle of the tab bar, you'll likely want it invisible as the animating in view controller reaches it (if not sooner) so something between 0.1 and 0.15 seconds could be used to animate it out.
Now this does not make the button behave exactly the same as the tab bar, but with the quickness of the transition being so short, it will be unnoticeable really to the user.
Now just to provide a question for you to ask yourself. Why do you need to push a view controller that overlaps the tab bar? Why is that more desirable/necessary than presenting a modal view controller? If you can strongly argue for it, keep at it and good luck, if it's not necessary however, you may be able to achieve the experience you want with a modal view controller.
Check this one to put a button on the UITabBar. See if it works after with hidesBottoBarWhenPushed.

iOS transitioning views using animation blocks

I am trying to animate between 2 subviews. At the moment I've tried different options, each with their own side effects.
The application is a small game with a skills subview, an inventory subview, and a status subview. I want to animate between the skills and the inventory views while leaving the status subview on the bottom of the main view. Below I've listed my various attempts and the side effects from them.
Animate from `animateWithDuration
[UIView animateWithDuration:0.3 delay:0.3 options:UIViewAnimationOptionTransitionFlipFromRight | UIViewAnimationCurveEaseIn animations:^{
skillView.hidden = NO;
inventoryView.hidden = YES;
}completion:NULL];
No transitions seems to take place. The views just pop in.
Animate from transitionFromView
[UIView transitionFromView:inventoryView toView:skillView duration:0.5 options:UIViewAnimationOptionTransitionFlipFromRight completion:^(BOOL finished){
inventoryView.hidden = YES;
}];
The transition is done perfectly, but the status view transitions with the other views. Almost as if the main view is animating with everything.
The views are loaded into the main view just hidden in the background and they used to just pop into the main window. However, I would like to animate between the views to have a better application flow. I've seen people remove and add to the main view, but I'm hoping that setting the subviews to be visible/invisible should have the same effect.
Any advice is greatly appreciated.
Core Animation doesn't know how to animate those views apart from their direct ancestor (parent).
Break them into a single container view.
Eg:
Instad of this:
Parent
- Other View
- View A
- View B
- Other View
Have this:
Parent
- Other View
- Container
- View A
- View B
- Other View
See comments to question for more detail.

Resources