Switch Between 2 UIViewControllers in a NavigationBar Underneath - objective-c

I have built a UIViewController to contain two other UIViewControllers. What I would like to do using a UISegment in the UINavigationBar is to switch between both views. When the user is finished they click on "Done" and it goes back to the RootViewController. I got this to work except the UIViewControllers take the size of the whole screen so the top portion is covered by the UINavigationBar. They don't adjust to the space under the UINavigationBar. I have been trying different techniques without success.
I have already tried in the ChildUIViewControllers without success
self.edgesForExtendedLayout = UIRectEdgeNone;
Here is my code:
RootViewController Calls the Container
ContainerController *controller = [[ContainerController alloc] init]
[self.navigationController pushViewController:controller animated:YES];
Container Code
- (void)viewDidLoad {
[super viewDidLoad];
UIViewController *vc = [self getCurrentViewController]; // Returns Current ViewController to Display
[self addChildViewController:vc];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
self.currentViewController = vc;
}
-(UIViewController *)getCurrentViewController{
UIViewController *vc;
switch ([[NSUserDefaults standardUserDefaults] integerForKey:#"currentView"]) {
case kView1:{
vc = (ViewController1 *)[[ViewController1 alloc] init];
}break;
case kView2:{
vc = (ViewController2 *)[[ViewController2 alloc] init];
}break;
}
return vc;
}
- (void)segmentedControlIndexChanged:(id)sender{
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithInt:[sender selectedSegmentIndex]] forKey:#"currentView"];
[userDefaults synchronize];
UIViewController *vc = [self getCurrentViewController];
[self addChildViewController:vc];
[self transitionFromViewController:self.currentViewController toViewController:vc duration:0.5 options:UIViewAnimationOptionTransitionCrossDissolve animations:^{
[self.currentViewController.view removeFromSuperview];
vc.view.frame = self.view.bounds;
[self.view addSubview:vc.view];
} completion:^(BOOL finished) {
[vc didMoveToParentViewController:self];
[self.currentViewController removeFromParentViewController];
self.currentViewController = vc;
}];
self.navigationItem.title = vc.title;
}
Anybody know what the problem is? Thanks.

