How to rotate app with TabBar? - xcode

Hi I have a splitview app that is working fine until I add a TabBar in the rootview section. The problem is that when I add the TabBar to the rootview the app does not rotate to landscape, if I change the orientation the view remains in portrait mode.
How can I solve this?. Hope you can help
#import "SplitViewTest3AppDelegate.h"
#import "SISACWelcomeViewController.h"
#implementation SplitViewTest3AppDelegate
#synthesize window, masterViewController, splitViewController,masterViewTabBarController, searchViewController;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
masterViewController = [[MasterViewController alloc] initWithStyle:UITableViewStyleGrouped];
UINavigationController *masterNavigationController = [[UINavigationController alloc] initWithRootViewController:masterViewController];
masterNavigationController.tabBarItem.image = [UIImage imageNamed:#"Folder.png"];
//NewsFeedsNavigationController *newsFeedsNavigationController = [[NewsFeedsNavigationController alloc] init];
SISACWelcomeViewController *sisacWelcomeViewController = [[SISACWelcomeViewController alloc] init];
UINavigationController *detailNavigationController = [[UINavigationController alloc] initWithRootViewController:sisacWelcomeViewController];
searchViewController = [[UIViewController alloc] initWithNibName:#"SearchView" bundle:nil];
searchViewController.tabBarItem.image = [UIImage imageNamed:#"Search-icon.png"];
masterViewTabBarController = [[UITabBarController alloc] init];
masterViewTabBarController.viewControllers = [NSArray arrayWithObjects:masterNavigationController, searchViewController, nil];
masterViewController.detailNavigationController = detailNavigationController;
splitViewController = [[UISplitViewController alloc] init];
splitViewController.viewControllers = [NSArray arrayWithObjects:masterViewTabBarController, detailNavigationController, nil];
splitViewController.delegate = sisacWelcomeViewController;
// Add the split view controller's view to the window and display.
[window addSubview:splitViewController.view];
//[masterNavigationController.view addSubview:tab.view];
[window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
*/
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}
- (void)dealloc {
[window release];
//[tab release];
[super dealloc];
}
#end

The answer below is correct. If you are adding tabs which include using the CoreDataTableView controller (that is used with the CS193P course), be sure to add a method to allow for any orientation. If not, your split view will not work correctly.

SOLVED:
I had the same issue.
Without the TabBar all is well, add the TabBar and the rotation breaks.
I guessed that there is something broken in the responder chain or view hierarchy.
So I was about to submit as a bug. So wrote a test app to demo to Apple (because they ALWAYS ask for one), and it worked. Hooray, but why?
These are my findings from the Apple docs.
From the View Programming Guide for iOS.
Split View Controller
"A split view controller must always be the root of any interface you create."
Thus they should not be embedded within a TabBar View, although I understand that there is a workaround out in the wild.
Also:
Creating a Tab Bar Interface
"Install it as one of the two root views in a split view interface. (iPad only)"
Solution:
After much more investigation, and some trial and error, I found the issue.
Of course it seems so obvious NOW.
When the SplitView tests for shouldAutorotateToInterfaceOrientation, it tests every possible view on the whole hierarchy, that is EVERY view in the MasterView, thus EVERY view in the TabBar, and EVERY view in the DetailView, thus EVERY view in the current NavigationStack.
The fly in the ointment is that a newly created ViewController does not support Landscape by default.
Where I had gone wrong was: I had created ALL of the TabBar subviews, but not written any more code yet, because I wanted to get the SplitView with TabBar working first, thus 1 of my Tab Views had not been changed from the default.

Related

The new UISplitViewController in iOS8 using objective c without storyboard

I try to implement adaptive UI in my app. By making UISplitViewController as the rootview controller, I can run the iPhone's code in iPad too.
I red Apple's documentation about UISplitViewController and some samples. All are using storyboards and the sample codes are available in swift only. I can not find a working version of code. So I started the code myself.
See my splitview controller class (BaseSplitViewController)
BaseSplitViewController.h:
#import <UIKit/UIKit.h>
#interface BaseSplitViewController : UISplitViewController <UISplitViewControllerDelegate>
#end
BaseSplitViewController.m:
#import "BaseSplitViewController.h"
#import "TabBarViewController.h"
#interface BaseSplitViewController ()
#property(nonatomic, strong) TabBarViewController *primaryTabBarVC;
#property(nonatomic, strong) UINavigationController *primaryNavigationController;
#property(nonatomic, strong) UINavigationController *secondaryNavigationController;
#end
#implementation BaseSplitViewController
- (instancetype)init
{
self = [super init];
if (self)
{
[self setViewControllers:#[self.primaryNavigationController, self.secondaryNavigationController]];
self.delegate = self;
self.preferredDisplayMode = UISplitViewControllerDisplayModeAutomatic;
[[NSNotificationCenter defaultCenter] addObserver:self selector:#selector(cellTapped:) name:#"cellTapped" object:nil];
}
return self;
}
- (void)viewDidLoad
{
[super viewDidLoad];
[self assignPrimaryViewController];
}
- (void)assignPrimaryViewController
{
// Need to assign tab bar controller as primary view controller here
}
- (void)assignSecondaryViewController:(UIViewController *)vc
{
// Need to update the secondary controller each time the primary controller was tapped
}
- (UINavigationController *)primaryNavigationController
{
if (!_primaryNavigationController)
{
_primaryNavigationController = [[UINavigationController alloc] init];
}
return _primaryNavigationController;
}
- (UINavigationController *)secondaryNavigationController
{
if (!_secondaryNavigationController)
{
_secondaryNavigationController = [[UINavigationController alloc] init];
}
return _secondaryNavigationController;
}
- (UITabBarController *)primaryTabBarVC
{
if (!_primaryTabBarVC)
{
_primaryTabBarVC = [[TabBarViewController alloc] init];
}
return _primaryTabBarVC;
}
#end
Some points:
The above class "BaseSplitViewController" is the rootview controller of my app.
That is, self.window.rootViewController = [[BaseSplitViewController alloc] init];
From Apple's Documentation,
"When designing your split view interface, it is best to install
primary and secondary view controllers that do not change. A common
technique is to install navigation controllers in both positions and
then push and pop new content as needed. Having these types of anchor
view controllers makes it easier to focus on your content and let the
split view controller apply its default behavior to the overall
interface."
So, I created two navigation controllers (primary/secondary) and set them as split view controllers's primary & secondary views. setViewControllers: can be used for this.
My primary view here is, tab bar view. So, inside the assignPrimaryViewController: method, I should assign my TabBarViewController as split view controller's primary view.
Here, I found two ways.
1. [self.primaryNavigationController showViewController:self.primaryTabBarVC sender:nil];
2. [self.primaryNavigationController pushViewController:self.primaryTabBarVC animated:YES];
Here, I tried with [self showViewController:self.primaryTabBarVC sender:nil]; but my tab bar view was never shown. From my understanding, here "self" means the UISplitViewController. Calling showViewController: here makes the confusion to choose the navigation controller. Because we have two navigation controllers. So we need to clearly tell that navigation controller which needs to hold the primary controller.
Primary view controller part is over. Now the real problem starts. Consider my primary view controller is the tab bar which have tableview's in it. If I tap on the cell, I need to update the secondary view's content. This is the case in Regular mode. In compact mode, I expect when the user taps on the cell, it should push the detail view (secondary view) with back button.
I expect to put the below code within assignSecondaryViewController: vc: method
[self.secondaryNavigationController pushViewController:vc animated:NO];
[self.primaryNavigationController showDetailViewController:self.secondaryNavigationController sender:nil];
But it does not works.
Questions:
What should be placed inside assignPrimaryViewController & assignSecondaryViewController: methods to get my expected result?
And I really, yes really don't know how to implement UISplitViewController's following delegate methods.
primaryViewControllerForCollapsingSplitViewController:
splitViewController:collapseSecondaryViewController:ontoPrimaryViewController:
primaryViewControllerForExpandingSplitViewController:
splitViewController:separateSecondaryViewControllerFromPrimaryViewController:
Would be really helpful, if someone explains this new UISplitViewController's behavior.
Thanks

xcode - switch between more than 2 view controllers

I have several .xib files (page1, page2 ...) and want to switch between them using buttons (as a navigation bar)
I am using
page1 *second = [[page1 alloc] initWithNibName:nil bundle:nil];
second.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:second animated: YES];
page2 *second = [[page2 alloc] initWithNibName:nil bundle:nil];
second.modalTransitionStyle = UIModalTransitionStyleFlipHorizontal;
[self presentModalViewController:second animated: YES];
and so on...
I learned that this consumes a lot of memory because I am presenting a view over and over again and after switching back and forth the app sometimes crashes.
So, question is what can I do?
I tried this:
[self dismissModalViewControllerAnimated:YES]
but after dismiss it returns to the previous page and I can not navigate to another one.
Probably I used a stupid approach, however, I've done a few apps that way and don't want to change the controller completely.
Thank you for your help!
I think you have to create IBActions from that 2 blocks of code an link that IBActions to the right button.

How to I launch a view controller from a tap gesture

Apologies if this is a basic question but I am new to Xcode and have a storyboard app and in the storyboard (with no segue) I have a view controller with an embedded map view.
On the storyboard screen I have an image with a tap gesture linked, I have tested the tap and it works (NSLog) but I want to know how to launch my mapview view controller and also zoom to an x&y.
My code currently has
-(IBAction)handleMapTap:(UIGestureRecognizer *)sender {
NSLog(#"Tapped");
}
& I have tried;
MMMapViewController *mapViewController = [[MMMapViewController alloc] initWithNibName:#"MapView" bundle:nil];
[self.navigationController pushViewController:mapViewController animated:YES];
My view controller has a class set as MMMapViewController I have given the view controller a storyboard id of MapView (if it's required?).
I've read a lot of stackoverflow articles but can't seem to find an answer. If anyone can help I would be really grateful.
-(IBAction)handleMapTap:(UIGestureRecognizer *)sender
{
MMMapViewController *mapViewController = [[MMMapViewController alloc] initWithNibName:#"MapView" bundle:nil];
//[self.navigationController pushViewController:mapViewController animated:YES];
[self presentModalViewController:mapViewController animated:YES];
[mapViewController release];
}
It would probably help to know what self is, if it is indeed a UIViewController, then
I would make sure that self.navigationController is not nil.
You actually have the right code, as far as I can tell, but depending on your scenario, you could get away with presenting the mapView as a modal view controller.

Expected Identifiers in Xcode? I need need help!

im using 3.2.6 iOS 4.3 to begins with. now the question i have is its telling me I have an (located on the "(#Implementation window, hvController;"):
Expected Identifier or '(' before '#' token
in the Delegate.m class
//HelloUniverseAppDelegate.M
(#Implementation window, hvController;
(...
//HelloUniverseAppDelegate.m
- (void)applicationDidFinishishLaunching:(UIApplication *)application {
HelloUniverseController *hvc = [[HelloUniverseController alloc]
inWihhNibName:#"HelloUniverse" bundle:[NSBundle mainBundle]];
self.hvController = hvc;
[hvc release];
[window addSubview:[self.hvController view]];
// Override point for customization after application launch
[window makeKeyAndVisible ;
}
- (Void)dealloc {
[hvController release];
[window release];
[super dealloc];
}
HelloUniverseController *hvc = [HelloUniverseController alloc];
hvc = [hvc initWithNibName:#"HelloUniverse" bundle:[NSBundle mainBundle]];
#import "HelloUniverseAppDelegate.h"
#implementation HelloUniverseAppDelegate
#synthesize window;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
// Override point for customization after application launch.
[self.window makeKeyAndVisible];
return YES;
}
- (void)applicationWillResignActive:(UIApplication *)application {
/*
Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state.
Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game.
*/
}
- (void)applicationDidEnterBackground:(UIApplication *)application {
/*
Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later.
If your application supports background execution, called instead of applicationWillTerminate: when the user quits.
*/
}
- (void)applicationWillEnterForeground:(UIApplication *)application {
/*
Called as part of transition from the background to the inactive state: here you can undo many of the changes made on entering the background.
*/
}
- (void)applicationDidBecomeActive:(UIApplication *)application {
/*
Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface.
*/
}
- (void)applicationWillTerminate:(UIApplication *)application {
/*
Called when the application is about to terminate.
See also applicationDidEnterBackground:.
*/
}
#pragma mark -
#pragma mark Memory management
- (void)applicationDidReceiveMemoryWarning:(UIApplication *)application {
/*
Free up as much memory as possible by purging cached data objects that can be recreated (or reloaded from disk) later.
*/
}
- (void)dealloc {
[window release];
[super dealloc];
}
#end
now also its telling me I have a similar error in the Controller.h with
Expected Identifier before '{' token
its located on the "- (void)dealloc :{" line. the code I have for it is
#import <UIKit/UIKit.h>
#interface HelloUniverseController : UIViewController {
IBOutlet UITextField *txtFirstName;
IBOutlet UITextField *txtLastName;
IBOutlet UILabel *lblMessage;
}
- (IBAction) btnClickMe_Clicked:(id)sender;
//HelloUniverseController.m
- (void)dealloc :{
[txtFirstName release];
[txtLastName release];
[lblMessage release];
[super dealloc];
}
#end
im also very new at this, my second day ever using a mactonish as well as first with Xcode.
Objective-C requires that classes have two parts: the interface, which usually appears in a .h file and declares the class' instance variables, properties, and methods; and the implementation, which should be in a .m file and defines the class' methods. You seem to be trying to define the -dealloc method inside an #interface block rather than inside an #implementation block, and that's leading to at least one of the errors you're getting.
Frankly, one cannot avoid the impression that you've copied and pasted code from somewhere without understanding very much about the language. There are a number of blatant errors that just don't make any sense, including the one I just described and the #import statement that seems to be part of your -applicationDidFinishLaunching method.
StackOverflow is a great community that will, I'm sure, be happy to help you as you learn to program. However, you'll quickly wear out your welcome if you haven't made an effort to learn the basic syntax of the language. More importantly, it's really not going to help you if we just keep correcting your errors. Please, please read Learning Objective-C: A Primer. Or, if you don't have any experience with C-based languages (C, C++, C#, Java...) and some form of object-oriented programming, consider picking up a third-party book aimed at beginners. Thanks to the huge popularity of iPhone and iPad, there are plenty of books to choose from.
Remove this
(
before
(#implementation

Interface Builder: Failing to display TabBarController when calling from TableViewController

A buddy of mine asked for a quick sample of code for an app skeleton that would use a TableView to call a TabView. I estimated an hour.
After more hours than I want to admit messing around in IB, I gave up and implemented the following code.
Can anyone tell me how to do this in IB? I was careful (I thought) to make all the right connections, but no go. I even had another (working) app where I went through and step-by-step made the same connections. I got errors about "Changing the delegate of a tab bar managed by a tab bar controller is not allowed..." (This when I connected the TabBar's delegate to the File's owner, even though another app was working fine with that setting)
Until I wrote this code, I never got the tabbar view, only the view that came with the view xib... (I tested by putting a label on the view).
Thanks in advance...
UITabBarController *tabBarController = [[[UITabBarController alloc] initWithNibName:nil bundle:nil] autorelease];
NumberOneViewController *numberOneViewController = [[[NumberOneViewController alloc] initWithNibName:#"NumberOneViewController" bundle:nil] autorelease];
NumberTwoViewController *numberTwoViewController = [[[NumberTwoViewController alloc] initWithNibName:#"NumberTwoViewController" bundle:nil] autorelease];
NumberThreeViewController *numberThreeViewController = [[[NumberThreeViewController alloc] initWithNibName:#"NumberThreeViewController" bundle:nil] autorelease];
NumberFourViewController *numberFourViewController = [[[NumberFourViewController alloc] initWithNibName:#"NumberFourViewController" bundle:nil] autorelease];
tabBarController.viewControllers = [NSArray arrayWithObjects:numberOneViewController, numberTwoViewController,
numberThreeViewController, numberFourViewController, nil];
[self.navigationController pushViewController:tabBarController animated:YES];
self.view = tabBarController.view; in the viewDidLoad method of the TabBarController delegate class fixed it...
Ah well, surely someone else will run into the same thing and hopefully this will help them...

Resources