UISplitview not alligned at the top - ios

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...

Related

Is it possible to display a SFSafariViewController inside of a UITabBarController?

I want to load SFSafariViewController inside of a tab, so the tab bar is at the bottom of the entire Safari view.
Is this possible? I tried this with no luck:
[self.tabBarController presentViewController:sfController animated:YES completion:nil];
Is it required that the Safari view be full screen?
I was able to achieve this programmatically. They key to not have the UITabBar overlay on top of your UIViewController is to set translucent to NO:
In your AppDelegate.m:
#import SafariServices;
// ...
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
UITabBarController *tabBarController = [[UITabBarController alloc] init];
tabBarController.tabBar.translucent = NO;
SFSafariViewController *firstVC = [[SFSafariViewController alloc] initWithURL:[NSURL URLWithString:#"http://stackoverflow.com"]];
firstVC.title = #"SFSafariViewController";
UIViewController *secondVC = [[UIViewController alloc] init];
secondVC.view.backgroundColor = [UIColor blueColor];
secondVC.title = #"Blue VC";
tabBarController.viewControllers = #[firstVC, secondVC];
self.window.rootViewController = tabBarController;
[self.window makeKeyAndVisible];
return YES;
}
Using JAL's answer as a base, I was able to implement this myself in an app that had existing structure with tabs already.
I wanted tab #3 to go into a Safari controller within the tab after a button was pressed on the existing view, and not pop the Safari controller into its own window like it does using Apple's default code.
The key was to swap in a SFSafariViewController into the existing UITabBarController's array of view controllers. I saved the existing original view controller on tab #3 (index 2) to come back to it when the Done button was pressed on the Safari controller.
Here's what I did to go into the Safari controller from with my tab when a button was pressed:
NSMutableArray *viewArray = [NSMutableArray arrayWithArray:self.tabBarController.viewControllers];
self.savedController = [viewArray objectAtIndex:2];
[viewArray replaceObjectAtIndex:2 withObject:safariController];
self.tabBarController.viewControllers = viewArray;
[self setTabIconTitle];
Then I could swap back to the original view on that tab like this when the Done button was pressed on the Safari controller using this delegate call:
- (void)safariViewControllerDidFinish:(SFSafariViewController *)controller
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
NSMutableArray *viewArray = [NSMutableArray arrayWithArray:tabBarController.viewControllers];
[viewArray replaceObjectAtIndex:2 withObject:self.savedController];
tabBarController.viewControllers = viewArray;
[self setTabIconTitle];
}
When I swapped controllers in an out of the tabBarController view controller array, I lost my tab icon and tab name, so I had to set those. Here is how I fixed that issue (and kept my theming when the tab icon was touched):
- (void)setTabIconTitle
{
UITabBarController *tabBarController = (UITabBarController *)self.window.rootViewController;
UITabBar *tabBar = tabBarController.tabBar;
UITabBarItem *marketplaceTab = [tabBar.items objectAtIndex:2];
marketplaceTab.image = [[UIImage imageNamed:#"tab2-icon"] imageWithRenderingMode:UIImageRenderingModeAlwaysOriginal];
marketplaceTab.selectedImage = [UIImage imageNamed:#"tab2-icon"];
marketplaceTab.title = #"My Tab";
}
I must admit that I am not sure that Apple intended that the SFSafariViewController be used in this way within a tab, based on what the normal behavior of calling SFSafariViewController currently does. Just be aware that future iOS updates may change this behavior and always test your code when new iOS versions go into Beta.

UISplitViewController Getting Detail VC Only in Portrait View

I have recently removed the tab bar from my app in favor of a "slide out" styled menu which I have written myself. It appears to be working perfectly, except that the one split-view controller I use in the app does not work correctly on the iPad in portrait orientation (landscape is just fine). The problem I'm seeing is the detail VC ONLY is loaded into the portrait view, where both VCs load correctly in landscape view. This is on iOS7.
So, here is the code I'm using. This code has been moved from the AppDelegate (previously) to the root VC. There were some changes but relatively minor. It did work fine with the tab bar, but using this new slide out menu (i.e., a table view) I have this one problem. I'm only including the portions of the code that I think would be relevant.
AdminMasterViewController *adminMasterVC = [[AdminMasterViewController alloc] init];
UINavigationController *adminMasterNav = [[UINavigationController alloc] init];
adminMasterNav.viewControllers = [NSArray arrayWithObjects:adminMasterVC, nil];
adminMasterNav.view.frame = CGRectMake(0,0,[Utility screenWidth],[Utility screenHeight]);
AdminDetailViewController *adminDetailVC = [[AdminDetailViewController alloc] init];
UINavigationController *adminDetailNav = [[UINavigationController alloc] init];
adminDetailNav.viewControllers = [NSArray arrayWithObjects:adminDetailVC, nil];
adminDetailNav.view.frame = CGRectMake(0,0,[Utility screenWidth],[Utility screenHeight]);
UISplitViewController *adminSplitVC = [[UISplitViewController alloc] init];
adminSplitVC.viewControllers = [NSArray arrayWithObjects: adminMasterNav, adminDetailNav, nil];
adminSplitVC.delegate = self;
adminSplitVC.title = #"Admin";
adminSplitVC.view.frame = CGRectMake(0,0,[Utility screenWidth],[Utility screenHeight]);
vcArray = [NSArray arrayWithObjects:homeVC, adminSplitVC, expressiveNav, receptiveNav, typerNav, nil];
(The last line builds the array of all the VCs in the project; the code which creates these VCs has been omitted).
After the VC has been selected it is presented as a child VC as follows:
UIViewController *vc;
if ([selected isEqualToString:#"Home"])
{
vc = [vcArray objectAtIndex:VCHome];
}
else if ([selected isEqualToString:#"Administrator"])
{
vc = [vcArray objectAtIndex:VCAdmin];
}
... (others listed here)
[self.view addSubview:vc.view];
[self addChildViewController:vc];
[vc didMoveToParentViewController:self];
From what I have read there may be some issue with NOT using the tab bar, but the articles are confusing because a lot of them are dated. I will appreciate any input or suggestions on this problem as I've read everything I can find and don't really know where to go from here. TIA.
After a couple of days of reading and trying different things, an hours after posting the question I solved this. Just in case anyone else hits this same problem, here's the solution:
I subclassed the UISplitViewController and made it its own delegate.
Then, this delegate method solved it:
- (BOOL)splitViewController:(UISplitViewController *)svc shouldHideViewController:(UIViewController *)vc inOrientation:(UIInterfaceOrientation)orientation
{
return NO;
}

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.

add a tabbed view as a main view to a navigation-based iphone app

I am relatively new to iOS, hence I apologize for any inconsistency in my question. I need help with the following issue with an app I'm trying to build. My issue is this: The app i am working has a navigation based functionality with a tableview(daily filled by user) and a detailed tableview listing the inputs of the user, but this is just one functionality of the app.
I want to have a main tab based view where one of the tabs(each tab representing a functionality) points to this module.
I wanted to ask for steps and changes i need to make to for example app delegate or rootviewcontroller(I can post the code if it helps better) to make is so that the app starts with a mutli-tabbed bar view where one tab refers to view linked to the rootviewontroller of the navigation-based app.
For summary: Need a main tab bar view where one tab points to the rootviewcontroller highlighted in the screenshot(link below)
If helpful here is a relevant function code i have in app delegate :
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[navigationController viewControllers] objectAtIndex:0];
rootViewController.managedObjectContext = self.managedObjectContext;
//Next TWO LINES FOR COLOR BACKGROUND
[[UINavigationBar appearance] setBackgroundImage:[[UIImage alloc] init] forBarMetrics:UIBarMetricsDefault];
[[UINavigationBar appearance] setBackgroundColor:[UIColor redColor]];
}
PS:Here is the screenshot for the storyboard: where i would like to have one tab refer to the view(highlighted in the screenshot) which is linked class rootviewcontroller.m/h
The screenshot: http://i.stack.imgur.com/G9AXI.png
edit: The actual question can be seen as: How and what do i need to do to have a tabbarviewcontroller which i would add with storyboard become my rootviewcontroller instead of the navigationcontroller(highlighted in black in the screenshot: http://i.stack.imgur.com/G9AXI.png).
My current rootviewcontroller.m manages anything related to the tableview of the current navigationviewcontroller, do i need to change that also?.
I apologize for excessiv details, I am really new to iOS dev.
From this one http://i.stack.imgur.com/suLBm.png I tried to embedd in tab barviewcontrol only with storyboard to this one http://i.stack.imgur.com/TZxLo.png I tried to embedd in a tab controller just by story but i get an error :'NSInvalidArgumentException', reason: '-[UIViewController setManagedObjectContext:]: unrecognized selector sent to instance 0x8184e30'
classes related to this are(especially rootviewcontroller.m which is a navigationcontroller for now:
AppDelegate.{h,m}
Configures the Core Data stack and the first view controllers.
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UINavigationController *navigationController = (UINavigationController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[navigationController viewControllers] objectAtIndex:0];
rootViewController.managedObjectContext = self.managedObjectContext;
}
RootViewController.{h,m}
Manages a table view for listing all values entered. Provides controls for adding and removing these values.
- (void)viewDidLoad
{
[super viewDidLoad];
self.navigationItem.leftBarButtonItem = self.editButtonItem;
}
DetailViewController.{h,m}
Manages a detail display for display details of each entered value.
My initial guess is that i need to change the rootviewcontroller appdidfinishlaunching.
Any suggestions ?
In fact now you have:
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
UITabBarController *tabController = (UITabBarController *)self.window.rootViewController;
RootViewController *rootViewController = (RootViewController *)[[[[tabController viewControllers] objectAtIndex:0] viewControllers] objectAtIndex:0];
rootViewController.managedObjectContext = self.managedObjectContext;
}
So you actually need a UITabBarViewController in the Storyboard and you can point to the UINavigationController if you want the ability to push other controllers.
You don't need other UINavigationControllers as I saw in your screenshot, as long as the rootviewcontroller is an UINavigationController.
You can add the UINavigationController as first of the tabs and then you can go and fill the other tabs with the viewcontrollers that you need displayed.
SO basically you need to create UITabBarController as rootviewcontroller.
Let me know if I understood your question correctly.
Here is an example of UITabBarController :
- (void)applicationDidFinishLaunching:(UIApplication *)application
{
//Here you set your controller
UIViewController* centerController = [[UIViewController alloc]init];
UINavigationController *navCenter = [[[UINavigationController alloc] initWithRootViewController:centerController] autorelease];
UITabBarController *tabBarController = [[[UITabBarController alloc] init] autorelease];
tabBarController.viewControllers = [NSArray arrayWithObjects:navCenter,nil];
self.window = [[[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]] autorelease];
self.window.rootViewController = tabBarController;
return YES;
}
Let me know if it worked.
You should have something like this :

UINavigationController is NULL

I've had a good look at the Apple docs as well as similar Stack Overflow questions, but I am stuck on why my navigationController is null when using tab bars. I am trying to build most of the app from code, and am not using XIBs to insert a navigationController.
While debugging I have greatly simplified my app, down to two tabs. One tab holds a tableview and when a row is touched I'm expecting a detail page (from a XIB) to appear. Should be pretty simple. I am finding the value of self.navigationController is NULL when attempting to push the detail view, and of course it is then not working. I took the tab bar our completely and it works fine from a single view (the tableview). In this instance self.navigationController has a value.
AppDelegate.m
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
// With Tab Bars
self.tabBarController = [[UITabBarController alloc] init];
ViewController *vc1 = [[ViewController alloc] initWithNibName:#"ViewController" bundle:nil];
vc1.tabBarItem.title = #"Words";
vc1.tabBarItem.image = [UIImage imageNamed:#"tab_feed.png"];
TextTableViewController *vc2 = [[TextTableViewController alloc] init];
vc2.tabBarItem.title = #"Text";
vc2.tabBarItem.image = [UIImage imageNamed:#"tab_live.png"];
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:vc1];
NSArray* controllers = [NSArray arrayWithObjects:vc2, navController, nil];
tabBarController.viewControllers = controllers;
tabBarController.delegate = self;
window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]];
window.rootViewController = self.tabBarController;
[window makeKeyAndVisible];
return YES;
}
From TextTableViewController.m
- (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath
{
TextViewController *detailViewController = [[TextViewController alloc] initWithNibName:#"TextViewController" bundle:nil];
Text *text = [[Text alloc] init];
text = [textArray objectAtIndex:indexPath.row];
detailViewController.TextID = text.textID;
NSLog(#"Nav Controller: %#",self.navigationController);
[self.navigationController pushViewController:detailViewController animated:YES];
NSLog(#"pushed");
}
I've also got two questions related to this problem.
(1) What is the purpose of this line. It doesn't appear to make a difference if it is in or out, and is absent from the Apple example.
tabBarController.delegate = self;
(2) When creating an array of tabs, one of the views is made the navigationController. Does it matter which tab it is or should this be a different view altogether not related to any tab and not visible. Is this where the problem lies?
In answer to question (1) about the tab bar controller's delegate, see the UITabBarControllerDelegate protocol reference. For the basic functionality of a tab bar controller, you don't need to bother with a delegate.
But let's say you want to do something special--for instance, save a document or reset an interface element to a default value--when the user changes tabs. You could make one of your classes, perhaps your app delegate or another controller class, conform to the UITabBarControllerDelegate protocol and implement tabBarController:didSelectViewController:
In your "answer" you asked if each tab will need its own UINavigation controller. That is absolutely correct. Basically, each tab is a completely independent hierarchy, so you need a separate UINavigation controller in each tab that requires one.
This should also imply the answer to your question (2) in the original post. You need to add the nav controller to the specific tab(s) that needs it.
OK I found it. The UINavigationController needs to be contained within the appropriate tab of the UITabBarController. So by making this coding change (below), a new UINavigationController is embedded in the tab with the tableview.
UINavigationController* navController = [[UINavigationController alloc] initWithRootViewController:vc2];
NSArray* controllers = [NSArray arrayWithObjects:vc1, navController, nil];
Which then begs the question: what if you need multiple examples of this - do you create a new UINavigationController for each tab that has a need for one, and mark each one as a rootViewController?

Resources