How to create a DetailViewController for UISplitViewController? - ipad

I have developed a program for iPad programmatically. I have a SplitViewController, RootViewController and DetailViewController.
I am able to get the UITableViewController as a popover.
How to get a UILabel been displayed on DetailViewController on click of each index of the UITableViewController programmatically?
Thanks in advance..

The template that Apple provides for you in XCode does exactly what you are looking for.

Firstly, I realise the original poster has probably long since moved on from needing an answer to this question. Since I recently needed to search for a similar question, did not find a suitable question/answer, I decided to start digging for myself, and came up with an answer that may be useful for someone else.
As mentioned by #Wes, the template provided in XCode for "Master-Detail Application" does create useful jumping off point to create a universal app with a view controller:
XCode 4.2 New Project Dialog
be sure to also choose Universal..
What I did find however, which was not inherently obvious, is that whilst when using the app as an iPhone app, you will get a call to method setDetailItem: in the detailViewController (which will in turn call configureView), you won't automatically get this happening in the iPad version of the app. this is because the _detailViewController ivar (mapped to by detailViewController property) in masterViewController is nil by default.
This is because in the iPhone version, when you select a detail item, the default code checks to see if this iVar is nil, and autocreates one for you. in the iPad version however, the [appDelegate application: didFinishLaunchingWithOptions:] has already created a single detailViewController for you, along with a masterViewController. to get this working in my code, what I did was add the following lines in the [appDelegate application: didFinishLaunchingWithOptions:] method, as follows:
masterViewController.detailViewController = detailViewController;
[masterViewController tableView:masterViewController.tableView
didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
The second line automatically selects the first detail item for you on app start. This is safe in the default demo code, because it is set up to handle 1 detail. if you are going to change that in your code (eg by creating the detail items dynamically from some other source) you will of course need to ensure there is a valid detail item there to select at position 0.
The method (after i added these 2 lines) looks like this now:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
MasterViewController *masterViewController = [[[MasterViewController alloc] initWithNibName:#"MasterViewController_iPhone" bundle:nil] autorelease];
self.navigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];
self.window.rootViewController = self.navigationController;
} else {
MasterViewController *masterViewController = [[[MasterViewController alloc] initWithNibName:#"MasterViewController_iPad" bundle:nil] autorelease];
UINavigationController *masterNavigationController = [[[UINavigationController alloc] initWithRootViewController:masterViewController] autorelease];
DetailViewController *detailViewController = [[[DetailViewController alloc] initWithNibName:#"DetailViewController_iPad" bundle:nil] autorelease];
UINavigationController *detailNavigationController = [[[UINavigationController alloc] initWithRootViewController:detailViewController] autorelease];
masterViewController.detailViewController = detailViewController;
[masterViewController tableView:masterViewController.tableView
didSelectRowAtIndexPath:[NSIndexPath indexPathForRow:0 inSection:0]];
self.splitViewController = [[[UISplitViewController alloc] init] autorelease];
self.splitViewController.delegate = detailViewController;
self.splitViewController.viewControllers = [NSArray arrayWithObjects:masterNavigationController, detailNavigationController, nil];
self.window.rootViewController = self.splitViewController;
}
[self.window makeKeyAndVisible];
return YES;
}

Related

Strange behaviour of UINavigationController when the applications rootViewController is a tabBarController

I try to push a UIViewController onto a UINavigationController. The NavigationBar changes (i.e. a back-button appears) but the view is not pushed (*).
I have a UITabBarController as my applications RootViewController.
When I switch to another tab and then switches back, the view (*) gets pushed.
I have never seen this behaviour before. My problem is exactly the same as this, however the methods that solved that issue did not solve mine.
Initially
After I press the row
I understand that this question might be related to issues in AppDelegate, therefore i post the code I use.
Code:
in AppDelegate:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions: (NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
self.window.backgroundColor = [UIColor whiteColor];
[MagicalRecord setupCoreDataStackWithStoreNamed:#"DBModel"];
/* CONTACTS LIST CONTROLLER */
BoonContactListViewController *contactListViewController = [[BoonContactListViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *contactListNavigationController = [[UINavigationController alloc] initWithRootViewController:contactListViewController];
[contactListNavigationController setValue:[[BoonNavigationBar alloc]init] forKeyPath:#"navigationBar"];
contactListNavigationController.tabBarItem.title = [NSLocalizedString(#"CONTACTS", nil) capitalizedString];
contactListNavigationController.tabBarItem.image = [UIImage imageNamed:#"menu_contacts.png"];
/* INVITATIONS */
BoonInvitationListViewController *invitationListController = [[BoonInvitationListViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *invitationNavigationController = [[UINavigationController alloc] initWithRootViewController:invitationListController];
[invitationNavigationController setValue:[[BoonNavigationBar alloc]init] forKeyPath:#"navigationBar"];
invitationNavigationController.tabBarItem.title = [NSLocalizedString(#"SETTINGS", nil) capitalizedString];
invitationNavigationController.tabBarItem.image = [UIImage imageNamed:#"menu_invitations.png"];
/* SETTINGS */
BoonSettingsViewController *settingsViewController = [[BoonSettingsViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *settingsNavigationController = [[UINavigationController alloc] initWithRootViewController:settingsViewController];
[settingsNavigationController setValue:[[BoonNavigationBar alloc]init] forKeyPath:#"navigationBar"];
settingsNavigationController.tabBarItem.title = [NSLocalizedString(#"SETTINGS", nil) capitalizedString];
settingsNavigationController.tabBarItem.image = [UIImage imageNamed:#"menu_settings.png"];
/* TAB BAR */
BoonTabBarViewController *tabBarController = [[BoonTabBarViewController alloc] init];
tabBarController.viewControllers = #[contactListNavigationController, invitationNavigationController, settingsNavigationController];
[self.window setRootViewController:tabBarController];
[self.window makeKeyAndVisible];
[tabBarController showLogin];
return YES;
}
EDIT:
In the viewController that i am trying to push, neither viewWillAppear, viewDidLoad nor viewDidAppear is called.
If I use presentViewController: animated: completion: I get the preferred behaviour, id rather not though
EDIT 2
How I push my new VC
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
BoonContactInfoViewController *contactInfoViewController = [[BoonContactInfoViewController alloc] initWithNibName:nil bundle:nil];
NSLog(#"NAV %#", self.navigationController);
[self.navigationController pushViewController:contactInfoViewController animated:YES];
}
EDIT 3
It is only the initial tab that cannot push ... if i swap places of the first and second tab, i can push a view controller using in the way i do above.
EDIT 4
It works if i (in my tabBarController) calls
self.selectedIndex = 1;
self.selectedIndex = 0;
EDIT 5
- (void)showLogin
{
if([BoonUserHandler getLogin].length > 0 && [BoonUserHandler getPassword].length > 0){
return;
}
BoonWelcomeViewController *welcomeWC = [[BoonWelcomeViewController alloc] initWithNibName:nil bundle:nil];
UINavigationController *welcomeNavigationController = [[UINavigationController alloc] initWithRootViewController:welcomeWC];
[welcomeNavigationController setNavigationBarHidden:YES];
[self presentViewController:welcomeNavigationController animated:NO completion:nil];
}
What version of iOS are you developing for?
I'd first ask why you're hacking in a nav bar using:
[settingsNavigationController setValue:[[BoonNavigationBar alloc]init] forKeyPath:#"navigationBar"];
rather than the iOS5+ UINavigationController method:
- (instancetype)initWithNavigationBarClass:(Class)navigationBarClass toolbarClass:(Class)toolbarClass
But my overall suggestion would be to remove all this code and use a storyboard. This looks like the perfect opportunity.
I think you are getting wrong Navigation controller to push that's why it showing this problem..
You have to fetch right navigation controller from tab controller
self.tabBarController.selectedIndex = 0;
just change tab controller selected index

Switch between different Views with a Navigation Controller

I'm totally new to iOS programming. I only programmed on Android so far and Objective-C is a total different and new language for me now.
What I want to do is to not use a design that I've created with the storyboard. I want to do all programmatically, since I think it will be more dynamic if I do it like this.
The problem I'm encountering is, that I want to have 3 different views. I googled a bit, and stumbled upon some stackoverflow questions. There, people suggested using a NavigationController. Okay. Now I'm trying to implement it. What I want to have is the following
A MainViewController that has 3 different views. The first view is a loginView. The second one is displaying data and the third is displaying detailed data dependent on the click of the second view.
Is a navigationcontroller corerct for this? The problem I'm having is where I tell the app that I want to start with the MainViewController and push the LoginView in it.
I have a MainViewController.h and MainViewController.m that are subclasses of UIViewController
Now, where exactly do I do this? I have the didFinishLaunchingWithOptions method right here with the following content
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
self.window.backgroundColor = [UIColor whiteColor];
UIViewController *viewController = [[MainViewController alloc]init];
UINavigationController *navigationController = [[UINavigationController alloc] initWithRootViewController:viewController];
[navigationController pushViewController:viewController animated:NO];
self.window.rootViewController = navigationController;
[self.window makeKeyAndVisible];
return YES;
}
But that just crashes the app. What am I doing wrong? How do I get those three views? Am I starting completely wrong? Please help. As I said I'm new to iOS development. It's easy for me to programm on one view. I did that already, but I want thre different views! Thanks!
A MainViewController that has 3 different views. The first view is a loginView. The second one is displaying data and the third is displaying detailed data dependent on the click of the second view.
That's wrong.
You need three different view controllers, each of those will manage its own view.
Then you push one after another in the navigation controller, depending on user interaction.
Yes, Gonzalo Aune is rite, You should not push the rootviewcontroller in NavicationController.
Also , I will Suggest you to keep your first view (Login View) out of Navigation controller.
You can start with your MainViewController and based on check and conditions you can present LoginView on MainViewController using
[self presentViewController:loginViewController animated:YES completion:NULL];
And after successful login you can dismiss LoginViewController.
Remove this:
[navigationController pushViewController:viewController animated:NO];
You shouldnt push the ViewController since you told the NavigationController already that the ViewController would be the root one:
UINavigationController *navigationController = [[UINavigationController alloc]
initWithRootViewController:viewController];
use this code and if application is universion then use same code else remove the condition of ([[UIDevice currentDevice] userInterfaceIdiom]
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
UINavigationController *navController;
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPhone" bundle:nil];
{
if(result.length>0)
{
for(var i in result)
{
var ObjResult=result[i];
var content = "<div data-role='collapsible' id='set" + i + "'>";
content+="<h3>"+ObjResult.title+"<br>";
var intDate=parseInt(ObjResult['ordered date']);
content +=timestampToDate(intDate)+"</h3>"
if(isNaN(ObjResult.med_placeorderfor))
content+="<p><a>Medicle Place order for: </a>"+result[i].med_placeorderfor+"</p>";
if(isNaN(ObjResult.pres_placeorderfor)>0)
content+="<p><a>Medicle Place order for: </a>"+result[i].placeorderfor+"</p>";
if(ObjResult['order status'].length>0)
content+="<p><a>Order status: </a>"+ObjResult['order status']+"</p>";
if(ObjResult.comments.length>0)
content+="<p><a>Comments: </a>"+ObjResult.comments+"</p>";
content+="</div>";
}
$("#id_notification_list_dashboard").append( content ).collapsibleset('refresh');
$("#id_notification_list_dashboard").trigger('create');
}
else
{
$("#id_notification_list_dashboard").append("<div style=\"text-align:center\" data-role='list-divider'><h1>No data found</h1></div>").collapsibleset('refresh');
}
$('body').removeClass('ui-loading');
loadingWithMsg("hide");
}
} else {
self.viewController = [[ViewController alloc] initWithNibName:#"ViewController_iPad" bundle:nil];
}
navController=[[UINavigationController alloc]initWithRootViewController:self.viewController];
[navController.navigationBar setTranslucent:YES];
navController.navigationBar.tintColor = [UIColor colorWithRed:161.0f/255.0f green:18.0f/255.0f blue:6.0f/255.0f alpha:1];
self.window.rootViewController =navController ;
[self.window makeKeyAndVisible];
return YES;
}

iOS itouch replaceObjectAtIndex navigation bar disappears

I have a family of devices that are very similar and are controlled by an applet with three tabs. Within each view controller, I make use of the navigation controller to expand into the set up of each one of those features.
The first tab, the 'input' tab, especially is quite different between these three devices so when it is detected that I've switched between devices, I perform the following thing in my application delegate:
if ([self IsCrescendo])
{
//thirdViewController is really the crescendo'a input view - I need to rename that mess one day
crescendoInputView = [[ThirdViewController alloc] init : (UIViewController*) currentViewController];
crescendoInputView.title = [[viewControllers objectAtIndex:INPUT_TAB_INDEX] title];
crescendoInputView.tabBarItem = [[viewControllers objectAtIndex:INPUT_TAB_INDEX] tabBarItem];
[viewControllers replaceObjectAtIndex:INPUT_TAB_INDEX withObject:crescendoInputView];
[crescendoInputView release];
[self.tabBarController setViewControllers:viewControllers animated:FALSE];
}
if ([self IsSpirito3])
{ // similar to above using obviously a different view controller
}
if ([self IsSonata])
{ // similar to above using obviously a different view controller
}
Initially, this app just controlled one device so when I first created it, I set the three tabs up in the main window's XIB which works well. It defaults to the original device and the navigation bar is in tact and working.
Now that there are more devices to control, I figured to just use a replaceObjectAtIndex so swap a new view controller in but my Navigation bar disappears.
I'd very much appreciate any light you may be able to shed on this.
Thanks!
Okay, after lots more head scratching, the following fixed it:
I had initially used the main window's XIB to instantiate the three tabs.
This works fine if you're not doing a replaceObjectAtIndex. When I did do a ReplaceObjectAtIndex, it would lose the navigation bar.
Instead, if you instantiate the tabs programmatically, along with each having its own navigation controller, you can replace tabs with impunity and not lose features like the navigation bar.
(BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
// Override point for customization after application launch.
// Input view (defaults to Crescendo)
UIViewController *viewController1 = [[[ThirdViewController alloc] initWithNibName:#"ThirdView" bundle:nil] autorelease];
UINavigationController *nav1 = [[UINavigationController alloc] initWithRootViewController:viewController1];
// Volume View
UIViewController *viewController2 = [[[SecondViewController alloc] initWithNibName:#"SecondView" bundle:nil] autorelease];
UINavigationController *nav2 = [[UINavigationController alloc] initWithRootViewController:viewController2];
// System view
UIViewController *viewController3 = [[[FirstViewController alloc] initWithNibName:#"FirstView" bundle:nil] autorelease];
UINavigationController *nav3 = [[UINavigationController alloc] initWithRootViewController:viewController3];
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:nav1, nav2, nav3, nil];
.
.
}
Not sure why it does not work when you set it up from a XIB. I could swear I had it working on a previous version so maybe something changed and apple forgot to tell us about it.
I like this approach better anyway. It isn't the first time a 'wizard like' programming tool has bit me so maybe this will save someone out there a little time.

Using a navigationcontoller with a tabbar controller

I'm trying to make it so I have a tab bar at the bottom of my screen, and it's always there. I also want it so if I "click" into some menu in one of the tabs, it gives you the option to go back, thus a navigation controller and a tab bar controller.
I still don't really understand iOS, so the answer I found is confusing me.
This Answer: Having a UITabBar AND a UINavigationController in an app?
So how do I implement this? I'm guessing I change this method in my App Delegate,
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
// Override point for customization after application launch.
UIViewController *viewController1, *viewController2;
if ([[UIDevice currentDevice] userInterfaceIdiom] == UIUserInterfaceIdiomPhone) {
viewController1 = [[CFSDFirstViewController alloc] initWithNibName:#"CFSDFirstViewController_iPhone" bundle:nil];
viewController2 = [[CFSDSecondViewController alloc] initWithNibName:#"CFSDSecondViewController_iPhone" bundle:nil];
} else {
viewController1 = [[CFSDFirstViewController alloc] initWithNibName:#"CFSDFirstViewController_iPad" bundle:nil];
viewController2 = [[CFSDSecondViewController alloc] initWithNibName:#"CFSDSecondViewController_iPad" bundle:nil];
}
self.tabBarController = [[UITabBarController alloc] init];
[self.tabBarController setDelegate:self];
self.tabBarController.viewControllers = [NSArray arrayWithObjects:viewController1, viewController2, nil];
self.window.rootViewController = self.tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Thanks for your assistance!
First of all you don't need to to manually set up the nib name. You could just name them CFSDFirstViewController~iphone.xib and CFSDFirstViewController~ipad.xib. Then you can call [[CFSDFirstViewController alloc] init] and let iOS do the rest for you. For info see iOS Supports Device-Specific Resources.
About your question, you can only insert the UINavigationController within the UITabBarController. To do it wrap viewController1 within a UINavigationController like the following:
CFSDFirstViewController viewController1 = [[CFSDFirstViewController alloc] init];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:viewController1];
and then use navController instead of viewController1 like the folliwing
self.tabBarController.viewControllers = [NSArray arrayWithObjects:navController, nil];
Check the code because I wrote by hand. And pay attention to memory if you use a non-ARC project.
Hope it helps.

UISplitview not alligned at the top

I have a problem I can't figure out, I have made an application which uses UIsplitview inside a tab bar. I have been implementing the different tabs however now when I am working on the first tab - the UIsplitview is not aligned in landscape mode. Do you guys have any suggestions - if I start it in portrait and go to landscape, then there's no problem at all.
Update:
I dont do any init with frames anywhere, and I have checked the sizes etc. in IB. The following shows how I add the uisplitview controller in the app delegate. It has been done this way because I wanted a splitview in a tabbar controller. When i have added the spilview I just set the master and detail view in IB. A bit of mystery.
if (index == 2) {
detailViewController = [[DetailUserCreatorViewController alloc] initWithNibName:#"DetailUserCreatorView" bundle:nil];
userContent=[[UserContentForPopViewController alloc]init];
userContent.userDetails=detailViewController;
detailViewController.delegate=userContent;
//rootViewController.navigationItem.title = #"List";
UINavigationController *nav = [[[UINavigationController alloc] initWithRootViewController:userContent] autorelease];
splitViewController = [[UISplitViewController alloc] init];
splitViewController.tabBarItem = controller.tabBarItem;
splitViewController.viewControllers = [NSArray arrayWithObjects:nav, detailViewController, nil];
splitViewController.delegate = detailViewController;
[controllers replaceObjectAtIndex:index withObject:splitViewController];
}
Update: I tried to set the selected tab in application didfinishlaunch in the app delegate - self.tabBarController.selectedIndex = 0; and this made the tab start at the correct placement. However it does not seem to be a proper solution.
Some pointers...splitViewController needs to be added as a subview of window:
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[window addSubview:splitViewController.view];
[window makeKeyAndVisible];
return YES;
}
The following code is incorrect. You should not assign a viewController to a delegate.
splitViewController.delegate = detailViewController;
You will also not require this line of code:
[controllers replaceObjectAtIndex:index withObject:splitViewController];
The following line handles that part of assigning delegates.
splitViewController.viewControllers = [NSArray arrayWithObjects:nav, detailViewController, nil];
Also, if you can upload your code, I'll try to correct it and post back the reason and corrected code...

Resources