I have a series of UIViewControllers in my app, and these are presented using a UINavigationController. The HOME ViewController calls pushViewController to get to the PROFILES ViewController. The PROFILES screen correctly shows the back button to HOME. Then selecting a button on PROFILES will take the user to the DETAIL ViewController. The DETAIL screen correctly shows the back button to PROFILES. But when I press the back button to PROFILES, I do indeed go back to the PROFILES screen but the navigation bar on that screen now shows the title HOME with no back button. In other words, it appears that IOS 8 has popped the ViewController once to go back from DETAIL to PROFILES, but has somehow popped the navigation bar items twice!
Any idea how I can fix this?
Apparently the solution outline can be found here:
UINavigationController and UINavigationBarDelegate.ShouldPopItem() with MonoTouch
In my solution, I just have all my view controllers extend CustomUINavigationController, which looks like this:
#import "CustomUINavigationController.h"
#import "IOSVersion.h"
#interface CustomUINavigationController ()
#end
#implementation CustomUINavigationController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
self.delegate=self;
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
//
// The following two methods are the key to overriding the buggy behavior in IOS 8
// The first method is from here:
// https://stackoverflow.com/questions/6413595/uinavigationcontroller-and-uinavigationbardelegate-shouldpopitem-with-monotouc
//
- (BOOL)navigationBar:(UINavigationBar *)navigationBar shouldPopItem:(UINavigationItem *)item {
NSLog(#"Inside shouldPopItem");
if (regularPop) {
NSLog(#"regularPop is TRUE");
} else {
NSLog(#"regularPop is FALSE");
}
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
if (regularPop) {
regularPop = FALSE;
return YES;
}
regularPop = TRUE;
[self popViewControllerAnimated:YES];
return NO;
} else {
return [super navigationBar:navigationBar shouldPopItem:item];
}
}
- (UIViewController *)popViewControllerAnimated:(BOOL)animated
{
NSLog(#"Inside popViewControllerAnimated");
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
NSMutableArray *viewControllers = [NSMutableArray arrayWithArray:self.viewControllers];
int cnt=(int)[viewControllers count];
NSLog(#"Inside popViewControllerAnimated, cnt is %d",cnt);
UIViewController *vc=[viewControllers objectAtIndex:cnt-2];
if (regularPop) self.desiredVC=vc;
[self popToViewController:vc animated:animated];
return vc;
} else {
return [super popViewControllerAnimated:animated];
}
}
- (UIViewController *)manualpopViewControllerAnimated:(BOOL)animated {
NSLog(#"Inside manualpopViewControllerAnimated");
if (SYSTEM_VERSION_GREATER_THAN_OR_EQUAL_TO(#"8.0")) {
regularPop=TRUE;
return [self popViewControllerAnimated:animated];
} else {
return [super popViewControllerAnimated:animated];
}
}
- (void)navigationController:(UINavigationController *)navigationController
didShowViewController:(UIViewController *)viewController
animated:(BOOL)animated {
NSLog(#"Inside didShowViewController");
if (viewController==self.desiredVC) {
NSLog(#"Inside didShowViewController, found desiredVC");
regularPop = FALSE;
}
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
#end
Related
I've got a custom navigation controller declared as below. My problem is that once I implement this, the back swipe gesture to go back to previous stack (interactivepopgesturerecognizer) is not working. How can I enable it back? I've got a lot of view controller in my app. Thank You.
#import "NavController.h"
#interface NavController ()
{
BOOL shouldIgnorePushingViewControllers;
}
#end
#implementation NavController
-(instancetype)init {
self = [super init];
self.delegate=self;
return self;
}
-(void)pushViewController:(UIViewController *)viewController animated:(BOOL)animated
{
if (!shouldIgnorePushingViewControllers)
{
[super pushViewController:viewController animated:animated];
}
shouldIgnorePushingViewControllers = YES;
}
- (void)didShowViewController:(UIViewController *)viewController animated:(BOOL)animated
{
shouldIgnorePushingViewControllers = NO;
}
#end
Try to enable property
self.interactivePopGestureRecognizer.enabled = YES;
to init method
When I try to receive data from detail view controller, the master view controller is not added a new cell. I want to update the table view in master view controller based on the array in the detail view-controller. Also cancel button is not work more than one time
This is the master view controller code for save and cancel button.
(void)detailControllerSaved:(DetailViewController *)controller {
if ([self.presentedViewController isEqual:controller]) {
[self.moviesToDisplay addObject:controller.detailItem];
[self dismissViewControllerAnimated:YES
completion:nil];
// it's a modal view
} else {
// it's a navigation view
NSIndexPath *indexPath = [self.tableView indexPathForSelectedRow];
self.moviesToDisplay[indexPath.row] = controller.detailItem;
[self.navigationController popViewControllerAnimated:YES];
}
[self.tableView reloadData];
}
(void)detailControllerCanceled:(DetailViewController *)controller {
if ([self.presentedViewController isEqual:controller]) {
// it's a modal view
[self dismissViewControllerAnimated:YES
completion:nil];
} else {
// it's a navigation view
[self.navigationController popViewControllerAnimated:YES];
}
}
This is my array list
(void) loadSampleContent {
NSArray *movies = #[
[Films movieWithGenre:#"Comedy" title:#"LittleMan " date:#"2006" rate:#"7.5"],
self.moviesToDisplay = [[NSMutableArray alloc] initWithArray:movies];
}
and this is the code in the detail view controller
(void)viewWillAppear:(BOOL)animated {
if(self.detailItem) {
self.movieTitle.text = self.detailItem.movieTitle;
self.genreField.text = self.detailItem.movieGenre;
self.movieRate.text = self.detailItem.movieRate;
self.yearOfMovie.text = self.detailItem.movieDate;
}
}
(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
(IBAction)Save:(id)sender {
self.detailItem =
[Films movieWithGenre:self.genreField.text title:self.movieTitle.text date:self.yearOfMovie.text rate:self.movieRate.text];
[self.delegate detailControllerSaved:self];
}
(IBAction)cancel:(id)sender {
[self.delegate detailControllerCanceled:self];
}
I think you missed reload table after received data from Detail viewcontroller. Try add reload tableview in mastercontroller in this code:
if ([self.presentedViewController isEqual:controller]) {
[self.moviesToDisplay addObject:controller.detailItem];
[self dismissViewControllerAnimated:YES
completion:nil];
// it's a modal view
}
Hope this help!
I have an app which contains a UITabBarController. The last tab should only be entered when a condition is met. Currently I am checking this condition at the function viewDidAppear. But is it also possible to do this check every time before the tab is opened and displayed?
According to the first response I added this two files:
MainTabBarController.h
#import <UIKit/UIKit.h>
#interface MainTabBarController : UITabBarController
#end
MainTabBarController.m
#import "MainTabBarController.h"
#interface MainTabBarController ()
#end
#implementation MainTabBarController
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
// Get the new view controller using [segue destinationViewController].
// Pass the selected object to the new view controller.
}
*/
- (void)tabBarController:(UITabBarController *)theTabBarController didSelectViewController:(UIViewController *)viewController
{
NSUInteger indexOfTab = [theTabBarController.viewControllers indexOfObject:viewController];
if(indexOfTab == 2)
{
NSLog(#"Is it working?");
}
}
#end
In MainTabBarController.m file,add a delegate
#interface MainTabBarController ()<UITabBarControllerDelegate>
Then in viewDidLoad, add
self.delegate = self;
Then add a method:
- (BOOL)tabBarController:(UITabBarController *)tabBarController shouldSelectViewController: (UIViewController *)viewController
{
//add your check here
return YES;
}
is it also possible to do this check every time before the tab is
opened and displayed?
You need to override the UITabBarController delegate method for this :
- (void)tabBarController:(UITabBarController *)theTabBarController didSelectViewController:(UIViewController *)viewController {
NSUInteger indexOfTab = [theTabBarController.viewControllers indexOfObject:viewController];
if(indexofTab == yourTabIndexToMetCondition){
// Do your stuff here
}
}
I want to transition to a view I made in the main.storyboard, when they enter the password correctly.
How do I do this?
I need it to pull up the view I already created. I want a transition in the code block -(void) unlock.
Code
//
// ViewController.m
// Login
//
// Created by Ben Rosen on 5/24/14.
// Copyright (c) 2014 Ben Rosen. All rights reserved.
//
#import "ViewController.h"
#import "UnlockedScreen.h"
#interface ViewController ()
#end
#implementation ViewController
-(IBAction)login:(id)sender
{
NSString *correctUser = #"money";
NSString *correctPassword = #"ilovemoney";
if ((usernameTextField.text == correctUser)==YES && (passwordTextField.text = correctPassword)==YES)
{
[self unlock];
}
}
-(void) unlock
{
// here should be the transition
}
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
-(UIStatusBarStyle)preferredStatusBarStyle
{
return UIStatusBarStyleLightContent;
}
#end
In you storyboard, go on your first view controller, press CTRL click on the viewController and release the mouse (and CTRL) on the destination view controller.
Now choose type of segue (push if you are in a navigationController otherwise modal) and choose an identifier on the inspector for this trigger.
In your code:
-(IBAction)login:(id)sender
{
NSString *correctUser = #"money";
NSString *correctPassword = #"ilovemoney";
if ([usernameTextField.text isEqualToString:correctUser] && [passwordTextField.text isEqualToString:correctPassword])
{
[self performSegueWithIdentifier:#"name" sender:sender];
}
}
As you see i changed your if statement..your compare was wrong.
[self unlock];
remove it and write this method
[self performSegueWithIdentifier:#"profileSegue" sender:self] ;
in the storyboard name to identifier(profileSegue) on the inspector
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
if ([segue.identifier isEqualToString:#"profileSegue"]) {
ProfileViewController *profileViewController = segue.destinationViewController;
profileViewController.isFromDealView = YES;
profileViewController.hidesBottomBarWhenPushed = YES;
}
Instantiate your viewController with the identifier you have provided for your viewController.
-(void) unlock
{
// here should be the transition
UIViewController *vc = [[UIStoryboard storyboardWithName:#"storyboardname" bundle:nil] instantiateViewControllerWithIdentifier:#"viewControllersID"];
[self presentViewController:vc animated:YES completion:nil];
}
This question already has an answer here:
Navigation bar overlapped by status bar
(1 answer)
Closed 9 years ago.
Note: This problem seems to occur after modal views are dismissed.
I am subclassing my UINavigationController to make it so that it can't be rotated when on a view that contains navigation. Here is what the code looks like... very simple. I just set my UINavigationController class in Interface Builder to NavViewController:
#import "NavViewController.h"
#interface NavViewController ()
#end
#implementation NavViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// Custom initialization
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
// Do any additional setup after loading the view.
}
- (void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
// Dispose of any resources that can be recreated.
}
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return NO;
}
#end
The problem is, this is causing my top bar position to get messed up when coming back from a modal view. For example, here is what it looks like when I navigate to the view (Just FYI: the black on the top status bar is built into the background image for the Nav bar):
Then on my view controller with the Nav bar on it, I call this code to get a picture from the photo album:
- (IBAction)goToPhotoAlbum
{
UIImagePickerController *mypicker = [[UIImagePickerController alloc] init];
mypicker.delegate = self;
mypicker.allowsEditing = NO;
mypicker.wantsFullScreenLayout = YES;
mypicker.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;
[self presentViewController:mypicker animated:YES completion:nil];
}
and then I dismiss it:
- (void)imagePickerControllerDidCancel:(UIImagePickerController *)picker
{
[self dismissViewControllerAnimated:YES completion:nil];
}
When the view reappears, the Nav bar now looks like this:
When I comment out the following code from my Nav subclass, like so, everything seems to work fine again and the bar is positioned correctly:
/*
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationPortrait;
}
- (BOOL)shouldAutorotate
{
return NO;
}
*/
Anyone know what is going on here and how I can maybe fix this?
Answering my own question:
This is actually a duplicate of Navigation bar overlapped by status bar
The fix was to change my code in the subclass to this:
- (NSUInteger)supportedInterfaceOrientations
{
return UIInterfaceOrientationMaskPortrait;
}
- (BOOL)shouldAutorotate
{
return YES;
}