iOS 7 UIWebView rotation to landscape orientation add some bar - objective-c

I have such situation, all screens in my application is in portrait mode, but I have one screen that could be in both orientations. On iOs 6 everything works fine but on iOS 7 when I rotate to landscape I am receive such situation as shown at the bottom. Big black bar at the bottom of screen.:
I want to make full screen and I have try self.edgesForExtendedLayout = UIRectEdgeNone; but it doesn't work for me.

try to remove the flag (use autolayout) in the interface builer document

My problem was with tab bar when I rotate my device, to solve that issue I have implement next code in my category that works with hiding and showing tab bar on rotation:
#implementation UITabBarController (HideBar)
- (void)showTabBar:(BOOL)show
{
UITabBar* tabBar = self.tabBar;
if (show != tabBar.hidden)
return;
UIView* subview = [self.view.subviews objectAtIndex:0];
CGRect frame = subview.frame;
frame.size.height += tabBar.frame.size.height * (show ? -1 : 1);
subview.frame = frame;
tabBar.hidden = !show;
}
I just add next code at the bottom of the method:
if (IOS_7) {
CGRect tabBarFrame = tabBar.frame;
tabBarFrame.size.height = show ? TABBAR_HEIGHT : 0;
tabBar.frame = tabBarFrame;
}

Related

Moving UIVIewController modal up when keyboard appears independent of rotation with iOS7

I just struggled quite a while with this, so will document it for others.
Here's the problem I was having. With an iPad app, supporting iOS7, I have a modal view controller that has a text field near the bottom the modal. Thus, when the keyboard appears, I wanted to move that modal up so the text field would still be visible with the keyboard present. With iOS8, this problem has a pretty clean solution (e.g., see Moving a modally presented UIViewController up when keyboard appears on iPad with iOS8). With iOS7 I was using self.myNavController.view.superview.center for repositioning, but ran into problems when trying to move the modal given the appearance of the keyboard. The coordinate CGPoint adjustments I was using would not move the modal in the right direction with all four rotations/orientations of the iPad.
The problem in part lies in how iOS7 does the rotation-- with transforms. However, I was unable to resolve the issue using CGPointApplyAffineTransform, or conversion of points using views (e.g., convertPoint:fromView:).
The solution I found to this problem involved a few steps:
1) I found it necessary to change the center of the modal (an assignment to self.myNavController.view.superview.center) relative to the center of the screen. I computed the center of the screen based on [UIScreen mainScreen].bounds.size. For some example code, I used the method screenCenter below.
// Adapted from: http://stackoverflow.com/questions/24150359/is-uiscreen-mainscreen-bounds-size-becoming-orientation-dependent-in-ios8
+ (CGSize) screenSize;
{
CGSize screenSize = [UIScreen mainScreen].bounds.size;
CGSize rotatedSize;
if ([UIDevice ios7OrEarlier] && [[SMRotation session] isLandscape]) {
rotatedSize = CGSizeMake(screenSize.height, screenSize.width);
}
else {
rotatedSize = screenSize;
}
return rotatedSize;
}
+ (CGPoint) screenCenter;
{
CGSize size = [self screenSize];
CGPoint center = CGPointMake(size.width/2.0, size.height/2);
return center;
}
2) Now, given that you have computed the amount that you have to shift the modal upwards (e.g., given the keyboard height and your modal height and the position of the text field on the modal), call this amount dy. I next found it necessary if the app was in an inverted rotation (upside down portrait or landscape), to change the sign of dy before applying it to the CGPoint center position I was calculating. Something like this:
CGPoint newCenter = [SMRotation screenCenter];
if ([SMRotation session].isInverted) {
dy = -dy;
}
newCenter.y += dy;
With some of the code for isInverted here:
- (BOOL) isInverted;
{
switch (self.interfaceOrientation) {
case UIInterfaceOrientationPortraitUpsideDown:
case UIInterfaceOrientationLandscapeRight:
return YES;
case UIInterfaceOrientationPortrait:
case UIInterfaceOrientationLandscapeLeft:
case UIInterfaceOrientationUnknown:
return NO;
}
}
3) Then, if the app was in landscape I found it necessary to swap the x and y coordinates. Something like this:
if ([SMRotation session].isLandscape) {
newCenter = CGPointMake(newCenter.y, newCenter.x);
}
4 Finally, I did the assignment to update the center of the modal:
self.myNavController.view.superview.center = newCenter;

