I have a Add View where when you tap on Category, the following code is executed
- (void)categoryTapped {
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
[self presentViewController:categoryGroupViewController animated:YES completion:nil];
}
CategoryGroupViewController.h looks like
#interface CategoryGroupViewController : UIViewController<UITableViewDataSource, UITableViewDelegate>
#property (nonatomic, strong) UINavigationController *navigationController;
#property (strong, nonatomic) IBOutlet UITableView *tableView;
#end
CategoryGroupViewController.m looks like
#import "CategoryGroupViewController.h"
#import "Helper.h"
static NSString *CellIdentifier = #"Cell";
#interface CategoryGroupViewController ()
#property(nonatomic, strong) NSArray *categories;
#end
#implementation CategoryGroupViewController
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil {
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
// (todo) should come from API
self.categories = #[#"Food & Drink", #"Utilities"];
}
[self.tableView registerClass:[UITableViewCell class] forCellReuseIdentifier:CellIdentifier];
return self;
}
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"categoryGroup View loaded");
self.navigationController = [[UINavigationController alloc] initWithRootViewController:self];
self.navigationController.title = #"Pick Category";
}
...
}
When I run my application, I see the following in log
2014-11-20 21:29:53.589 myapp-ios[30332:70b] categoryGroup View loaded
But on Simulator, I see
Why don't I see NavigationController?
As you are presenting your CategoryGroupViewController it will not show Navigation Bar by default.
You have to set your CategoryGroupViewController as rootViewController for UINavigationController and instead of presenting CategoryGroupViewController present newly created UINavigationController.
- (void)categoryTapped{
CategoryGroupViewController *categoryGroupVC = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController: categoryGroupVC];
[self presentViewController:categoryGroupViewController animated:YES completion:nil];
}
as i mentioned above if u want a navigaioncontroller u can set CategoryGroupViewController as a root view for a navigation controller and present it for example,
- (void)categoryTapped
{
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
//add this
UINavigationController *navController = [[UINavigationController alloc]initWithRootViewController: categoryGroupViewController];
//present the navigation controller which contains root view controller categoryGroupViewController
[self presentViewController:navController animated:YES completion:nil];
}
You need to instantiate a rootViewController before View did load
[alink]https://developer.apple.com/library/ios/featuredarticles/ViewControllerPGforiPhoneOS/ViewLoadingandUnloading/ViewLoadingandUnloading.html
UIViewController already as a navigationController property, so this is redundant:
// Remove this property from CategoryGroupViewController
#property (nonatomic, strong) UINavigationController *navigationController;
Structuring the user interface in the way you are attempting is also incorrect, and would result in a circular reference between CategoryGroupViewController and UINavigationController. First you need to modify your -viewDidLoad method like so:
- (void)viewDidLoad {
[super viewDidLoad];
// Do any additional setup after loading the view from its nib.
NSLog(#"categoryGroup View loaded");
// UINavigationController will use this automatically.
self.title = #"Pick Category";
}
Then you should change the way you go about preseting the view controller in your original method:
- (void)categoryTapped {
CategoryGroupViewController *categoryGroupViewController = [[CategoryGroupViewController alloc] initWithNibName:#"CategoryGroupViewController" bundle:nil];
UINavigationController *navController = [[UINavigationController alloc] initWithRootViewController:categoryGroupViewController];
[self presentViewController:navController animated:YES completion:nil];
}
Finally, the introduction in the UINavigationController documentation has a great explanation of how the class should be used. Taking a few minutes to read it would help you tremendously in the future.
Related
I have a view controller which is my HomeViewController, and I have a modal segue between them.
This is the HomeViewController:
import "HomePageViewController.h"
#import "CreatePageViewController.h"
#import "StackTableViewController.h"
#import "PopUpView.h"
#interface HomePageViewController ()
#property (nonatomic, strong) IBOutlet UIButton *toggleButton;
#property (nonatomic, strong) CreatePageViewController *modalTest;
#property (nonatomic, strong) PopUpView *popup;
#end
#implementation HomePageViewController
-(UIStatusBarStyle)preferredStatusBarStyle{
return UIStatusBarStyleLightContent;
}
-(void)viewDidLoad {
[super viewDidLoad];
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:#"Main" bundle:Nil];
_modalTest = [storyboard instantiateViewControllerWithIdentifier:#"ModalTest"];
[_toggleButton addTarget:self action:#selector(go) forControlEvents:UIControlEventTouchUpInside];
[[NSNotificationCenter defaultCenter]addObserver:self selector:#selector(hide) name:#"HideAFPopup" object:nil];
}
-(void)go {
_popup = [PopUpView popupWithView:_modalTest.view];
[_popup show];
}
-(void)hide {
[_popup hide];
}
- (IBAction)pushToNextViewController:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc]init];
[self presentModalViewController:vc animated:YES];
}
-(void)didReceiveMemoryWarning {
[super didReceiveMemoryWarning];
}
#end
I want to add a navigation controller to StackTableViewController...its just a table view and I want it to have a navigation controller, how should I do this?
Also, why xcode tells me my modal method presentModalViewController is deprecated?
tnx
Create a new instance of UINavigationController, with your StackTableViewController as its rootViewController. Then present the navigation controller:
- (IBAction)pushToNextViewController:(id)sender {
StackTableViewController *vc = [[StackTableViewController alloc]init];
UINavigationController *navCtrl = [[UINavigationController alloc] initWithRootViewController:vc];
[self presentViewController:navCtrl animated:YES completion:nil];
}
Note that presentModalViewController:animated: is deprecated because it has been replaced by presentViewController:animated:completion:.
I've followed several guides on passing data between view controllers, but they seem to involve setting the secondViewController's property in any equivalent of a -(void)goToNextView method. I'm trying to figure out how to assign a value to a property in a 2nd view controller from the first while using a tab bar controller created in the app delegate.
Current setup:
AppDelegate.m
#synthesize window;
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
...
UITabBarController *tbc = [[UITabBarController alloc] init];
FirstViewController *vc1 = [[FirstViewController alloc] init];
SecondViewController *vc2 = [[SecondViewController alloc] init];
[tbc setViewControllers: [NSArray arrayWithObjects: vc1, vc2, nil]];
[[self window] setRootViewController:tbc];
[self.window makeKeyAndVisible];
return YES;
}
...
#end
FirstViewController.h
#import "SecondViewController.h"
#interface FirstViewController : UIViewController
{
SecondViewController *vc2;
IBOutlet UISlider *sizeSlider;
}
#property (nonatomic, retain) SecondViewController *vc2;
#property (strong, nonatomic) UISlider *mySlider;
-(IBAction) mySliderAction:(id)sender;
#end
FirstViewController.m
#import "FirstViewController.h"
#import "SecondViewController.h"
#implementation FirstViewController
#synthesize vc2, mySlider;
- (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil
{
self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
if (self) {
UITabBarItem *tbi = [self tabBarItem];
[tbi setTitle:#"xib"];
}
return self;
}
...
- (IBAction) mySliderAction:(id)sender
{
NSString *str = [[NSString alloc] initWithFormat:#"%3.2f", mySlider.value];
if(self.vc2 == nil)
{
SecondViewController *viewTwo = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
self.vc2 = viewTwo;
}
vc2.sliderValueString = str;
}
...
#end
SecondViewController.h
#import <UIKit/UIKit.h>
#import "myView.h"
#interface SecondViewController : UIViewController
{
NSString *sliderValueString;
}
#property (copy) NSString *sliderValueString;
#end
SecondViewController.m
#import "SecondViewController.h"
#implementation SecondViewController
#synthesize sliderValueString;
- (id)initWithNibName:(NSString *)nibName bundle:(NSBundle *)bundle
{
self = [super initWithNibName:nil bundle:nil];
if (self) {
UITabBarItem *tbi = [self tabBarItem];
[tbi setTitle:#"View 2"];
}
return self;
}
-(void) loadView
{
CGRect frame = [[UIScreen mainScreen] bounds];
myView *view = [[myView alloc] initWithFrame:frame];
printf("Slider Value: %s", [sliderValueString UTF8String]);
[self setView: view];
}
...
#end
myView.h and .m are likely irrelevant to the question, but I've got the .h subclassing UIView, and the .m creating the view with -(id)initWithFrame:(CGRect)frame
I'm guessing that I'm assigning the 2nd VC's property in the wrong place (mySliderAction), given that the printf() in the 2nd VC is blank, so my question is: Where should the property be assigned, or what am I doing wrong that is preventing the 2nd VC from allowing it's sliderValueString to not be (or remain) assigned?
Thanks!
You are fine setting the property in mySliderAction, the trouble is that you are setting it on the wrong object.
In the App Delegate you create a viewController for tabControllers' item 2:
SecondViewController *vc2 = [[SecondViewController alloc] init];
In vc1's mySliderAction you also create an instance of vc2:
SecondViewController *viewTwo = [[SecondViewController alloc] initWithNibName:nil bundle:nil];
This is not the instance that you navigate to via the second tab on the tabController, but it is the one who's sliderValueString property you are setting.
Instead of making a new instance here, you need to refer to the already-existing instance:
SecondViewController *viewTwo = [self.tabBarController.viewControllers objectAtIndex:1]
Then you should be ok.
NavigationController.h
#import <UIKit/UIKit.h>
#protocol NavigationControllerDelegate;
#interface NavigationController : UINavigationController<UINavigationControllerDelegate>
#property (nonatomic , assign)id<NavigationControllerDelegate , UINavigationControllerDelegate> delegate;
-(void)cancelImagePicker:(id)sender;
#end
#protocol NavigationControllerDelegate <NSObject>
- (void)mediaPickerController:(NavigationController *)picker didFinishPickingMediaWithInfo:(NSDictionary *)info;
- (void)mediaPickerControllerDidCancel:(NavigationController *)picker;
#end
NavigationController.m
#import "NavigationController.h"
#import "DataViewController.h"
#interface NavigationController ()
#end
#implementation NavigationController
#synthesize delegate;
-(id)init{
UIViewController *controller = [[DataViewController alloc]initWithNibName:#"DataViewController" bundle:nil];
self = [super initWithRootViewController:controller];
if (self) {
self.navigationBar.topItem.title = #"Data Table";
self.navigationBar.tintColor = [UIColor clearColor];
UIBarButtonItem *rightButton = [[UIBarButtonItem alloc] initWithTitle:#"Cancel"
style:UIBarButtonSystemItemCancel target:self action:#selector(cancelImagePicker:)];
self.navigationBar.topItem.rightBarButtonItem = rightButton;
}
return self;
}
-(void)cancelImagePicker:(id)sender{
[delegate mediaPickerControllerDidCancel:self];
}
#end
DataViewController.m
.....
-(void)tableView:(UITableView *)tableView accessoryButtonTappedForRowWithIndexPath:(NSIndexPath *)indexPath{
secondViewController *secondController = [[secondViewController alloc]initWithNibName:#"secondViewController" bundle:nil ];
[self.navigationController pushViewController: secondController animated:YES];
}
.......
I want to add a "cancel" button on secondViewController's navigation bar which performs the action -(void)cancelImagePicker:(id)sender; from NavigationController.m. And the same for pushed third, fourth and fifthViewController. How can this be achieved? Do i have to write code in each viewController or Can i write in common?
I have presented the NavigationController from MainViewController on buttonClick as
- (IBAction)navView:(id)sender {
NavigationController * controller = [[NavigationController alloc]init];
controller.delegate = self;
[self presentViewController:controller animated:YES completion:nil];
}
and implemented the delegation methods there.
You can use notification center instead of delegates, the idea is,
[NSNotificationCenter DefaultCenter] addObserver]
i search for a way to have multiple detail view in iPad application and i find the sample code in apple developer site http://developer.apple.com/library/ios/#samplecode/MultipleDetailViews/Introduction/Intro.html , but now i want to have navigation in detail view which this sample does not cover, i add uinavigationcontroller to detail view as :
-(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
ReportsViewController_iPad *master = [[ReportsViewController_iPad alloc] initWithNibName:#"ReportsViewController_iPad" bundle:nil];
DetailViewController_iPad *detail = [[DetailViewController_iPad alloc] initWithNibName:#"DetailViewController_iPad" bundle:nil];
UINavigationController *masterNavController = [[[UINavigationController alloc] initWithRootViewController:master ] autorelease];
UINavigationController *detailNavController = [[[UINavigationController alloc] initWithRootViewController:detail ] autorelease];
splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavController , detailNavController, nil];
[window addSubview:splitViewController.view];
[window makeKeyAndVisible];
return YES;
}
but when i run the sample i got error
[UINavigationController showRootPopoverButtonItem:]: unrecognized selector sent to instance...
showRootPopoverButtonItem is a method define in a protocol in RootViewController
#protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
---- ReportsViewController.h
#protocol SubstitutableDetailViewController
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem;
#end
#protocol DetailViewControllerManagerDelegate
-(void) didSelectRowAtIndexPathPopOver:(NSString *)ID;
#end
#interface ReportsViewController_iPad : ReportsViewController<UISplitViewControllerDelegate , DetailViewControllerManagerDelegate>
{
UISplitViewController *splitViewController;
UIPopoverController *popoverController;
UIBarButtonItem *rootPopoverButtonItem;
}
#property (nonatomic, assign) IBOutlet UISplitViewController *splitViewController;
#property (nonatomic, retain) UIPopoverController *popoverController;
#property (nonatomic, retain) UIBarButtonItem *rootPopoverButtonItem;
#property(nonatomic, retain) id<DetailViewControllerManagerDelegate> delegate;
-(void)didSelectRowAtIndexPath:(NSString*)ID;
#end
--DetailViewController.h
#import <UIKit/UIKit.h>
#import "ReportsViewController_iPad.h"
#interface DetailViewController_iPad : UIViewController<SubstitutableDetailViewController>
{
UIToolbar *toolbar;
}
#property (nonatomic, retain) IBOutlet UIToolbar *toolbar;
#end
--DetailViewController.m
#import "DetailViewController_iPad.h"
#implementation DetailViewController_iPad
#synthesize toolbar;
#pragma mark - View lifecycle
- (void)viewDidLoad
{
[super viewDidLoad];
}
- (void)viewDidUnload
{
[super viewDidUnload];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
#pragma mark -
#pragma mark Managing the popover
- (void)showRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Add the popover button to the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray insertObject:barButtonItem atIndex:0];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
- (void)invalidateRootPopoverButtonItem:(UIBarButtonItem *)barButtonItem {
// Remove the popover button from the toolbar.
NSMutableArray *itemsArray = [toolbar.items mutableCopy];
[itemsArray removeObject:barButtonItem];
[toolbar setItems:itemsArray animated:NO];
[itemsArray release];
}
- (void)dealloc {
[toolbar release];
[super dealloc];
}
#end
So Thanks in advance.
Where definition of method showRootPopoverButtonItem is present, seems like this is not defined. You need to define it.
If you want to avoid crash then you can use -
if ([aViewController respondsToSelector:#selector(showRootPopoverButtonItem:)]) {
[aViewController performSelector:#selector(showRootPopoverButtonItem:) withObject:self.rootPopoverButtonItem];
}
EDIT -
I have checked this and found what you are doing wrong , for e.g. code in willHideViewController-
UIViewController <SubstitutableDetailViewController> *detailViewController = [splitViewController.viewControllers objectAtIndex:1];
this is expecting a view controller, while you are passing navigation controller which in turn has view controller(similar at some other position), so you need to alter these codes as well if you want to pass navigation controller from app delegate.
I need to call a method in the viewcontroller that creates a popupviewcontroller, from the created popupviewcontroller.
For iPad I create it like this:
if (!self.flipsidePopoverController) {
FlipsideViewController *controller = [[[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil] autorelease];
controller.delegate = self;
self.flipsidePopoverController = [[[UIPopoverController alloc] initWithContentViewController:controller] autorelease];
}
if ([self.flipsidePopoverController isPopoverVisible]) {
[self.flipsidePopoverController dismissPopoverAnimated:YES];
}
else
{
/// The important part ///
[self.flipsidePopoverController presentPopoverFromRect:CGRectMake((self.view.frame.size.width-320), 0, (self.view.frame.size.width), 10) inView:self.view permittedArrowDirections:UIPopoverArrowDirectionUp animated:YES];
}
Now I wish to call a method in my main view controller from within the popup. How can I achieve that?
My iPhone equivalent is this:
// Creating it //
FlipsideViewController *controller = [[[FlipsideViewController alloc] initWithNibName:#"FlipsideViewController" bundle:nil] autorelease];
controller.delegate = self;
controller.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:controller animated:YES];
Calling a method from within the popup:
if ([self.presentingViewController isKindOfClass:[MainViewController class]])
[(MainViewController*)self.presentingViewController resetClock];
Give the displayed view controller a reference to your main view controller. Eg:
#class MainViewController;
#interface FlipsideViewController : UIViewController
{
}
#property (nonatomic, assign) MainViewController *mainController;
#end
(Don't forget the #synthesize in the implementation!)
Later when you present the popover, just set the property:
[controller setMainController:self];
.h
#import <UIKit/UIKit>
#import AppDelegate.h"
#interface FlipsideViewController : UIViewController
{
}
#property (nonatomic, assign) MainViewController *mainController;
#end
.m
#import "FlipsideViewController.h"
#import "MainViewController.h"
#interface FlipsideViewController ()
#end
#implementation FlipsideViewController
#synthesize mainController = _mainController;
// methods
#end