My view hierarchy looks like this:
tab bar -> navigation bar -> table view -> view 1 -> view 2 (UIWebView)
How can I rotate view 2 so it can be displayed in both landscape & portrait mode?
Heres your fix...just solved the same problem. The issue is the tab bar controller is responding no to the shouldRotate method.
Ignore the advice in the apple docs and create a subclass for tab view controller. In that subclass handle the shouldRotate
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation
{
// Always returning YES means the view will rotate to accomodate any
orientation.
return YES; }
Heres my complete subclass
TSTabBarController.h
#import <Foundation/Foundation.h>
#interface TSTabBarController : UITabBarController {
}
#end
and the implementation file.
#import "TSTabBarController.h"
#implementation TSTabBarController
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
// Always returning YES means the view will rotate to accomodate any orientation.
return YES;
}
#end
If you change the class in IB for the tab bar controller you should just work.
Hope this helps.
Rich
Related
I am transiting my project to iOS7. I am facing a strange problem related to the translucent navigation bar.
I have a view controller and it has a tableview as subview (let's call it ControllerA) . I init a new uinavigationcontroller with the controllerA and present it modally using presentviewcontroller. The presented view controller's table view is blocked by the navigation bar. I set the automaticallyAdjustsScrollViewInsets to YES but the result did not change.
I knew I can set the edgesForExtendedLayout to UIRectEdgeNone, but it will make the navigation bar no more translucent.
After that, I tried to create a new view controller for testing. It contains almost the same elements. But the result is much different. The table view content does not get blocked.
Conclusion
Two View Controllers' automaticallyAdjustsScrollViewInsets set to YES
The project is not using storyboard
The first one is created at Xcode 4.6, The second one is newly created on Xcode 5
I have compared two classes xib and code, not much different
I have found the answer on apple developer forum.
There are two different case.
The first one, the view controller added is a UITableViewController.
And the issue should not be appeared since apple will auto padding it.
The second one, the view controller is NOT a UITableViewController.
And in the view hierarchy, it contains a UITableView. In this case, if the UITableview(or ScrollView) is the viewController's mainview or the first subview of the mainview, it will work. Otherwise, the view controller doesn't know which scroll view to padding and it will happen the issue.
In my case, the view controller is the second one. And there is a background image view as the first subview of the main view. So, it fails.
Here is the Apple developer forum link (need developer account to access):
https://devforums.apple.com/message/900138#900138
If you want the view to underlap the navigation bar, but also want it positioned so the top of the scrollview's content is positioned below the navigation bar by default, you can add a top inset manually once the view is laid out. This is essentially what the view layout system does when the top-level view is a scroll view.
-(void)viewDidLayoutSubviews {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
UIEdgeInsets currentInsets = self.scrollView.contentInset;
self.scrollView.contentInset = (UIEdgeInsets){
.top = self.topLayoutGuide.length,
.bottom = currentInsets.bottom,
.left = currentInsets.left,
.right = currentInsets.right
};
}
}
Based on Tony's answer I was able to get around this problem programatically with temporarily sending the table view to the back, let the adjustments be made and then send the background view back to the back. In my case there is no flickering to this approach.
In the View Controller:
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
[self.view sendSubviewToBack:self.tableView];
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
[self.view sendSubviewToBack:self.backgroundView];
}
Obviously if there are other subviews on self.view you may need to re-order those too.
There's probably too many answers on this already, but I had to take Christopher's solution and modify it slightly to support view resizing and allowing the content inset to be changed in a subclass of the UIViewController.
#interface MyViewController ()
#property (weak, nonatomic) IBOutlet UIScrollView *scrollView;
#property (assign, nonatomic) UIEdgeInsets scrollViewInitialContentInset;
#end
#implementation MyViewController
- (void)viewDidLoad {
[super viewDidLoad];
[self setScrollViewInitialContentInset:UIEdgeInsetsZero];
}
- (void)viewWillLayoutSubviews {
[super viewWillLayoutSubviews];
if (UIEdgeInsetsEqualToEdgeInsets([self scrollViewInitialContentInset], UIEdgeInsetsZero)) {
[self setScrollViewInitialContentInset:[self.scrollView contentInset]];
}
}
- (void)viewDidLayoutSubviews {
[super viewDidLayoutSubviews];
UIEdgeInsets scrollViewInset = [self scrollViewInitialContentInset];
if (UIEdgeInsetsEqualToEdgeInsets(scrollViewInset, UIEdgeInsetsZero) {
if ([self respondsToSelector:#selector(topLayoutGuide)]) {
scrollViewInset.top = [self.topLayoutGuide length];
}
if ([self respondsToSelector:#selector(bottomLayoutGuide)]) {
scrollViewInset.bottom = [self.bottomLayoutGuide length];
}
[self.scrollView setContentInset:scrollViewInset];
}
}
#end
To explain the point:
Any subclass of MyViewController can now modify the contentInset of scrollView in viewDidLoad and it will be respected. However, if the contentInset of scrollView is UIEdgeInsetsZero: it will be expanded to topLayoutGuide and bottomLayoutGuide.
#Christopher Pickslay solution in Swift 2:
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topInset = topLayoutGuide.length
inTableView.contentInset.top = topInset
inTableView.contentOffset.y = -topInset
inTableView.scrollIndicatorInsets.top = topInset
}
Yeah - a bit annoying.
I have a nib with a single tableview within the main view, not using autolayout. There is a tabbar, navigationbar and a statusbar and the app needs to work back to 5.0. In Interface builder that neat 'see it in iOS7 and iOS6.1 side-by-side' thing works, showing the tables neatly fitting (once the iOS6/7 deltas were set properly).
However running on a device or simulator there was a large gap at the top of the table, which was as a result of a content inset (which pretty much matched by iOS6/7 vertical delta) that was set to zero in the nib.
Only solution I got was in viewWillAppear to put in [_tableView setContentInset:UIEdgeInsetsZero].
Another ugly hack with a pretty on-screen result.....
[self.navigationController setNavigationBarHidden:YES animated:YES];
in:
- (void)viewDidLoad
when we do like this
self.navigationController.toolBarHidden = NO;
question : where does navigationController come from. I take a look at UIViewController.h but I can not find that property at all
Please advice me on this. Thanks
Look at the UINavigationControllerItem category on UIViewController (in UINavigationControler.h):
#interface UIViewController (UINavigationControllerItem)
#property(nonatomic,readonly,retain) UINavigationItem *navigationItem; // Created on-demand so that a view controller may customize its navigation appearance.
#property(nonatomic) BOOL hidesBottomBarWhenPushed; // If YES, then when this view controller is pushed into a controller hierarchy with a bottom bar (like a tab bar), the bottom bar will slide out. Default is NO.
#property(nonatomic,readonly,retain) UINavigationController *navigationController; // If this view controller has been pushed onto a navigation controller, return it.
#end
I am working on UISplitview base project.I have one problem regarding UISplitview.I want to hide masterDetailview (LeftSide view) in portrait mode form other UIview controller class .How can i do that ?
I declared UISplitviewcontroller in Appdelegate and create separate detail view class.
Try this link http://www.raywenderlich.com/1040/ipad-for-iphone-developers-101-uisplitview-tutorial you will get your answer.
or try this
- (BOOL)splitViewController:(UISplitViewController*)svc shouldHideViewController:(UIViewController *)vc
inOrientation:(UIInterfaceOrientation)orientation
{
return YES;
}
this for remove masterViewController
I have found quite a lot on this subject but I just can't figure it out. Any help would be massively appreciated!
I have an app set up with a UITabBarController. Within one of the tabs, I am showing a UITableView which is using a UINavigationController to allow for hierarchy. All the tables rotate just fine when the orientation is changed, until I get to what is effectively the final view in the hierarchy.
The final view is not a UITableView, just a basic UIView. But I can not get this page to rotate successfully! I have remade the view from with the absolute basics required and it still doesn't want to work! The code is below but it is currently pretty much a standard template with nothing in it now.
Also, I am not using InterfaceBuilder, and shouldAutorotateToInterfaceOrientation is on all views. This is the only one I am having problems with.
SomeView.h
#import <UIKit/UIKit.h>
#interface SomeView : UIViewController
{
NSString *someID;
NSString *someName;
}
#property(nonatomic,retain) NSString *someID;
#property(nonatomic,retain) NSString *someName;
#end
SomeView.m
#import "SomeView.h"
#import "AppDelegate.h"
#implementation SomeView
#synthesize someID, someName;
-(void)loadView
{
}
-(void)viewDidLoad
{
[super viewDidLoad];
}
-(void)viewDidUnload
{
[super viewDidUnload];
}
-(BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
{
return YES;
}
-(void)willAnimateRotationToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation duration:(NSTimeInterval)duration
{
NSLog(#"willAnimateRotationToInterfaceOrientation");
}
-(void)didReceiveMemoryWarning
{
[super didReceiveMemoryWarning];
}
-(void)dealloc
{
[super dealloc];
}
#end
UPDATE 10th Nov 2011
I'm still having this issue, however looking through documents and bits this seems to be my problem (http://developer.apple.com/library/ios/#qa/qa1688/_index.html)
The view controller's UIView property is embedded inside UIWindow but alongside an additional view controller.
You may find a situation where shouldAutorotateToInterfaceOrientation is called once at startup for a given view controller but is never called again when the device is rotated. Because view controllers are tightly bound to the views they manage, they are also part of the responder chain used to handle events. View controllers are themselves descendants of the UIResponder class and are inserted into the responder chain between the managed view and its superview. So it is common practice to have one primary view controller in your application as part of the responder chain. You would typically add one primary view controller such as a UINavigationController, UITabBarController or a generic UIViewController to your UIWindow. For example, this is done by calling:
[myWindow addSubview:primaryViewController.view];
If you add an additional view controller's UIView property to UIWindow (at the same level as your primary view controller) via the following:
[myWindow addSubview:anotherController.view];
this additional view controller will not receive rotation events and will never rotate. Only the first view controller added to UIWindow will rotate.
My UITabBarController stopped to autorotate, when I added a new navigationController to it with a tableViewController and didn't notice, that my custom navigation controller's shouldAutorotateToInterfaceOrientation returns YES only for one orientation. The solution is to check shouldAutorotateToInterfaceOrientation function in each Controller inside TabBarController.
May be it will help to somebody.
And I have figured it out...
I was looking at the code which pushes the UIViewController onto the stack and I had not fully initied the UIViewController.
I have made a subclass of TTPhotoViewController, wich when I Rotate iPhone also the current image is rotated but NOT The navigation bar and the toolbar (the bar with prev and next button).
In my subclass I have overide the shouldAutorotateToInterfaceOrientation: method:
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
return YES;
}
I've tried to overide willRotateToInterfaceOrientation:duration: e set up a breakpoint inside but seem that this method is never called.
Make sure all your view controllers i.e. Parent view controllers are allowing rotations.. most likely it is happening because one or more view controller is not returning TRUE for shouldAutorotateToInterfaceOrientation
I solved as follow:
TTPhotoViewController was within a TabBarController and by default TabBarController doesn't return YES for shouldAutorotateToInterfaceOrientation. So just subclass TabBarController and do something like that:
#implementation CustomTabBarController
- (BOOL)shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation) interfaceOrientation {
return [self.selectedViewController shouldAutorotateToInterfaceOrientation:interfaceOrientation];
}
#end
I add a small detail: in my firts attempt to rotate the interface i've found that the deviceOrientationDidChange: in TTScrollView.m was commeted out, this is done because if you decomment this code the scroll view have a strange behaviour on landascape rotation.