I have a UIView named scoreView on ViewController. When I load the ViewController I hide the scoreView in the viewDidLoad method. It works fine.
- (void)viewDidLoad{
[super viewDidLoad];
self.navigationController.navigationBarHidden = YES;
scoreView.hidden = YES;
}
Then after being pushed from another view controller to this ViewController, I call a method, where I want to show the scoreView. But the scorView is still being hidden. Where is the mistake I am doing?
-(void)levelCompleteViewAppear: (NSString *)score{
NSLog(#"This method is called!");
scoreView.hidden = NO ;
[gameScore setText:score];
}
This is how I am pushing to the ViewController from anothe view controller.
-(void)levelComplete{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle: nil];
ViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"ViewController"];
[self.navigationController pushViewController:vc animated:YES];
[vc levelCompleteViewAppear:scoreLabel.text];
}
Try This,
-(void)viewDidLoad
{
[super viewDidLoad];
[self.view addSubview:scrollview];
[self.view bringSubviewToFront:scrollview];
}
When you are pushing the viewController to navigationController, it will not call viewDidLoad directly. If you want to make it visible, write it down in viewWillAppear or vieDidAppear method.
- (void) viewWillAppear{
scoreView.hidden = YES;
}
add this in your code
If first time ViewController class in opeining then ViewDidLoad will call but if you are coming back from some other ViewController then ViewDidLoad wont get call for that you need to show your View in ViewWillAppear Or ViewDidAppear.
Suppose you called Class A then ViewDidLoad will get call then again you moved class B then class B viewDidLoad will get call but if you are coming back again to class A then your viewDidLoad wont get call, it will call ViewWillAppear and viewDidAppear.
Hope it may clear you more.
-(void)viewWillApper:(BOOL)animated{
scoreView.hidden = NO ;
}
Related
I've got a problem with hidesBarOnSwipe property of UINavigationController.
Overview :
Link to project file
I have one controller named FirstViewController which is root view of UINavigationController.
Everything is in Main.storyboard.
FirstViewController contains UIButton action. Inside that action I instantiate a SecondViewController and push it on a navigation stack.
- (IBAction)button:(id)sender {
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"SecondViewController"];
[self.navigationController pushViewController:vc animated:YES];
}
Inside SecondViewController there is only an hidesBarsOnSwipe property set to YES on viewDidLoad :
- (void)viewDidLoad {
[super viewDidLoad];
self.navigationController.hidesBarsOnSwipe = YES;
}
and dealloc gets NSLogged :
- (void)dealloc {
NSLog(#"Dealloc");
}
Problem :
When we swipe up to hide navigationBar, dealloc is never get called. Instruments shows a SecondViewController memory leak here.
When we are on SecondViewController and we just press back button - everything is fine. Dealloc gets called.
There is definitly some kind of retain cycle but i have no idea why and how to avoid this kind of situation.
Some updates and temporary solution :
There is another method to perform navigationBar hiding.
What worked for me is to use :
[self.navigationController setNavigationBarHidden:hidden animated:YES];
To achieve good results add a property in your class to keep track status of navigationBar animation :
#property (assign, nonatomic) BOOL statusBarAnimationInProgress;
Implement UIScrollViewDelegate like this :
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat yVelocity = [scrollView.panGestureRecognizer velocityInView:scrollView].y;
if (yVelocity > 0 && !self.statusBarAnimationInProgress) {
[self setNavigationBarHidden:NO];
} else if (yVelocity < 0 && !self.statusBarAnimationInProgress) {
[self setNavigationBarHidden:YES];
}
}
Set navigation bar hidden should look like :
- (void)setNavigationBarHidden:(BOOL)hidden {
[CATransaction begin];
self.statusBarAnimationInProgress = YES;
[CATransaction setCompletionBlock:^{
self.statusBarAnimationInProgress = NO;
}];
[self.navigationController setNavigationBarHidden:hidden animated:YES];
[CATransaction commit];
}
I use CATransaction to check if animation of navigation bar is completed. Any way that works. Not so easy solution but at least there is no leak :)
I'm playing around with view life cycles & am having trouble changing a view from the load of a different view.
In my ViewController.h i have:
-(void)viewDidAppear:(BOOL)animated{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
}
However this only causes the view to be between ViewController, and ViewController2 appearing with animation (in a loop).
I used the code in viewDidLoad however neither of the view's loaded (from reading you cannot change view until the viewWillAppear)
Update: When using the code in viewWillAppear, whose view is not in the window hierarchy error is thrown.
How does one change the view from view setup stage?
Update
Using the above code, inside & out of GCD, in viewDidLoad, viewWillAppear & viewDidAppear either results in an infinite loop of animated showing of the ViewController2, or crash on 2nd attempt of segue (result from the loop).
EDITED:
I'm not sure exactly what you're trying to do, but assuming you are wanting the first viewcontroller to appear and then the second viewcontroller to immediately animate on top of the first one, you should be able to accomplish using several options:
First you could just wrap your calls in a dispatch_async call:
dispatch_async(dispatch_get_main_queue(), ^{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:nil];
ViewController2 *viewController = (ViewController2 *)[storyboard
instantiateViewControllerWithIdentifier:#"ViewController2"];
[self presentViewController:viewController animated:YES completion:nil];
});
Or you could use a show modally segue:
- (void)viewDidLoad {
[super viewDidLoad];
dispatch_async(dispatch_get_main_queue(), ^{
[self performSegueWithIdentifier:#"myModalSegue" sender:self];
});
}
Or you could use a navigation controller and use a standard show segue (formally push). This one doesn't require the dispatch_async:
- (void)viewDidLoad {
[super viewDidLoad];
[self performSegueWithIdentifier:#"myshowsegue" sender:self];
}
I've posted working examples of all three on: github
It is better to exchange views in loadView method.
- (void)loadView {
CGRect rect = [[UIScreen mainScreen] applicationFrame];
MyView *view = [[MyView alloc] initWithFrame:rect];
[view setAutoresizingMask:UIViewAutoresizingFlexibleHeight | UIViewAutoresizingFlexibleWidth];
self.view = view;
}
On View1 I hide the navigationBar in viewDidLoad:
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
Then I navigate to View2 where I show the navigationBar
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:NO];
self.title = #"Title";
}
But on back to View1 again, the navigationBar doesn't hide, even if I did tried to hide it after the pushViewController in View2
[self.navigationController pushViewController:View1 animated:YES];
[self.navigationController setNavigationBarHidden:YES];
I also tried to hide the navigation from viewWillAppear in View1 and it hides it, but there is an ugly delay and I don't find it as a good practice.
So can anyone help me with this issue, how can I hide correctly the navigationBar on back to View1?
The best practice to do what you want is putting bellow in your first viewController:
- (void)viewWillAppear:(BOOL)animated{
[self.navigationController setNavigationBarHidden:YES animated:animated];
[super viewWillAppear:animated];
}
- (void)viewWillDisappear:(BOOL)animated{
[self.navigationController setNavigationBarHidden:NO animated:animated];
[super viewWillDisappear:animated];
}
-(void) viewDidAppear:(BOOL)animated {
[super viewDidAppear:animated];
[self.navigationController setNavigationBarHidden:YES];
}
The ViewController1 is not going to get allocated again and so viewDidLoad is not going to get called.
You can do it in viewWillAppear though. But if you are saying that there is a delay, you can do one more thing.
You can get the reference ofViewController1 in ViewController2. Suppose ViewController1 is the first controller in the navigation controller, then do this:
//ViewController2.m
- (IBAction)backButtonPressed:(id)sender{
ViewController1 *view1 = [self.navigationController.viewControllers objectAtIndex:0];
[view1.navigationController setNavigationBarHidden:YES];
Your code is correct, but you need to write like this:
[self.navigationController setNavigationBarHidden:YES];
first, then write
[self.navigationController pushViewController:View1 animated:YES];
See when you are pushing View2 from View2 in navigation stack than View1 doesn't gets deallocated. it is there in in the stack. So when you popping out View2 that time View1 viewDidLoad won't get called. so your code setNavigationBarHidden to hide navigation bar doesn't executes. So put that code to ViewWillAppear or ViewDidAppear because these methods gets called every time View appears.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
[self.navigationController setNavigationBarHidden:YES];
}
I'm confused. I have a navigation controller with a BarItem which opens a first view. After some work is done, I want this view to disappear and I want a second view to open.
root view: navigation controller
first view: activity indicator, where some data is put together
second view: MFMailComposeViewController
In the root view, the BarItem runs these lines to open the first view:
IndicatorViewController *indicator = [[IndicatorViewController alloc] initWithNibName:#"IndicatorViewController" bundle:nil];
indicator.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:indicator animated:YES];
The first view (IndicatorViewController) does some work and finally runs
[self dismissModalViewControllerAnimated:YES];
This works fine. But - how do I open the second view?
I tried this:
I open the second view. After closing the second view, my first view pops up again (since it is still there) and get's dismissed at this point. This code is placed in the first view:
- (void) viewDidAppear:(BOOL)animated {
static BOOL firstTime = YES;
if (firstTime) {
//do stuff that takes some time (that's why I show the indicator)
MailViewController *controller = [[MailViewController alloc] init];
if (controller)
[self presentModalViewController:controller animated:YES];
firstTime = NO;
} else {
[self dismissModalViewControllerAnimated:YES];
}
}
Since the first view pops up again, the user can see the indicator one more time, after the second view is closed - and that is not what I want.
What am I missing here? What would be the better way to do this?
I would do something like this. Make a navigationController, and make the first view as the root controller. Then do something like this:
FirstView.m
- (void)viewDidLoad
{
[super viewDidLoad];
[self.navigationController setNavigationBarHidden:YES];
}
- (void) nextView { // however you get to your next view, button/action/etc.
UIViewController *screen = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
[self.navigationController pushViewController:screen animated:YES];
}
Then in the second view:
SecondView.m
- (void) nextView { // however you get to your next view, button/action/etc.
UIViewController *screen = [self.storyboard instantiateViewControllerWithIdentifier:#"yourIdentifier"];
[self.navigationController pushViewController:screen animated:YES];
}
And finally in the rootview:
RootView.m
- (void)viewDidLoad
{
[super viewDidLoad];
NSArray *navStack = [NSArray arrayWithObject:self];
self.navigationController.viewControllers = navStack;
[self.navigationController setNavigationBarHidden:NO];
}
This will make your RootView the new rootview of the NavigationController.
self.navigationController.viewControllers
is the array with all the ViewControllers that are on the navcontrollers stack. The first object is the rootcontroller. If we replace the whole array with our own array, it knows only one item. You CAN go back by dismissing if that's what you want though. This isn't the prettiest way of doing it, but it's not the worst either.
I'm using a UIStoryBoard to allow the FirstViewController to add the view of second ViewController as a subview. On removing the sub view using the following method
FirstViewController.m
- (IBAction) btnMoveTo:(id)sender
{
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"MainStoryboard" bundle:nil];
UIViewController *vc = [storyboard instantiateViewControllerWithIdentifier:#"Second"];
vc.view.backgroundColor = [UIColor clearColor];
self.modalPresentationStyle = UIModalPresentationCurrentContext;
[self presentModalViewController:vc animated:NO];
}
SecondViewController.m
-(void)viewDidLoad{
self.view.opaque = YES;
self.view.backgroundColor = [UIColor clearColor];
}
- (IBAction) withDraw:(id)sender{
[self.view removeWithZoomOutAnimation:2 option:nil];
}
When I access the withDraw Function, the view of the SecondViewController is removed and firstViewController is back. However when I use the button to access the - (IBAction) btnMoveTo:(id)sender function. It doesn't work. Nothing really happens. Any suggestions or help would be greatly appreciated.
You are confusing views with view controllers. View controllers are objects that control views, so for the first line you wrote,
I'm using a UIStoryBoard to allow the FirstViewController to add the view of second ViewController as a subview. On removing the sub view using the following method
you cant add a view controller as a subview of another view controller. You present a view controller that manages its own views, and you can add UIViews as subviews of a UIViewController. A UIViewController manages UIViews.
The problem you are having with the code you posted, is that when you trigger the withDraw: function, you are removing the view of the view controller. Not the view controller itself. You need to dismiss the SecondViewController to gain access of the FirstViewController again.