UINavigationBar gets cropped in landscape - ios

I am facing this situation where the navigation bar looks OK in portrait mode but gets cropped in landscape:
portrait
landscape
I subclassed UINavigationBar as follows:
class CustomNavigationBar: UINavigationBar {
override func sizeThatFits(size: CGSize) -> CGSize {
let newSize :CGSize = CGSize(width: self.frame.size.width, height: 64)
return newSize
}
}
and assigned it to the appropriate Navigation Controller via the StoryBoard:
but it makes no difference.
Any ideas?

Navigation bar has different height in Portrait and Landscape mode. You should handle content of custom title view according to navigation bar height. Use autolayout to auto adjust the subview when navigation bar's height changes.

I solved it by overriding sizeThatFits func in an extension. The idea is that it resets the size back to 44 which is the default for portrait:
// prevent navigation bars from resizing in landscape
extension UINavigationBar {
public override func sizeThatFits(size: CGSize) -> CGSize {
let portraitSize = CGSizeMake(UIScreen.mainScreen().bounds.width, 44)
return portraitSize
}
}

Related

Custom Navigation Bar height is not coming properly

[I have give the Navigation Bar height to 104 but navigation bar item is displaying only till height 44 ]
enter image description here
I cannot post code due to some reason.I am not allow to post the picture also.
My navigation bar item is not display to full height it only comes to up to 44.
For Navigation Bar:
enter code here
let nav = UINavigationbar();
nav.frame = CGRect(x:0,y:0,width:View.frame.width,height:104)
view.addsubview(nav)
Please forgive me for my poor English.
What you can do is to subclass UINavigationBar and use that
class HeightedNavigationBar: UINavigationBar {
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: 104)
}
}

Managing view frame when hide and unhide a tabbar

I have a UIViewController that has tab bar controller at bottom. When user click on a button I m hiding the tab bar. Tab bar is getting hidden but there is a white space at bottom. ViewController frame is not changing. How to manage this ? If tabor controller gets hidden, viewController height should get increase.
func apply(_ effect: ActivityFeedEffect) {
switch effect {
case .feedTypeChange(mode: let mode):
self.parent?.tabBarController?.tabBar.isHidden = mode == .hidden
}
}
This is an extension on UITabBarController, which you can use.
This basically, updates the frames of the view.
You can add animation and other frame handling if needed, based on your use case. But this is something that can lead you in that direction.
extension UITabBarController {
func hideTabBar(isHidden:Bool) {
if (isTabBarAlreadyHidden() == isHidden) { return }
let frame = self.tabBar.frame
let height = frame.size.height
let offsetY = (isHidden ? -height : height)
self.tabBar.frame.offsetBy(dx:0, dy:offsetY)
self.view.frame = CGRect(x:0,y:0,width: self.view.frame.width, height: self.view.frame.height + offsetY)
self.view.setNeedsDisplay()
self.view.layoutIfNeeded()
}
func isTabBarAlreadyHidden() ->Bool {
return self.tabBar.frame.origin.y < UIScreen.main.bounds.height
}
}
In my case, I have configured on the storyboard the extended Edges to go under bottom bars and under opaque bars (see image). So My view always takes the hole screen, and I don't need to adjust the frame. Maybe this helps.
My structure is Tab bar -> Navigation Controller -> TableView (here I hide/show the tab bar)

UISplitViewController: titleView in DetailViewController disappears on landscape orientation, intended behaviour?

I'm adding a custom titleView inside a navigation bar using navigationItem.titleView for both Master/Detail VC. On changing the orientation of the device to landscape, titleView under MasterViewController works fine, but for DetailViewController titleView disappears. On changing the orientation back to portrait titleView appears back for DetailViewController. I have also attached a link for source code and video.
Is this an intended behavior or am I making a mistake from my side or is it an issue from Apple's side ?
//Custom Title View:
class TitleView: UIView {
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: 50, height: 20)
}
}
class DetailViewController: UIViewController {
override func viewDidLoad() {
super.viewDidLoad()
//Adding titleView for Master/Detail VC:
navigationItem.titleView = {
//Setting frame size here, did not make any difference
let view = TitleView(frame: .zero)
view.backgroundColor = .red
return view
}()
}
}
Full source code here: https://github.com/avitron01/SplitViewControllerIssue/tree/master/MathMonsters
Video highlighting the issue:
https://vimeo.com/336288580
I had the same issue. It seems an iOS bug. My workaround was to reassign the title view on every view layout. I used this piece of code in my DetailViewController:
override func viewWillLayoutSubviews() {
super.viewWillLayoutSubviews()
if let v = navigationItem.titleView {
navigationItem.titleView = nil
navigationItem.titleView = v
}
}
For those who stumble upon this, see also iOS 11 navigationItem.titleView Width Not Set. Basically, there's two suggested workarounds:
use a custom UIView that tells iOS to treat its intrinsicContentSize to be as big as possible with UIView.layoutFittingExpandedSize
use widthAnchor/heightAnchor constraints to set width and height of your view

