I'm having an issue where the gray overlay that's automatically put over my UISearchDisplayController when the keyboard is shown doesn't always fully cover the table area (you can see the white on the bottom in the picture below). This doesn't always happen but it's frequent enough that it's annoying. Anyone know what's going on? Thanks.
I believe this is a bug in Apple's code. Having worked extensively with UIPopoverControllers, I have found that there are many occasions in which a popover becomes confused as to whether or not it has a navigation bar when performing sizing calculations.
I am confident that if you measure the height of the white box you will find that it is exactly 37 pixels: the height of a navigation bar in a popover. (Navigation bars in popovers are not 44 pixels high like most navigation controllers since they are embedded into the popover's border.)
If you were able to access the gray overlay and manually resize it you could account for the height of the navigation bar or lack thereof. Unfortunately you are in a bit of a bind since the overlay is controlled by the search bar.
My suggestion would be to try to get the popover to recompute the size of its contents after it appears or is resized. I use this pattern when dynamically resizing a UIPopover containing a navigation bar when it appears:
// UIViewController subclass with a navigation bar which is displayed in a popover
// _popoverController is a (unretained) pointer to the UIPopoverController in which this view controller is displayed
- (void)viewDidLoad
{
[self.view sizeToFit];
CGSize newSize; // Dynamically computed based on popover contents
self.contentSizeForViewInPopover = newSize;
newSize.height += 37; // Account for popover navigation bar
[_popoverController setPopoverContentSize:size animated:YES];
}
I don't know how much this answer will help, but I hope it will at least give you a push in the right direction.
Have a look in this post: http://www.cannonade.net/blog.php?id=1498
He discusses the problem, providing a (called by himself) ugly workaround, but also says how to fix it!
Related
I'm having trouble using the space left behind by my hiding a UITabBar.
I have a UITabBarController with a UINavigationController, whose root view controller just has a UIWebView. I'm using auto-layout constraints to make the webview fill the view which works fine (and fills the available space) when I hide the navigation/status bars.
However, when I hide the tab bar (using setNavigationBarHidden), the tab bar is hidden but the space it vacates isn't used up by the webview, as expected.
Searching similar questions suggest using hidesBottomBarWhenPushed before pushing the view. I don't want to have to push another VC (or have to reload the webview) when rotating the device. Others suggest to resize the frame (like https://stackoverflow.com/a/1554637/1429412 ), but I have not been able to do that successfully.
What is the best way to hide the tab bar in one orientation, but not the other, and have a view fill the space vacated by the tab bar?
Portrait screenshot, showing UIWebview with a green background behind status/nav bar and tab bar as expected: http://i.stack.imgur.com/Hzj9k.png
Landscape screenshot showing hidden status/navbar and tab bar. The webview contents have extended to the top (navbar), but not so to the bottom (tab bar). However, the webview itself (the only element with a green background) has extended down just not its contents (regardless of length): http://i.stack.imgur.com/sdk75.png
If I examine the views at runtime (using FLEX), and click the viewable content area, it shows UIWeBrowserView view with shorter 271 height. Clicking the area where the tabbar space is shows _UIWebViewScrollView with the full 320 height. In code, I can see the UIWebView's .contentSize is only 568x271. I tried various combinations of setting the frame on the webview and its subviews, without success.
Right now, without any frame resizing hacks, the code is simply:
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration {
[[self navigationController] setNavigationBarHidden:UIInterfaceOrientationIsLandscape(toInterfaceOrientation) animated:YES];
[[UIApplication sharedApplication] setStatusBarHidden:UIInterfaceOrientationIsLandscape(toInterfaceOrientation) withAnimation:UIStatusBarAnimationSlide];
self.tabBarController.tabBar.hidden = UIInterfaceOrientationIsLandscape(toInterfaceOrientation);
}
I'm using xCode 6.1 for an iOS7+ project.
What should I do next? Thanks in advance for any pointers!
That is simply the way Tabbars are suppose to work, The only form of UIView that allows tab bors to be covered are modal views presentviewcontroller .... dismissviewcontroller Apple has a lot of samples just search for it.
My app has a view controller that due to the fact it plays its own custom transition animations, provides its own standalone UINavigationBar view at the top (As opposed to using a UINavigationController).
When using an iPhone, and when rotating the device, I would like the UINavigationBar to automatically apply the landscape UIBarMetrics properties (eg, change height, change the background image, resize the buttons etc), but by default, it does not. This is a problem on iOS 7, since even if I manually change the height of the UINavigationBar, the UIBarButtonItem elements don't change their vertical positions.
Is there a way to manually 'tell' the UINavigationBar to apply specific bar metric properties to itself? Or is that actually an implementation inside UINavigationController, and not UINavigationBar?
After various testing and trial and error after asking this question, I eventually worked out a solution that fixed all of my issues, so I'll post it here under the solution I'd previously accepted.
When my app is displayed in landscape on an iPhone, I wanted the UINavigationBar at the top to shrink to the standardly accepted 32 points high, as is the case with any apps that use the UINavigationController class. However, as I am not using a UINavigationController for this particular view (for varying reasons of feasibility), I needed to implement this manually.
To account for the new transparent status bar in iOS 7, I adjusted the origin and size of the UINavigationBar so it encompassed both the bounds of the status bar, and the normal UINavigationBar region (ie, so the UINavigationBar frame origin was {0,0}, and the height was 52 points.)
Unfortunately, this happened:
While the bar itself is rendering at the proper position and height, all of the content in the bar, including the title and buttons are not positioned properly, being much too high, almost touching the status bar content.
It was pretty obvious what was happening. The navigation bar content is being vertically aligned to its own middle, completely disregarding the presence of the status bar content.
When I tested the same orientations with a normal UINavigationController, this was not the case, and the title and buttons in the UINavigationBar from the UINavigationController worked absolutely fine. Apple had done SOMETHING in there that wasn't part of the normal UINavigationBar implementation.
Going on this, I picked apart the view layout hierarchy of a UINavigationControllerto see what was happening to the UINavigationBar in there (Mainly calling a lot of NSLog() statements that would dump the subviews of the navigation bar.)
This is what I discovered:
From the looks of it, Apple have employed a relatively sneaky hack to achieve this effect. It turns out the actual UINavigationBar is actually placed right below the status bar (ie at point {0,20}) and only has a height of 32 points. Then, what happens is a private subview inside the UINavigationBar in charge of rendering the background is extended upwards, outside of the bounds of the navigation bar to encompass the region behind the status bar (ie, its origin is {0, -20}, and its height is 52 points, local to the navigation bar's subview coordinate space).
So by doing that, not only does the content vertically align properly, but the translucent effect still extends behind the status bar.
Anyway, after I discovered this, it was pretty straightforward to write a solution. All I needed to do was reposition and resize the UINavigationBar back to how I had it iOS 6 (ie, 20 points down, and only 32 points high), and then implement a UINavigationBar subclass that override the layoutSubviews method, grabbed the internal background view (Doing a quick subview check for a view with a class name that matched "Background"), and then manually extended it.
The bar metrics properties you can set on a UINavigation bar are things like background image and the title vertical position. Heigh and width need to be set from within your view controller.
If you need to manually tell the navigation bar to change it's size when the orientation changes you can implement the method - (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation duration:(NSTimeInterval)duration1 in your view controller and change the size there.
Another option you can use is to use autolayout to specify that the width of your navigation bar is pinned to the left and right sides of its superview and let it figure out how wide it should be. For example
UINavigationBar *bar = [[UINavigationBar alloc] init];
bar.translatesAutoresizingMaskIntoConstraints = NO;
[self.view addSubview:bar];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"H:|[bar]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(bar)]];
[self.view addConstraints:[NSLayoutConstraint constraintsWithVisualFormat:#"V:|[bar(44)]|"
options:0
metrics:nil
views:NSDictionaryOfVariableBindings(bar)]];
I have several issues. Basically I want to rebuild this view:
While rebuilding this I m getting weird behaviors. Let's get started:
First my progress so far:
Device Screenshot:
My ViewControllers structure (Storyboard):
Well step by step:
Navigation Bar
I tried to make it transparent and I think it would normally work, but as you see in my structure I put a UIView over my background-imageview (Big profile picture) that simulate a alpha overlay. As you can see in my Device-Screenshot the Navigation Bar cuts of the overlay. So any idea how to fix that?
Code:
[self.navigationController.navigationBar setBackgroundImage:[UIImage new]
forBarMetrics:UIBarMetricsDefault];
self.navigationController.navigationBar.shadowImage = [UIImage new];
self.navigationController.navigationBar.translucent = YES;
self.navigationController.navigationBarHidden = NO;
View Positioning
As you can maybe see only the background-profile-image goes behind the Navigation Bar, but the rounded image and text-labels have the same top margin from the Navigation Bar. Shouldn't it be also effected by the translucency of the Navigation Bar? Any hints would be great.
Also the UIView that act also as alpha overlay don't go that much down to fill the image. Even I set all the exact same heights.
You can't see it on these images, but the View that contains all the counting labels overlaps the background-imageview (The background-imageview shouldn't even go that far down, very strange!).
You guys are my last hope. Else I have throw this awesome design ;(
Your dim view should be attached to the top of the superview and not the top layout guide.
You could post your constraints if you want more help.
Its looking good. You're almost there! The problem might be that you have a UIScrollView inside your view controller's view and that it is respecting the content insets applied by a navigation controller (assuming there is one because I spy a navigation item in your storyboard).
Try setting this on your view controller:
self.automaticallyAdjustsScrollViewInsets = NO;
I have a strange one that I can not seem to fix. I am currently working on updating my app to iOS7. This all worked in iOS6. It is an universal app and thus uses same xib files. However the iPad uses UISplitViews on some. Like I said, this all worked in iOS6 oh this all works on the iPhone too.
The problem is a grey bar at the bottom. I changed the tab bar to be opaque to move views up properly as i had some UI clipped to bottom of views and that went underneath the tab bar, sidetracked there. But if i set it back to translucent bar, it goes underneath but stretched properly. if i dont, it adds a bar. Other tabs work fine when NOT using splitview.
The UISplitviewController is added programmatically.
See attached image for better description.
This I have tried:
Added autoresize on splitview
Checked xib for subviews in the splitviews to have auto resize
Tried to force splitview to be screen bounds
Removed clips to bounds on all views
Removed autoresize subviews
Any ideas would be welcomed.
Thank you all.
UPDATE:
setting the background colour the uisplitview, it does colour the bar black. So the uisplitview is definitely stretching to it.
I subclassed UISplitViewController and added the line below to viewDidLoad and that fixed the grey line.
self.extendedLayoutIncludesOpaqueBars = YES;
I believe I have found an alternative solution for you. I have had the exact same problem, mostly because we are both doing something against Apple's Guidelines which is having a SplitViewController nested within a Tabbar controller (SplitView should be the root view). This was okay in iOS 5/6, but now in iOS 7 there are far too many side effects to achieve this.
The reason you see your view stretch completely when you set the bar to be translucent is because the bar is NOT taken into account when drawing the view. When you set translucent to false, it is then taken into account of the view and you will see that grey bar there because that's your view pretending there's a tabbar at the bottom of the screen.
And as always, a SplitViewcontroller's height cannot be changed, as it is determined by the visible window height.
I tried everything you did and then some. The real solution came from using a third-party Split View Controller.
I recommend switching over to https://github.com/mattgemmell/MGSplitViewController . This split view controller is actually one large View with container views living inside of it. Because of this, you avoid all the side effects of putting an actual split view controller within a tab bar.
If that doesn't float your boat, you could create your own solution which follows the same idea of having one UIViewController with two container views contained in it, though the people behind MGSplitViewController did a good job of that already.
This was the only way I was able to solve this issue, let me know if you find an alternative.
Instead of creating a subclass for UISplitViewController, I just added this code on my master's viewDidLoad:
self.splitViewController?.extendedLayoutIncludesOpaqueBars = true
For the controller that is the detail view of UISplitViewController you just do this:
-(UITabBarController*)tabBarController{
return nil;
}
How do I position this ViewController over the detail view modally? I want it to be right aligned so you can see the navigation portion greyed out.
[self.window addSubview:self.splitViewController.view];
MyModalViewController *modalvc= [MyModalViewController new]; //brevity
modalvc.modalInPopover = YES;
modalvc.modalPresentationStyle = UIModalPresentationStylePageSheet;
modalvc.view.autoresizeMask = UIViewAutoresizeFlexibleRightMargin;
[self.splitViewController presentModalView:modalvc animated:NO];
[self.window makeKeyAndVisible];
I also checked in MyModalViewController if im setting the views mask and I am not, nor is it getting magic values from a Nib.
Adjusting the frame before the present (using modalvc.view.frame) does nothing.
Adjusting the frame after the present seems to yield crazy results, and I only really need it to be half a width over in landscape... portrait is normal behavior.
edit
the picture confused people so I took it out, I dont want the modal view to be the size of the screen, I want to keep it UIModalPresentationStylePageSheet but have its ORIGIN moved right so that it covers the detail view portion in landscape
The modalPresentationStyle is what controls that. You've set it to UIModalPresentationStylePageSheet, which sets the height to the height of the screen, and the width to to the width of the screen in portrait orientation, exactly as in your screenshot.
I think the only way to get full width in landscape is to use UIModalPresentationFullScreen. See the UIViewController reference for more info.
I had a similar problem, and I ended up using a custom view controller that uses a background translucent view and a foreground opaque view that I am able to position anywhere I want by manipulating its frame. It's useful as a lightbox for videos and images.