I found a solution. The reason that the tableview was under the navigationbar was due to the translucence of the navigation bar. When I set this:
self.navigationController.navigationBar.translucent = NO;
The views remained under the navigation bar. There was still a black bar above the UITableView I fixed that problem by instead of using a UITableViewController I user a UIViewController and added a tableView. Here is some code to make cycle between the two views in the container uiviewcontroller:
- (void)viewDidLoad {
self.viewController1 = [[ViewController1 alloc] init];
self.viewController2= [[ViewController2 alloc] init];
switch ([[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"]) {
case kDataView:{
self.viewController1.view.hidden=YES;
self.viewController2.view.hidden=NO;
}break;
case kChartView:{
self.viewController1.view.hidden=NO;
self.viewController2.view.hidden=YES;
}break;
}
[self.view addSubview:self.viewController1.view];
[self.view addSubview:self.viewController2.view];
}
- (void)segmentedControlIndexChanged:(id)sender{
if ([[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"]!=[sender selectedSegmentIndex]){
NSUserDefaults *userDefaults = [NSUserDefaults standardUserDefaults];
[userDefaults setObject:[NSNumber numberWithInteger:[sender selectedSegmentIndex]] forKey:#"dataView"];
[userDefaults synchronize];
self.segmentedControl.selectedSegmentIndex=[[NSUserDefaults standardUserDefaults] integerForKey:#"dataView"];
switch (self.segmentedControl.selectedSegmentIndex) {
case kDataView:{
self.viewController1.view.hidden=YES;
self.viewController2.view.hidden=NO;
}break;
case kChartView:{
self.viewController1.view.hidden=NO;
self.viewController2.view.hidden=YES;
}break;
}
}
}

Related

How to update previous view label with NSUserDefault value in iOS, objective c

I have two views in my app.in first view there is a label and I want to update it's value in my second view controller(this shows as a popup view). and after second view controller dismissed, the changed value should be in the label(as lebel.text). I used NSUserDefault.
in my second view controller I assign value like this :
- (IBAction)updatetheDatepicker:(id)sender
{
NSDate *flightDeparturedate = self.flightDepartureDatepicker.date;
NSDateFormatter *flightdepatureFormatter = [[NSDateFormatter alloc] init];
[flightdepatureFormatter setDateFormat:#"d/MM/y"];
NSString *flightDeparturedateDisplay = [flightdepatureFormatter stringFromDate:flightDeparturedate];
NSLog(#"selected departure date :%#", flightDeparturedateDisplay);
[[NSUserDefaults standardUserDefaults] setObject:flightDeparturedateDisplay forKey:#"flightDepartureDate"];
[[NSUserDefaults standardUserDefaults] synchronize];
}
and in my firstviewcontroller when second view dismiss, I want to update the label in my first view.how can I do that.
self.depdate.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"];
NOTE: second view appears as a UIPopoverpresentationController
this is how I popup my second view controller from first view controller
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
NSString *identifier = segue.identifier;
if([identifier isEqualToString:#"popover"])
{
UIViewController *destinationController = segue.destinationViewController;
UIPopoverPresentationController *popController = destinationController.popoverPresentationController;
if(popController)
{
popController.delegate = self;
}
}
if([identifier isEqualToString:#"popoverone"])
{
UIViewController *destinationController = segue.destinationViewController;
UIPopoverPresentationController *popController = destinationController.popoverPresentationController;
if(popController)
{
popController.delegate = self;
}
}
}
- (UIModalPresentationStyle)adaptivePresentationStyleForPresentationController:(UIPresentationController *)controller
{
return UIModalPresentationNone;;
}
hope your help with this.
NOTE : Here i did not use any segue. i initiated view controller
FirstViewController.h
#interface FirstViewController : UIViewController<UIPopoverPresentationControllerDelegate>
#property(nonatomic,strong)IBOutlet UILabel *depdate;
#end
FirstViewController.m
-(void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
[self updateDateLable];
}
- (IBAction)btnClicked:(id)sender
{
//[self performSegueWithIdentifier:#"openDatePicker" sender:self];
UIButton *btnInfo=(UIButton *)sender;
DatePickerPopUpViewController* popOverFileProperty = [[self storyboard] instantiateViewControllerWithIdentifier:#"DatePickerPopUpViewController"];
popOverFileProperty.modalPresentationStyle = UIModalPresentationPopover;
popOverFileProperty.popoverPresentationController.sourceView = btnInfo;
popOverFileProperty.popoverPresentationController.delegate=self;
[self presentViewController:popOverFileProperty animated:YES completion:nil];
}
-(void)updateDateLable
{
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"] != nil) {
self.depdate.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"];
}
else
{
//date is not set yet , set other text as you wish
self.depdate.text=#"Date not selected";
}
}
// Called on the delegate when the user has taken action to dismiss the popover. This is not called when the popover is dimissed programatically.
- (void)popoverPresentationControllerDidDismissPopover:(UIPopoverPresentationController *)popoverPresentationController
{
[self updateDateLable];
}
If you want to use Segue :
- (IBAction)btnClicked:(id)sender
{
[self performSegueWithIdentifier:#"openDatePicker" sender:self];
}
-(void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender
{
if ([segue.identifier isEqualToString:#"openDatePicker"])
{
DatePickerPopUpViewController* popOverFileProperty = [segue destinationViewController];
popOverFileProperty.modalPresentationStyle = UIModalPresentationPopover;
popOverFileProperty.popoverPresentationController.delegate=self;
}
}
Try to call your update value here from NSUserDefaults.
-(void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
if ([[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"] != nil||![[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"]] isEqualToString:#"(null)"]||![[NSString stringWithFormat:#"%#",[[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"]] isEqualToString:#""]) {
self.lbl.text = [[NSUserDefaults standardUserDefaults] objectForKey:#"flightDepartureDate"];
}
else
self.lbl.text=#"NO Date..";
}

iOS 7 Tab bar icons temporarily disappear when on More tab

When I add a view controller embedded by navigation controller, to a tab bar, its icon + title disappear briefly when coming back to the More tab.
However when the view controller is added as such, the icon+image are okay and don't disappear.
I've tried many things already, and am out of options. Any ideas?
Here's my AppDelegate code:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.tabBarController = [[UITabBarController alloc] init];
// Must be placed here, just before tabs are added. Otherwise navigation bar
// will overlap with status bar.
[[UIApplication sharedApplication] setStatusBarHidden:NO withAnimation:UIStatusBarAnimationSlide];
[self addViewControllersToTabBar];
self.window.rootViewController = self.tabBarController;
self.window.backgroundColor = [UIColor whiteColor];
[self.window makeKeyAndVisible];
return YES;
}
- (void)addViewControllersToTabBar
{
NSArray* tabBarClassNames =
#[
NSStringFromClass([FirstViewController class]),
NSStringFromClass([SecondViewController class]),
NSStringFromClass([FirstViewController class]),
NSStringFromClass([FirstViewController class]),
NSStringFromClass([FirstViewController class]),
NSStringFromClass([SecondViewController class]),
NSStringFromClass([FirstViewController class]),
];
NSMutableArray* viewControllers = [NSMutableArray array];
for (NSString* className in tabBarClassNames)
{
UIViewController* viewController = [[NSClassFromString(className) alloc] init];
UINavigationController* navigationController;
navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[viewControllers addObject:navigationController];
}
[viewControllers addObject:[[FirstViewController alloc] init]]; // This one is fine.
self.tabBarController.viewControllers = viewControllers;
self.tabBarController.selectedViewController = viewControllers[2];
}
and the view controllers are literally nothing more than:
#implementation SecondViewController
- (instancetype)init
{
if (self = [super init])
{
self.title = #"second";
self.tabBarItem.image = [UIImage imageNamed:#"second.png"];
}
return self;
}
#end
Holy shit, spent so much time on this bug, but here's my workaround. Instead of:
navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
I created my own NavigationController as subclass of UINavigationController:
#implementation NavigationController
- (instancetype)initWithRootViewController:(UIViewController*)rootViewController
{
if (self = [super initWithRootViewController:rootViewController])
{
NSString* className = NSStringFromClass([rootViewController class]);
NSString* name = [className stringByReplacingOccurrencesOfString:#"ViewController" withString:#""];
self.tabBarItem.image = [UIImage imageNamed:[NSString stringWithFormat:#"%#Tab.png", name]];
}
return self;
}
#end
and then do:
navigationController = [[NavigationController alloc] initWithRootViewController:viewController];
Prerequisite is that tab images have the same base name as the view controller class name, which was already the case in my app.
I was setting self.tabBarItem.image inside the view controllers' init method, and this seems to cause the effect I was seeing. So in addition to using my own navigation controller, I also simply deleted setting the tabBarItem in each individual view controller.

UIButton not working in second time (objective-C)

I have a button in my first screen for loading a small game here is the code:
- (IBAction)playButtonPressed:(id)sender
{
[self startGameWithConfig:[RootViewController singleplayerGameConfig]];
NSLog(#"play again");
}
and inside of my game page I have a button to back to the first screen when I used this button I can back but my playButtonPressed not working any more, it print the NSLog but
the button it's not loading the game any more
here is my return button:
- (IBAction)return:(id)sender {
RootViewController *b = [[RootViewController alloc] init];
[self presentModalViewController:b animated:YES];
}
would you please help me to this implementation
Thanks in advance!
and here is my startGamingWithConfig
- (void) startGameWithConfig:(GameConfig *)config
{
// fade in the loading screen to hide load time
[_loadingView setHidden:NO];
[_loadingView setAlpha:0.0f];
[UIView animateWithDuration:0.2f
delay:0.0f
options:UIViewAnimationOptionCurveLinear
animations:^{
[_loadingView setAlpha:0.0f];
}
completion:^(BOOL finished){
CardsViewCtrl* newController = [[CardsViewCtrl alloc] init];
newController.gameConfig = config;
AppDelegate *delegate = (AppDelegate *)[[UIApplication
sharedApplication] delegate];
[delegate.navController pushFadeInViewController:newController
animated:YES];
}];
}
It is a bit hard for me to understand where this code is since there are no headings but it looks like when you are attempting to go back to the RootViewController you are creating a new one and pushing that on the stack. You want to make sure that your topViewController is removed, not adding more views.
So for a starter try to replace return method:
- (IBAction)return:(id)sender {
RootViewController *b = [[RootViewController alloc] init];
[self presentModalViewController:b animated:YES];
}
with this:
- (IBAction)goBack:(id)sender {
[self dismissModalViewController];
}
I am not sure how you have your view hierarchy setup, but if you have a working navigationController than try using [self.navigationController popNavigationController:YES];

Add custom UIButton to UIKeyboard's accessory view for a UIWebView

I need to add a camera button to a UIWebView's keyboard accessory view toolbar (the one that already has the "Back|Next" and "Done" buttons).
Is there an easy way to do this?
I'm still looking for a better way to do it, but one solution for the moment would be to destroy the bar and recreate it like so :
- (void)viewDidLoad
{
[super viewDidLoad];
UIWebView *web = [[UIWebView alloc] initWithFrame:CGRectMake(0, 0, 320, 480)];
NSURL *aURL = [NSURL URLWithString:#"http://www.google.com"];
NSURLRequest *aRequest = [NSURLRequest requestWithURL:aURL];
[web loadRequest:aRequest];
[self.view addSubview:web];
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(keyboardWillShow:) name:UIKeyboardWillShowNotification object:nil];
}
- (void)keyboardWillShow:(NSNotification *)notification {
[self performSelector:#selector(removeBar) withObject:nil afterDelay:0];
}
- (void)removeBar {
UIWindow *keyboardWindow = nil;
for (UIWindow *testWindow in [[UIApplication sharedApplication] windows]) {
if (![[testWindow class] isEqual:[UIWindow class]]) {
keyboardWindow = testWindow;
break;
}
}
for (UIView *possibleFormView in [keyboardWindow subviews]) {
// iOS 5 sticks the UIWebFormView inside a UIPeripheralHostView.
if ([[possibleFormView description] rangeOfString:#"UIPeripheralHostView"].location != NSNotFound) {
for (UIView *subviewWhichIsPossibleFormView in [possibleFormView subviews]) {
if ([[subviewWhichIsPossibleFormView description] rangeOfString:#"UIWebFormAccessory"].location != NSNotFound) {
UISegmentedControl *nav = [[UISegmentedControl alloc] initWithItems:[NSArray arrayWithObjects:#"Previous",#"Next", nil]];
nav.momentary = YES;
nav.frame = CGRectMake(5, 8, 120, 30);
nav.segmentedControlStyle = UISegmentedControlStyleBar;
nav.tintColor = [UIColor colorWithWhite:0.25 alpha:1];
[nav addTarget:self action:#selector(navigate) forControlEvents:UIControlEventValueChanged];
UIBarButtonItem *pictureBtn =[[UIBarButtonItem alloc] initWithTitle:#"Picture" style:UIBarButtonItemStyleBordered target:self action:#selector(takePic:)];
UIBarButtonItem *flexButton = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemFlexibleSpace target:self action:nil];
UIBarButtonItem *doneButton =[[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyboard)];
NSArray *buttons = [NSArray arrayWithObjects:flexButton,pictureBtn,flexButton,doneButton, nil];
[(UIToolbar *)subviewWhichIsPossibleFormView addSubview:nav];
[(UIToolbar *)subviewWhichIsPossibleFormView setItems:buttons];
}
}
}
}
}
But then, you have to implement the previous, next and done function again. But it's not the hardest part.
there is an easier way to do this.
Keep your keyboard notification in your viewDidLoad
After that all you will need is the following method:
-(void)keyboardDidShow:(NSNotification*)notif
{
NSArray *array = [[UIApplication sharedApplication] windows];
for (UIWindow* wind in array) {
for (UIView* currView in wind.subviews) {
if ([[currView description] hasPrefix:#"<UIPeripheralHostView"]) {
for (UIView* perView in currView.subviews) {
if ([[perView description] hasPrefix:#"<UIWebFormAccessory"]) {
UIBarButtonItem *doneBttn = [[UIBarButtonItem alloc] initWithBarButtonSystemItem:UIBarButtonSystemItemDone target:self action:#selector(resignKeyBoard)];
NSMutableArray *arr = [[NSMutableArray alloc] initWithArray: [(UIToolbar *) perView items]];
[arr addObject:doneBttn];
[(UIToolbar *) perView setItems:arr];
}
}
}
}
}
}
I have basically taken the original prev/next buttons from the UIWebFormAccessory and added a done button to the end of it, but you can add what ever buttons you want to this.
Some may think this shouldn't be implemented in -(void)keyboardDidShow: because you are changing the UI after it displays on screen, but so far I haven't noticed any issues with this. (only tested in simulator)
Hope this was useful!

Load a .nib at first app launch

I want to show the "intro" nib i made only at first app launch.
I was using the following code in my viewDidLoad but it seems to do nothing (even in ViewWillAppear). I tried to clean, remove the app from simulator and device and build again but nothing happened.
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"]){
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:nil bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES];
[intro release];
[defaults setObject:[NSDate date] forKey:#"firstRun"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
I also tried to show a little UIAlertView at first launch, and it works! Am i failing to load the nib?
EDIT
I forgot to say it's a tab Bar based app and i've some code in my app delegate to highlight rows at the first three sessions of the app.
Any help appreciated!
Ok, add the following code and it should work:
- (void)Loadview_afterdelay{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"firstRun"]){
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:nil bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES];
[intro release];
[defaults setObject:[NSDate date] forKey:#"firstRun"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
- (void)viewDidLoad {
[self performSelector:#selector(Loadview_afterdelay) withObject:nil afterDelay:0.5];
}
Apparently, in this case, you can't load a second view right after your view is loaded (viewdidload)
Therefor you just set a small delay before loading your second view.
Try the following:
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:#"IntroViewController" bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES];
[intro release];
I have added your .nib name to initWithNibName
Also, if you're using iOS 5 (and ARC), you should use this:
IntroViewController *intro = [[IntroViewController alloc] initWithNibName:#"IntroViewController" bundle:nil];
intro.modalTransitionStyle = UIModalTransitionStyleCoverVertical ;
[self presentModalViewController:intro animated:YES completion:nil];
Have you tried moving it to viewDidAppear?
It looks to me that you should place that code in your AppDelegate
- (BOOL)application:(UIApplication *)application
didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// Override point for customization after application launch.
// Modify the code above to what you need.
self.window.rootViewController = self.viewController;
[self.window makeKeyAndVisible];
[application setStatusBarHidden:YES withAnimation:NO];
return YES;
}
It is there that your telling your application what view to start with.
So first time have a firstTimeViewController.
If you are doing it here don't animate the transition in.
Just animate the transition off.
Put a break point and check if you are going into the viewDidLoad method and if so check if your test is appropriate.
I suggest maybe using a BOOL in an NSNumber to check agains.
On top of that you may consider the option to put that in viewDidAppear.
As #Louis already answered the question very well already the only thing is It's just not compatible with the ARC since there are a [ release] What I'll write now isn't new but I'll declare it more for the beginner ones.
First you have to import the TourGuideViewController.h in your RootViewController.h which will be like similarly like this:
#import <UIKit/UIKit.h>
#import "TourGuideViewController.h"
#interface RootViewController : UITabBarController
{
TourGuideViewController *TourGuideViewController;
}
#property (nonatomic, strong) TourGuideViewController *TourGuideViewController;
#end
Then You have to synthesize and implement your function in your RootViewController.m file:
#import "RootViewController.h"
#interface RootViewController ()
#end
#implementation RootViewController
#synthesize TourGuideViewController = _TourGuideViewController;
- (void)viewDidLoad
{
[self performSelector:#selector(LoadTourGuide) withObject:nil afterDelay:0.5];
}
- (void)LoadTourGuide{
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
if (![defaults objectForKey:#"FirstRun"]){
TourGuideViewController *TourGuideVC = [self.storyboard instantiateViewControllerWithIdentifier:#"TourGuideViewController"];
TourGuideVC.modalTransitionStyle = UIModalTransitionStyleCrossDissolve;
[self presentViewController:TourGuideVC animated:YES completion:NULL];
[defaults setObject:[NSDate date] forKey:#"FirstRun"];
}
[[NSUserDefaults standardUserDefaults] synchronize];
}
#end