UIViewController rotating problem - iphone

I have a TabbarController with different ViewControllers.
Some of these ViewControllers should autorotate and one ViewController should be presented only in PORTRAIT.
I fill the Tabbar with the following procedure:
ChartThemeViewController *chartViewController = [[ChartThemeViewController alloc]
initWithTheme:chartThemeDict];
UINavigationController *theNavigationController = [[UINavigationController alloc]
initWithRootViewController:chartViewController];
[chartViewController release];
[localViewControllersArray addObject:theNavigationController];
[theNavigationController release];
tabBarController.viewControllers = localViewControllersArray;
The ChartThemeViewController is a subclass of ThemeViewController.
ThemeViewController is a subclass of UIViewController.
If I override 'shouldAutorotateToInterfaceOrientation' in the subclasses of ThemeViewController, and return YES in all subclasses and return NO in ChartThemeViewController... it happens that all the ViewControllers don't autorotate.
mmmmhhh... hope you can understand this...
How can I solve this problem?
many thanks
jens

I believe the trick to selective autorotation within an instance of UITabBarController is as follows: Subclass UITabBarController and override the method -(BOOL)shouldAutorotateToInterfaceOrientation: with the following:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return [[self selectedViewController] shouldAutorotateToInterfaceOrientation:interfaceOrientation];
};
Now, if you select your portrait-only tab and rotate to landscape, the application will stay in portrait.
A new problem here, though, is as follows: select a tab that does support landscape; rotate to landscape; select a tab that only supports portrait. Uh oh. The portrait-only view controller is being displayed in landscape. Unfortunately, there is no way to force a view controller to a specific orientation.
You can look here for a description of the problem: How to force a screen orientation in specific view controllers?
As you can see, there is no real solution.
I would recommend disabling all tabs that do not support the current orientation. You can override -(void)didAutorotateToInterfaceOrientation: in your UITabBarController subclass with the following to achieve this:
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
UIInterfaceOrientation toInterfaceOrientation = [[UIApplication sharedApplication] statusBarOrientation];
NSArray *items = [[self tabBar] items];
for (NSUInteger i = 0; i < [items count]; i ++)
{
UITabBarItem *item = [items objectAtIndex:i];
if (![[[self viewControllers] objectAtIndex:i] shouldAutorotateToInterfaceOrientation:toInterfaceOrientation])
{
[item setEnabled:NO];
}
else
{
[item setEnabled:YES];
};
};
};
If you do not wish to do this, then consider altering your interface to be able to support the same orientations in all of your view controllers.
Hope this helps,
Ryan

Related

QLPreviewController NavigationBar setTranslucent property not working