Increasing and Animating a Navigation Bar's height?

I subclassed UINavigationBar, and I have a button that drops down into a drop down menu. I wish to animate and push the contents below the navigation bar down as the navigation bar increases in height. Essentially I want a temporary table in the view of the navigationBar.
So far I overrode sizeThatFits() to return the custom sizes for the length I want, which is determined by a state enum. And I call sizeToFit() when the navigation bar needs to resize.
override func sizeThatFits(size: CGSize) -> CGSize {
let superSize = super.sizeThatFits(size)
var newSize: CGSize!
if(state == .Normal) {
newSize = CGSizeMake(superSize.width, superSize.height + heightIncrease)
} else if (state == .Menu) {
newSize = CGSizeMake(superSize.width, superSize.height + tableIncrease)
}
return newSize
}
func buttonPressed(){
if(state == .Normal){
state = .Menu
_delegate?.didChangeStateTo(.Menu)
} else if (state == .Menu){
state = .Normal
_delegate?.didChangeStateTo(.Normal)
}
UIView.animateWithDuration(0.3, animations: {
self.sizeToFit()
})
}
When I animate sizeToFit(), the navigation bar increases in size according to the animation, but the contents below the bar (the view of the viewController) immediately jumps down to the full length.
This is because sizeThatFits immediately returns the new CGSize. So the animation only works for the navigation bar itself, and the contents of the view do not follow the animation, but jump to their destination.
I tried avoiding using sizeThatFits, but UINavigationBar doesn't allow you to change the size of the bar simply by setting the frame with a CGRect.
I know there are other ways of going about this without playing around with subclassing UINavigationBar, but with my app's UI this way would be the most effective and code efficient.
Thanks in advance

Changing the height of UIToolbar in iOS 7

I am trying to change the height of my UIToolbar in a new iOS 7 project but I am not able to.
I am using a UINavigationController to manage a couple of UIViewController.
I tried setting the frame for the toolbar via the navigation controller but alas, the toolbar property is read-only.
I looked at "Is there a way to change the height of a UIToolbar?" but that did not work.
I tried subclassing UIToolbar, forcing a custom height and setting the right class in the Storyboard but that did not work neither, height keeps on being 44px.
I thought about auto-layout could not set any constraint on the size of the toolbar, every field is disabled.
I can set a custom view in a UIBarButtonItem with a bigger height than the toolbar. The big item will be correctly rendered but it will overflow from the toolbar.
This is the best I could do: screenshot
Is it actually possible to change the height of the UIToolbar in iOS 7?
Or am I supposed to create a bunch of custom items to mimic it?
Following the #Antoine suggestion using sizeThatFits, here is my Toolbar subclass with an height of 64:
import UIKit
class Toolbar: UIToolbar {
override func layoutSubviews() {
super.layoutSubviews()
frame.size.height = 64
}
override func sizeThatFits(size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
size.height = 64
return size
}
}
Then, when initializing the navigation controller, I say it should use that class:
let navigationController = UINavigationController(navigationBarClass: nil, toolbarClass: Toolbar.self)
The easiest way I found to set the toolbar height was to use a height constraint as follows:
let toolbarCustomHeight: CGFloat = 64
toolbar.heightAnchor.constraintEqualToConstant(toolbarCustomHeight).active = true
I've fixed this by subclassing UIToolbar and pasting the following code:
override func layoutSubviews() {
super.layoutSubviews()
var frame = self.bounds
frame.size.height = 52
self.frame = frame
}
override func sizeThatFits(size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
size.height = 52
return size
}
If you are using same height for all screens, this should do the trick
extension UIToolbar {
open override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: 60)
}
}
Although many solutions point in the right direction, they have either some layout issues or doesn't work properly. So, here's my solution:
Swift 3, custom UIToolbar subclass
class Toolbar: UIToolbar {
let height: CGFloat = 64
override func layoutSubviews() {
super.layoutSubviews()
var newBounds = self.bounds
newBounds.size.height = height
self.bounds = newBounds
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
var size = super.sizeThatFits(size)
size.height = height
return size
}
}
You can customize the height of your UIToolbar in iOS 7 with the following code. I have it tested and working in my current project.
- (void)viewWillAppear:(BOOL)animated {
[super viewWillAppear:animated];
// Make the Toolbar visible with this line OR check the "Shows Toolbar" option of your Navigation Controller in the Storyboard
[self.navigationController setToolbarHidden:NO];
CGFloat customToolbarHeight = 60;
[self.navigationController.toolbar setFrame:CGRectMake(0, self.view.frame.size.height - customToolbarHeight, self.view.frame.size.width, customToolbarHeight)];
}

Resources