iOS 8 Orientation change: Keyboard frame does not display correctly

This is only an iOS 8 problem, the keyboard displays correctly in iOS 7 with device orientation change. My application supports both portrait and landscape orientation and uses autolayout.
If I push a UIViewController subclass that contains a UITextField subclass onto a navigation stack and the UITextField becomes the first responder in portrait orientation then the default keyboard displays correctly. However, if I rotate the device to landscape orientation then the UIViewController subview layouts are displayed correctly but the keyboard is displayed in the top center of the screen. The keyboard's orientation is correct for landscape orientation but it's frame width is the same width as expected for portrait orientation. If I set the app orientation to only landscape orientation then the keyboard does not display correctly. This is only a problem for iOS 8 orientation change.
Prior to iOS 8, the keyboard's location and width/height were always relative to portrait orientation when reported to the app. (e.g. Landscape's keyboard width is in the y direction, ~352 pixels on an iPad.)
As of iOS 8, this has been updated to always have (0,0) at the top left of your (physical) view and the width/height reflect the x/y orientation you would normally expect outside of iOS. If you were previously positioning your keyboard via something like keyboardDidShow's [notification userInfo], you are going to get numbers that don't quite make sense. You can use something along these lines to take into account the pre-iOS8 idiosyncrasies:
- (void)keyboardDidShow: (NSNotification *) notification{
NSDictionary *keyboardInfo = [notification userInfo];
CGSize keyboardSize = [[keyboardInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
float height, width;
if(UIInterfaceOrientationIsPortrait(orientation)){
width = keyboardSize.width;
height = keyboardSize.height;
} else {
if (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1){
width = keyboardSize.height;
height = keyboardSize.width;
} else {
width = keyboardSize.width;
height = keyboardSize.height;
}
}
// Remainder of function
}
Which can be refactored down to...
- (void)keyboardDidShow: (NSNotification *) notification{
NSDictionary *keyboardInfo = [notification userInfo];
CGSize keyboardSize = [[keyboardInfo objectForKey:UIKeyboardFrameBeginUserInfoKey] CGRectValue].size;
UIInterfaceOrientation orientation = [[UIApplication sharedApplication] statusBarOrientation];
float width = keyboardSize.width;
float height = keyboardSize.height;
if(!UIInterfaceOrientationIsPortrait(orientation) && (floor(NSFoundationVersionNumber) <= NSFoundationVersionNumber_iOS_7_1)){
width = keyboardSize.height;
height = keyboardSize.width;
}
// Remainder of function
}
Also, the 8.1 update fixed several landscape/rotation bugs likely related to the above change. Grab the update and see if that solves your issue.
It is is not a bug of iOS8 or iPhone 6. It is problem of the correct migration of old projects to xCode6.
You simply need to add Launch screen interface file base name key to Info.plist file.
Detailed explanation of this case you can find here.

Tab Bar covers TableView cells in iOS7

I have a custom tableViewController that I'm adding to a TabBarController with
self.tabBarController.viewControllers = [NSArray arrayWithObjects:someOtherViewController, customTableViewController, nil];
self.tabBarController.selectedIndex = 1;
The issue I'm having is that the last 1.5 tableViewCells are being covered by the tab bar at the bottom of the screen on an iPhone 4 running iOS7. When I use the iOS Simulator - iPhone Retina (4-inch) / iOS 7.0 the issue still exists.
What is the correct way to make the tableView line up with the top of the tabBar at the bottom of the screen without using 'magic numbers'?
Try this for your CustomViewController:
- (void)viewDidLoad
{
[super viewDidLoad];
UIEdgeInsets adjustForTabbarInsets = UIEdgeInsetsMake(0, 0, CGRectGetHeight(self.tabBarController.tabBar.frame), 0);
self.scrollView.contentInset = adjustForTabbarInsets;
self.scrollView.scrollIndicatorInsets = adjustForTabbarInsets;
}
It's an iOS 8 solution but it may work on iOS 7 to: Go to storyboard > select table view controller > uncheck "Under Bottom Bars". That's it!
Setting the contentInset of your table view with a .bottom value of 49 points should correct this.
Under the right configurations, setting YES for the new UIViewController property on iOS 7 called automaticallyAdjustsScrollViewInsets should correct this, but (again) it depends upon a lot of other factors (view hierarchy, parent view controller's settings, et cetera).
The accepted answer doesn't quite work for me--my set up is a little different. I'm programatically creating my view controllers. My app's root is a tab bar controller, one tab is a navigation controller, whose root is a UIViewController with a table view as the main view.
What works for me though is when I manually computed the table view's height and set it in the frame when alloc-initing the table view. The general formula is:
screen height - (status bar height + nav bar height + tab bar height)
CGFloat bottom = self.tabBarController.tabBar.frame.size.height;
NSLog(#"%f",bottom);
[self.tableview setScrollIndicatorInsets:UIEdgeInsetsMake(0, 0, bottom, 0)];
self.tableview.contentInset = UIEdgeInsetsMake(0, 0, bottom, 0);
Embed your table controller in a navigation controller.
1. select the view in story board.
2. On menu bar select Editor -> embed in -> navigation controller.
Hope that helps
I have a similar view hierarchy to Matt Quiros: UITabBarController -> UINavigationController -> UIViewController -> UITableViewController (embedded as a subview of the UIViewController). The other answers didn't work in my case, and I had to set the table view's frame manually in the table view controller's viewWillAppear: method.
- (void)viewWillAppear:(BOOL)animated
{
[super viewWillAppear:animated];
// Adjust height of tableview (does not resize correctly in iOS 7)
CGRect tableViewFrame = self.tableView.frame;
tableViewFrame.size.height = [self heightForTableView];
self.tableView.frame = tableViewFrame;
}
- (CGFloat)heightForTableView
{
return CGRectGetHeight([[UIScreen mainScreen] bounds]) -
(CGRectGetHeight([[UIApplication sharedApplication] statusBarFrame]) +
CGRectGetHeight(self.navigationController.navigationBar.frame) +
CGRectGetHeight(self.tabBarController.tabBar.frame));
}
If anyone finds a better solution, please share!
I think this would work better for you:
After [super viewDidLoad];
try the following code:
if ([self respondsToSelector:#selector(edgesForExtendedLayout)])
self.edgesForExtendedLayout = UIRectEdgeNone;
You can also implement viewDidLayoutSubviews and use bottomLayoutGuide to get the height of the tab bar:
- (void)viewDidLayoutSubviews
{
[super viewDidLayoutSubviews];
CGFloat bottomOffset = self.bottomLayoutGuide.length;
self.tableView.contentInset = UIEdgeInsetsMake(0, 0, bottomOffset, 0);
}
Even though changing the contentInset of your table View is a working solution, I find it better to make sure your table view stops before the Tabbar.
As Paul Newman said, using the bottomLayoutGuide is a good thing, specially if you are using autolayout.
In My case adding a constraint to the bottom of the tableview linking to the top of the BottomLayoutGuide was a clean solution, this is an example with Storyboard, but it can be done in code as well.
Hope it helps.

Changing TabView: Resize TabView & Window

I made an application which have a preferences window with 2 tabs.
The first tab have a lots of prefs settings in it, but the second one is very small...
I'd like that the tabview & the window resize when we switch between these 2 tabs.
I act like that, but it doesn't seems to work, when I switch view the "Networks settings" tab is being reduced and disapear (like if the height was going from origin to 0 with animation).
Here is my code (.m):
- (void)tabView:(NSTabView *)tabView
didSelectTabViewItem:(NSTabViewItem *)tabViewItem
{
NSRect frame;
int height;
if ([[tabViewItem identifier] isEqualTo:#"Panel settings"]) {
height = 400;
} else if ([[tabViewItem identifier] isEqualTo:#"Network settings"]) {
height = 200;
}
frame = [[tabView window] frame];
frame.size.height = height;
frame.origin.y += height;
[[tabView window] setFrame:frame display:YES animate:YES];
}
Note that I linked the tab view to delegate.
My window is linked to the NSWindow * PrefWindow referencing outlet.
Thanks for your help!
I still think the problem is with the way your springs and struts are set in IB -- make sure you set them for not only for the tab view itself, but also for the individual objects in the view of the tab view item. I noticed that the default settings for my subviews had them all with the top strut set which made any subviews near the bottom of the view disappear when the window shrunk.

Scrollable UINavigationBar similar to Mobile Safari

My application uses a UINavigationController and the final view (detail view) lets you view an external website within the application using a UIWebView.
I'd like to free up some additional screen real estate when the user is viewing a webpage and wanted to emulate how Safari on iPhone works where their URL bar at the top scrolls up and off the screen when you're viewing content in the UIWebView that's below the fold.
Anyone have ideas on how to achieve this? If I set the navigationBarHidden property and roll my own custom bar at the top and set it and a UIWebView within a UIScrollView then there are scrolling issues in the UIWebView as it doesn't play nicely with other scrollable views.
Based on #Brian suggestion I made this code:
- (void)scrollViewDidScroll:(UIScrollView *)scrollView {
CGFloat height = navigationBar.frame.size.height;
CGFloat y = scrollView.bounds.origin.y;
if (y <= 0) {
CGRect frame = navigationBar.frame;
frame.origin.y = 0;
navigationBar.frame = frame;
} else if (tableView.contentSize.height > tableView.frame.size.height) {
CGFloat diff = height - y;
CGRect frame = navigationBar.frame;
frame.origin.y = -y;
navigationBar.frame = frame;
CGFloat origin = 0;
CGFloat h = height; // height of the tableHeaderView
if (diff > 0) {
origin = diff;
h = y;
}
frame = tableView.frame;
frame.origin.y = origin;
frame.size.height = tableView.superview.frame.size.height - origin;
tableView.frame = frame;
CGRect f = CGRectMake(0, 0, tableView.frame.size.width, h);
UILabel* label = [[UILabel alloc] initWithFrame:f];
tableView.tableHeaderView = label;
[label release];
}
}
My code has a UITableView but should work with any scrollable component. If you have other components than the navigationBar and the UIScrollView subclass, you should change the way the height of the scrollable component is calculated. Something like this:
frame.size.height = tableView.superview.frame.size.height - origin - otherComponentsHeight;
I needed to add a dumb tableHeaderView to have the desired behaviour. The problem was that when scrollViewDidScroll: is called the content has an offset, but the apparience in Mobile Safari is that the content is not scrolled until the navigationBar fully disappears. I tried first changing the contentOffset.y to 0, but obviously it didn't work since all the code relies on the scrolling mechanism. So I just added a tableHeaderView whose height is exactly the scrolled offset, so the header is never really seen, and the content appears to not scroll until the navigationBar fully disappears.
If you don't add the dumb tableHeaderView, then the scrollable component appears to scroll behind the navigationBar.
With the tableHeaderView, the scrollable component is actually scrolling (as seen in the scrollbar), but since there is a tableHeaderView whose height is exactly the same than the scrolled offset, the scrollable content appears to not be scrolling until the navigationBar fully disappears:
Have a delegate for the scrolling events in the UIWebView and when you initially start scrolling the UIWebView, have the UIWebView increase in height and have it's Y position decrease at the same time while simultaneously shifting the nav bar up in the Y direction. Once the nav bar has been completely shifted out of view, stop increasing the size of the UIWebView and just allow normal scrolling to occur.
This will give the illusion of the nav bar being part of the UIWebView as it scrolls off the screen.
Also, you'll need to do the reverse when you are scrolling in the opposite direction and are reaching the top of the content of the UIWebView.
Can't give you a straight answer, but have a look at iWebKit. Maybe that provides a solution. The demo, at least, contains a "full screen" item.