i have set the custom color to navigation bar of QLPreviewController
but the problem is that i want dark color of navigation bar in QLPreviewController
even i have set the navigation bar translucent property to No
But i Dont know Why it is not working
I want it like belowed image
but it shows like this image
QLPreviewController *previewer = [[QLPreviewController alloc] init];
// Set data source
[previewer setDataSource:self];
[previewer setDelegate:self];
// Which item to preview
[previewer setCurrentPreviewItemIndex:index];
[previewer.view addGestureRecognizer:singleTap];
previewer.navigationController.navigationBar.translucent = NO;
previewer.navigationController.navigationBar.barTintColor = [UIColor redColor];
self.navigationController.navigationBar.translucent=NO;
self.navigationController.navigationBar.barTintColor = [UIColor redColor];
[self.navigationController pushViewController:previewer animated:TRUE ];
even i have also tried like this but it is also not working
- (id <QLPreviewItem>)previewController: (QLPreviewController *)controller previewItemAtIndex:(NSInteger)index
{
// Break the path into it's components (filename and extension)
// Use the filename (index 0) and the extension (index 1) to get path
//lblFileName.text=[strFileName stringByReplacingOccurrencesOfString:#"movefile" withString:#""];
// For navigation bar color and text attributes of navigation bar
for (id object in controller.childViewControllers)
{
if ([object isKindOfClass:[UINavigationController class]])
{
UINavigationController *navController = object;
navController.navigationBar.translucent=NO;
navController.navigationBar.barTintColor = [UIColor redColor];;
navController.toolbar.translucent=NO;
navController.toolbar.barTintColor=[UIColor redColor];;
[navController.navigationBar setTitleTextAttributes:[NSDictionary dictionaryWithObjectsAndKeys:[UIColor whiteColor], NSForegroundColorAttributeName, nil]];
}
}
NSString *strFilename=[[NSBundle mainBundle]pathForResource:#"final" ofType:#"png"];
return [NSURL fileURLWithPath:strFilename];
}
Please suggest me where i am going wrong
Thanks In Advance
The main problem is that when you try to set the translucency of the navigation bar, you haven't pushed the preview controller on the navigation stack yet.
At this point, the preview controller is allocated and instantiated, but its view has not been loaded or added to the view hierarchy, and the value of previewer.navigationController is nil. The value of self.navigationController is not nil at this point, but the translucency property you set here will be overwritten as a side effect of pushing the preview controller. The easiest way to get the effect you want, is to swap the order of the statements, like this:
[self.navigationController pushViewController:previewer animated:YES];
self.navigationController.navigationBar.translucent = NO;
Do note that with the translucency of the navigation bar set to NO, the previewed content will start under the navigation bar, which is probably not what you want. The easiest way to work around that issue, is to set the translucency property after the view of the preview controller has appeared on screen. You can do this by subclassing QLPreviewController:
#interface PreviewController : QLPreviewController
#end
#implementation PreviewController
- (void)viewDidAppear:(BOOL)animated
{
[super viewDidAppear:animated];
self.navigationController.navigationBar.translucent = NO;
}
Note that things get more complicated when you present the preview controller modally (rather than pushing it on a navigation stack). In that case, there is no navigation controller available to access the navigation bar and you need to rely on the internal view hierarchy of the QLPreviewController. The following code works in iOS7, but might break in a later version:
[self presentViewController:previewController animated:YES completion:^{
UIView *view = [[[previewController.view.subviews lastObject] subviews] lastObject];
if ([view isKindOfClass:[UINavigationBar class]])
{
((UINavigationBar *)view).translucent = NO;
}
}];
No need for subclassing. try this:
QLPreviewController * ql = [[QLPreviewController alloc] init];
...
[self showViewController:ql sender:self];
ql.navigationController.navigationBar.translucent = NO;
ql.edgesForExtendedLayout = UIRectEdgeNone;
If you want to present it modally, just put the previewController into a navigationController:
UINavigationController * navi = [[UINavigationController alloc] initWithRootViewController:ql];
ql.navigationController.navigationBar.translucent = NO;
ql.edgesForExtendedLayout = UIRectEdgeNone;
[self presentViewController:navi animated:YES completion:nil];
Instead of using QLPreviewController,y don't you use webview to load the pdf.But if you load pdf in webview you need to customise the buttons thats it.Its also look very similar to QLPreviewController.
NSURL *targetURL = [NSURL fileURLWithPath:path_pdf]; //path_pdf is pdf's path
NSURLRequest *request = [NSURLRequest requestWithURL:targetURL];
[webview_pdf loadRequest:request];
Well,try it once.
If Still, anyone wants to customize the Navigation bar of QLPreviewController then they can try creating a UIViewController and customize it as per requirement and then create QLPreviewController object and add it as a child view controller.
This will allow you to get rid of share button and you customize navigation bar color etc. this is working for me.
To know, how to add child view controller you can refer to this

How to hold NavigationController in subViewController orientation?

I have made a NavigationController structure.
FirstViewController is RootViewController, SecondViewController is a next SubViewController. Each ViewController shouldAutorotateToInterfaceOrientation is a different(refer a following code).
FirstViewController is only portrait available. SecondViewController all support Portrait and landscapeMode.
In FirstViewController after sth button touch, call a pushHandler. next SecondViewController is a pushed.
In SecondViewController after rotated landscape back to the FirstViewController, that orientation is too landscape.
but, I implemented each ViewController orientation different. however each ViewController not independently set orientation. why happen?
How can I viewcontroller each orientation can be set independently, to do?
If SecondViewController change the orientation of the landscapeMode. I want back to the FirstViewController still portraitMode(forever hold portraitState Anything not to be affected).
How do I implements programmatically?
FirstViewController *rootViewController = [FirstViewController alloc] init];
UINavigationController *MyNavigationController = [UINavigationController alloc] initWithRootViewController:rootViewController]];
//FirstViewController
- (void)pushHandler
{
SecondViewController *subViewController = [SecondViewController alloc] init];
[[self navigationController] pushViewController:subViewController animated:YES];
[subViewController release];
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return (interfaceOrientation == UIInterfaceOrientationPortrait);
}
//SecondViewController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
return YES;
}
Because you use a UINavigationController for all your UIViewControllers whatever orientation behaviour you will set for the UINavigationController will be applied to all it's children or in otherwords objects on its stack.
Think of a UINavigationController as a house and UIViewControllers as rooms. All the rooms in the house will rotate in the same way the house. There is no way to turn a room without turning the house and other rooms.
But as always there are tricks. Look at my answer to this question Only having one view autorotate in xcode?

How to enable landscape orientation in a Tab Bar + NavigationControllers app?

I'm programmatically creating a tab bar based app. In the application:didFinishLaunchingWithOptions (app delegate) method I've put:
self.tabBarController = [[[UITabBarController alloc] init] autorelease];
SearchViewController *search_vc = [[[SearchViewController alloc] init] autorelease];
SearchBookmarksViewController *search_bookmarks_vc = [[[SearchBookmarksViewController alloc] init] autorelease];
ItemsBookmarksViewController *items_bookmarks_vc = [[[ItemsBookmarksViewController alloc] init] autorelease];
AboutUsViewController *aboutus_vc = [[[AboutUsViewController alloc] init] autorelease];
UINavigationController *search_nav = [[[UINavigationController alloc] initWithRootViewController:search_vc] autorelease];
UINavigationController *search_bookmarks_nav = [[[UINavigationController alloc] initWithRootViewController:search_bookmarks_vc] autorelease];
UINavigationController *items_bookmarks_nav = [[[UINavigationController alloc] initWithRootViewController:items_bookmarks_vc] autorelease];
UINavigationController *aboutus_nav = [[[UINavigationController alloc] initWithRootViewController:aboutus_vc] autorelease];
NSArray vc_stack = [NSArray arrayWithObjects:search_nav,search_bookmarks_nav,items_bookmarks_nav,aboutus_vc,nil];
tabBarController.viewControllers = vc_stack;
[self.window addSubview:tabBarController.view];
SearchViewController is basically a search form showing results in a UItableView with rows which when selected show details about the chosen row. User can also press a "View Photos" button that push a view controller with a UIImageView to show some photos.
Now when working on the photo view I had to handle landscape orientation which seems not working easily in tab bar applications. Can you help about what to do exactly to allow this photo view controllers to handle landscape orientation ?
I've been told to make shouldAutorotateToInterfaceOrientation method to return YES in every view controller thus making any view to allow landscape orientation OR to subclass TabBarController and this last solution could cause my app to be rejected by Apple. So I'm a bit confuse about what to do exactly...
Thx in advance for your help!
Stephane
Its very simple you just have to make :-
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
for your each and every ViewController.
I've used both of the options you mention.
make shouldAutorotateToInterfaceOrientation method to return YES in every instanced/subclassed view controller: For this to work you need to make sure that every single view controller has its shouldAutorotateToInterfaceOrientation method to return YES. One option is to CMD+Shift+F to search in the whole project for ": UIViewController", this will show you a list of all the headers files that are inheriting from UIViewController, so set shouldAutorotateToInterfaceOrientation to YES in every implementation file corresponding to this headers. (This because sometimes you may've included a third party code that has some classes that inherits from UIViewController and that you omit to set shouldAutorotateToInterfaceOrientation to YES there)
subclass TabBarController: Apple documentation says that "This class is not intended for subclassing." so it would be better to avoid this option, I have used and it works, but you will always has the possibility of been rejected by Apple. (Maybe not the first time, but on any upgrade)
Anyway, I think Apple doesn't encourage tabbar applications to be displayed in landscape mode because tab bar took a lot of the space on the screen. So it would be better to consider the architecture of your application to see if a tabbarcontroller is really needed or create your own tabbarcontroller control like Twitter app on iPhone. This way you can reduce the height of the tab bar when in lanscape.
In addition to enabling rotation in each of the subview controllers (which is enabled by default if you're developing in ios5), if you want to take over the whole screen do something like:
UIInterfaceOrientation toOrientation = self.interfaceOrientation;
if (self.tabBarController.view.subviews.count >= 2 )
{
UIView *transView = [self.tabBarController.view.subviews objectAtIndex:0];
UIView *tabBar = [self.tabBarController.view.subviews objectAtIndex:1];
if(toOrientation == UIInterfaceOrientationLandscapeLeft || toOrientation == UIInterfaceOrientationLandscapeRight) {
transView.frame = CGRectMake(0, 0, 568, 320);
self.portraitView.hidden = YES;
self.landscapeView.hidden = NO;
tabBar.hidden = TRUE;
self.wantsFullScreenLayout = YES;
}
else
{
//Designing to accomodate the largest possible screen on an iPhone. The structs and springs should be setup so that the view will remain consistent from portrait to landscape and back to portrait.
transView.frame = CGRectMake(0, 0, 320, 568);
tabBar.hidden = FALSE;
self.portraitView.hidden = NO;
self.landscapeView.hidden = YES;
self.wantsFullScreenLayout = NO;
}
}`
UPDATE:
https://stackoverflow.com/a/13523577/1807026

iPhone rotating view in navigationViewController mode

hours ago I post a question on organizing portrait and landscape mode in iPhone and now I think I know how to do it using willRotateToInterfaceOrientation:duration.
The first screen is 'Map View' with one button that leads to 'Setting View'. The Map View does not support rotate but for the Setting View I made separate view for portrait and landscape and they swap accordingly when rotated.
, ,
As you can see when Setting button pressed SettingView is added on the view stack as usual. So basically I use three view controllers; Setting, SettingLandscape and SettingPortrait.
I still found problem in rotating view in iPhone when I use navigationViewController. Segmented control is not working. it crashes without error message. It used to working fine without rotation.- when I'm not using multiple view for rotation-.
rotateViewController.m
This is root view controller.
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
-(IBAction) buttonPressed{
Setting *settingViewController = [[Setting alloc] initWithNibName:#"Setting" bundle:[NSBundle mainBundle]];
UINavigationController *navController1 = [[UINavigationController alloc] initWithRootViewController: settingViewController];
[self.navigationController presentModalViewController:navController1 animated:YES];
[settingViewController release];
[navController1 release];
}
Setting.m
This view controller does nothing but swap views when rotate and shows appropriate view between portrait and landscape.
In Setting.m, I swap view as follow;
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (toInterfaceOrientation==UIInterfaceOrientationLandscapeRight) {
NSLog(#"to Right");
SettingLandscape *setting_landscape = [[SettingLandscape alloc] initWithNibName:#"SettingLandscape" bundle:[NSBundle mainBundle]];
self.view = setting_landscape.view;
[setting_landscape release];
}
if (toInterfaceOrientation==UIInterfaceOrientationLandscapeLeft) {
NSLog(#"to Left");
SettingLandscape *setting_landscape = [[SettingLandscape alloc] initWithNibName:#"SettingLandscape" bundle:[NSBundle mainBundle]];
self.view = setting_landscape.view;
[setting_landscape release];
}
if (toInterfaceOrientation==UIInterfaceOrientationPortrait) {
NSLog(#"to Portrait");
SettingPortrait *settingportrait = [[SettingPortrait alloc] initWithNibName:#"SettingPortrait" bundle:[NSBundle mainBundle]];
self.view = settingportrait.view;
[settingportrait release];
}
if (toInterfaceOrientation==UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"to PortraitUpsideDown");
SettingPortrait *settingportrait = [[SettingPortrait alloc] initWithNibName:#"SettingPortrait" bundle:[NSBundle mainBundle]];
self.view = settingportrait.view;
[settingportrait release];
}
}
In viewWillAppear, Setting view controller also has ;
self.title = #"Shell ";
self.navigationController.navigationBarHidden = NO;
self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Done" style:UIBarButtonItemStylePlain target:self action:#selector(Done)] autorelease];
and Done is
- (void) Done{
[self dismissModalViewControllerAnimated:YES];
}
SettingLandscape.m
This view stacked on when the view is rotated. This view controller has it's navigation bar.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
self.title = #"Setting Landscape";
}
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
in viewDidLoad;
- (void)viewDidLoad {
[super viewDidLoad];
NSLog(#"landscape:viewDidLoad");
//self.title = #"SettingLandscape";//not working!!
//self.navigationItem.leftBarButtonItem = [[[UIBarButtonItem alloc] initWithTitle:#"Done1" style:UIBarButtonItemStylePlain target:self action:#selector(Done)] autorelease];
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
stringflag4MapType = [[NSString alloc] initWithString:#"blah"];
stringflag4MapType = [defaults stringForKey:#"flag4MapType"];
if (![stringflag4MapType isEqualToString:#"Hybrid"] && ![stringflag4MapType isEqualToString:#"Standard"] && ![stringflag4MapType isEqualToString:#"Satellite"]) {
segmentedControl4MapType.selectedSegmentIndex = 0;
}else if ([self.stringflag4MapType isEqualToString:#"Standard"]) {
segmentedControl4MapType.selectedSegmentIndex = 0;
}else if ([self.stringflag4MapType isEqualToString:#"Satellite"]) {
segmentedControl4MapType.selectedSegmentIndex = 1;
}else if ([self.stringflag4MapType isEqualToString:#"Hybrid"]) {
segmentedControl4MapType.selectedSegmentIndex = 2;
}
and following call does not get invoked. strange. doesn't matter rotation works anyway.
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
if (toInterfaceOrientation==UIInterfaceOrientationPortrait) {
NSLog(#"to Portrait");// does not print out.
SettingPortrait *settingportrait = [[SettingPortrait alloc] initWithNibName:#"SettingPortrait" bundle:[NSBundle mainBundle]];
self.view = settingportrait.view;
[settingportrait release];
}
if (toInterfaceOrientation==UIInterfaceOrientationPortraitUpsideDown) {
NSLog(#"to PortraitUpsideDown");
SettingPortrait *settingportrait = [[SettingPortrait alloc] initWithNibName:#"SettingPortrait" bundle:[NSBundle mainBundle]];
self.view = settingportrait.view;
[settingportrait release];
}
}
ok now, as you can see from those snap shots there are two navigation bar and each has its bar button, Done and Item. The Done button came from Setting and the Item button from SettingPortrait or SettingLandscape. All button's selector is same, that leads back to map view. The button Done works fine, but the button Item crashes. I need a button on navigation bar after rotation that acts like back button . I guess once I did 'self.view = settingportrait.view;' the problem starts.
The reason why I need the Item button work is that the segmented control started crashing once I add code to support rotation. If I found reason how to make the Item button-that is inside rotation view- work I think I can make the segmented control work as well.
You can download the whole code at https://github.com/downloads/bicbac/rotation-test/rotate-1.zip
https://github.com/downloads/bicbac/rotation-test/rotate-1.zip
this sample code is amazing for me. It solve my problem of rotating view just by simple delegate method
(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
my best attempt to answer question without looking at code (don't have time tonight :( )
When you present setting viewcontroller modally, your top viewcontroller is setting.
When rotation happens, you load setting_landscape or setting_portrait viewcontroller, but only retain the view inside setting_landscape|portrait. Thus, setting_landscape/portrait viewcontrollers are released. When device is rotated, it's probably "setting" viewcontroller receiving rotation message, not the "setting_landscape/portrait" viewcontroller because they are not pushed on to the viewcontroller stack.
So, when you click on item or segment control, it will call delegate, which is probably set to setting_landscape|portrait which is released already.
What is the message in console you get with crash?
My recommendation would be to build setting viewcontroller with segmented control, then use "willAnimateRotationToInterfaceOrientation:duration:" function to reposition the segmented control to the right position and frame. Just by returning YES to all orientation, rotation should be supported, doesn't it?
What was the reason for using two separate viewcontroller for landscape/portrait? (I do this sometimes, but rarely)
Edit* you need to use "willAnimateRotationToInterfaceOrientation" callback to animate the changes, not "willRotate..."

Orientation issues with Tab Bar Controller In WebView

I am new to iphone development. In my app, i am using number of viewControllers, web view, Tool bar, Tab Bar and so on. Here, i want to achieve orientation(portrait or landscape or vice versa) corresponding device view in all the web views. I could achieve orientation in all web views except those web views are coming under the tab bar controller web view(it may be an one of tab bar view controller or sub view of tab bar controller view).
Here i adding web view by using below code,
contentView = [[UIView alloc] initWithFrame:[[UIScreen mainScreen] applicationFrame]];
contentView.autoresizingMask = (UIViewAutoresizingFlexibleWidth | UIViewAutoresizingFlexibleHeight);
self.view = contentView;
self.view.autoresizesSubviews = YES;
CGRect webFrame = [[UIScreen mainScreen] applicationFrame];
webFrame.origin.y -= 20.0;
webView1 = [[UIWebView alloc] initWithFrame:webFrame];
[contentView addSubview:webView1];
and using below methods for achieving orientation,
- (BOOL) shouldAutorotateToInterfaceOrientation: (UIInterfaceOrientation) orientation
{
return YES;
}
- (void)didRotateFromInterfaceOrientation:(UIInterfaceOrientation)fromInterfaceOrientation
{
if(fromInterfaceOrientation == UIInterfaceOrientationPortrait){
[webView1 stringByEvaluatingJavaScriptFromString:#"rotate(0)"];
}
else
{
[webView1 stringByEvaluatingJavaScriptFromString:#"rotate(1)"];
}
}
please any one give soln!
Ok lets try this:
Step 1: Crate a custom class for TabBarController class as:
#interface CustomTabBarController : UITabBarController {
}
#end
In CustomTabBarController.m write
`#import "CustomTabBarController.h"
#implementation CustomTabBarController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Always returning YES means the view will rotate to accomodate any orientation.
return YES;
}
#end
Step 2: On appDelegate write this:
Change UITabBarController "CustomTabBarController"
and change it class reference in Interface builder to CustomTabBarController