Get the default height (or maxY) of a NavigationBar on iOS - ios

I would like to know if is there any way for us to obtain the default Navigation Bar height (maxY preferably) of a NavigationController.
Knowing that iOS 11 introduced large titles, is there any way for us then to get the default height (or maxY) of a Navigation Bar with a "small title" and of a Navigation Bar with a "large title"?
The reason I am asking this is because I am making the Navigation Bar's background transparent and introducing my own background to it (which is an Effect View). But the problem I am having is that every time I run the following code
self.navigationController?.navigationBar.frame.maxY
it returns a number ways higher than the expected :/
I tried to run this piece of code on many callbacks -> onViewWillAppear, onViewDidAppear, onViewDidLoad

You can get the height of navigation bar and status bar using this
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let topSpace:CGFloat?
if #available(iOS 11.0, *) {
topSpace = self.view.safeAreaInsets.top
} else {
topSpace = self.topLayoutGuide.length
}
print(topSpace)
}

I have used the native method to get the height of navigation bar including status bar. Use this line of code to get the navigation bar height and use as per your requirement. This worked for me perfectly fine on all devices & different iOS versions.
let navigationBarHeight = UIApplication.shared.statusBarFrame.size.height +
(self.navigationController?.navigationBar.frame.height ?? 0.0)

The best approach I found so far, without having to create a navigation controller instance:
[self.navigationBar sizeThatFits:CGSizeZero].height;
And just to mention, it supports screen orientation change too.

This works for me
let navigationBarHeight = UIApplication.shared.statusBarFrame.size.height +
(self.navigationController?.navigationBar.frame.height ?? 0.0)
Even tough your method may be the best solution for you I mostly try to not use the native navigation bar but hide it and create my own instead. This makes it easier to use custom and more advanced designs in the application.

Related

Xamarin iOS large tittle scroll velocity snapping issue

I am using Xamarin.Forms version 5.0 to develop an app for iOS 15. I am struggling to smooth the large title scroll transition. My problem is outlined on this question: iOS 11 large navigation bar title unexpected velocity
According to the above link, It seems like a fairly simple solution on Swift but I am struggling to do this using Xamarin.iOS.
Using a custom renderer, I have the following settings:
ExtendedLayoutIncludesOpaqueBars = True;
EdgesForExtendedLayout = UIRectEdge.Top;
AutomaticallyAdjustsScrollViewInsets = true;
NavigationController.NavigationBar.PrefersLargeTitles = true;
NavigationItem.LargeTitleDisplayMode = UINavigationItemLargeTitleDisplayMode.Automatic;
NavigationController.NavigationBar.Translucent = true;
I have tried modifying the constraints of my ScrollView by setting them to the constraints of the View. View.Superview is null for this page and would not allow me to change those constraints.
I have tried all sorts of different combinations of settings.
I have tried changing my ScrollView to a TableView.
I know I could make a custom navigation bar that could simulate this transition but I am trying to use native iOS settings and UI designs.
One of the answers on this question suggest the only way to get the smooth scroll transition is to use a UITableViewController instead of a UIViewController with a UITableView inside. Is this possible on Xamarin? I haven't found a way to use UITableViewController when designing the UI in Xaml. Even if I can change to a UITableViewController, will I be able to set the constraints correctly in the renderer?
Are there any other things I should try?
Thank you for any responses.
Try to find the ScrollView and change its constraints .
[assembly: ExportRenderer(typeof(ContentPage), typeof(MyBarRenderer))]
namespace FormsApp.iOS
{
internal class MyBarRenderer : PageRenderer
{
public override void ViewDidLoad()
{
base.ViewDidLoad();
ExtendedLayoutIncludesOpaqueBars = true;
foreach (UIView view in View.Subviews)
{
if (view is UIScrollView sc)
{
NSLayoutConstraint.ActivateConstraints(new NSLayoutConstraint[] {
sc.TopAnchor.ConstraintEqualTo(View.TopAnchor),
sc.LeftAnchor.ConstraintEqualTo(View.LeftAnchor),
sc.BottomAnchor.ConstraintEqualTo(View.BottomAnchor),
sc.RightAnchor.ConstraintEqualTo(View.RightAnchor),
});
}
}
}
}
}
Refer to
iOS 11 large title navigation bar snaps instead of smooth transition

Search bar as header in tableview - appear and disappear

I need to put a search bar at the top of my tableview. I am making a network call and when the results are greater than 100 I want to search bar to appear and when they are less than 100 I don't want to search bar to appear. The tableview is on the right side of the VC and does not take up the whole view controller. I want the search bar to be at the top of the table view as a header.
I cannot use a search controller because in iOS 11, using a search controller makes the search bar pop to the top of the VC when it is active.
I tried to set the tableviewheader to nil to get it to disappear. But I can't get it back obviously because I made the header nil.
self.rightDetailFilterTableView.tableHeaderView = nil
self.rightDetailFilterTableView.sectionHeaderHeight = 0
I have put the search bar into the storyboard as seen in the image below. Is this the right way to add the search bar as a header?
What is the best way to get it to appear and disappear in the tableview? I have tried a bunch of different methods. They all either leave a blank header or do something else that causes problems. I also tried using the header delegate methods but that still did not work.
I am not using a tableview controller, I am using a normal VC. I am also not using a search bar controller because of issues it causes in iOS 11.
Here's what I've done in one of my recent project. First, laid out my views like so:
That is, the Search Bar was added to the parent view rather than the table view. This allows me to hide/show it as needed.
Next, I've defined two optional layout constraint, one ensuring that the tableview is aligned to the top of the safe area, priority 750; the other aligning the top of the search bar to the top of the safe area; priority lower than 750 to hide it below the nav bar or priority higher than 750 to reveal it and push the table view down.
In code, I created a #IBOutlet to the layout constraint for the search bar to the top of the safe area, and I change its priority as needed:
#IBAction
func toggleSearchBar(_ sender: Any?) {
if searchBarVisibleLayoutConstraint.priority.rawValue > 750.0 {
searchBarVisibleLayoutConstraint.priority = UILayoutPriority(rawValue: 1.0)
searchBar?.endEditing(true)
} else {
searchBarVisibleLayoutConstraint.priority = UILayoutPriority(rawValue: 999.0)
}
UIView.animate(withDuration: 0.3) {
self.view.layoutIfNeeded()
}
}
In my case, the navigation bar is opaque and the search bar is not visible behind it. Your case may be different so you may also want to either clip the parent view or alpha fade the search bar when it is not visible.
Good luck!
Please check :
Created IBOutlet for my SearchBar.
#IBOutlet weak var testbar: UISearchBar!
And in my viewDidLoad :
override func viewDidLoad() {
var contentOffset = tableView.contentOffset
let showSearchBar = (results.count > 100)
self.tableView.tableHeaderView?.isHidden = !(showSearchBar)
if showSearchBar {
contentOffset.y -= testbar.frame.size.height
} else {
contentOffset.y += testbar.frame.size.height
}
tableView.contentOffset = contentOffset
}
Here is my tableview storyboard

What is the top bar height of iPhone X?

I would like to know exact height of top bar of iPhone X.
Could you please mention the status bar and navigation bar height of iPhone X.
Please help me.
The display on iPhone X, however, is 145pt taller than a 4.7" display, resulting in roughly 20% additional vertical space for content.
for more information you get HIG for iphone X from apple documents and detail description in here1 and here2
status bar height
previously 20pt, now 44pt
Because of the sensors on top of the display, the new status bar is split in 2 parts. If your UI is doing something special with that space (previously 20pt high, now 44pt), because it will be taller on the iPhone X. Make sure that it can be dynamically changed in height. A great thing is that the height won’t be changed if a user makes a phone call or is using a navigation app, which was previously the case on other iPhones.
portrait
Navigation bar height as normal 88 and large title time 140
Standard title - 44pt (88pt with Status Bar)
Large title - 140pt
bottom bar - 34pt
Landscape
Standard title - 32pt
bottom bar - 21pt
Nav bar is 44pt as usual (when no large titles) and the status bar has increased from 20pt to 44pt. Here's what you can type in the debugger to verify it:
You can programmatically obtain the navigation bar's height by using safeAreaInsets on the view in the contained view controller:
let navBarHeight = view.safeAreaInsets.top
This will account for whether it's a large title navigation bar or not, and whether or not there's a search bar attached to it.
See the safeAreaInsets documentation for more information.
You can simply get it in the next way (Swift 3):
let barHeight = navigationController?.navigationBar.frame.maxY
To get correct value make sure that you call it after setting prefersLargeTitles
navigationController?.navigationBar.prefersLargeTitles = false
You can use the navigation bar's .frame property to figure out the overall height of the top bar area:
Swift 5.0:
let xBarHeight = (self.navigationController?.navigationBar.frame.size.height ?? 0.0) + (self.navigationController?.navigationBar.frame.origin.y ?? 0.0)
ObjC:
CGRect navbarFrame = self.navigationController.navigationBar.frame;
float topWidth = navbarFrame.size.width;
float topHeight = navbarFrame.size.height + navbarFrame.origin.y;
I suppose this is a bit of a cheat, but adding the navbar's height with its y origin seems to give the correct total height regardless of device.
There is no specification in Apple Docs
Apple Docs
According to Geoff Hackworth its 88
Navigation title types :
Standard title
Large title
Increasing navigation bar in iOS 11
navigationController?.navigationBar.prefersLargeTitles = true
If you're using a UIWindow and you need to know the top bar height you can use this:
// old way of getting keyWindow
//guard let keyWindow = UIApplication.shared.keyWindow else { return }
// new way of getting keyWindow
guard let keyWindow = UIApplication.shared.windows.first(where: { $0.isKeyWindow }) else { return }
let navBarHeight = keyWindow.safeAreaInsets.top
print("navBarHeight:" , navBarHeight)
I got the idea from #Paolo's answer
Use it if you want to know where need start content
extension UIViewController {
var navigationBarbarContentStart: CGFloat {
return self.navigationBarTopOffset + self.navigationBarHeight
}
var navigationBarTopOffset: CGFloat {
return self.navigationController?.navigationBar.frame.origin.y ?? 0
}
var navigationBarHeight: CGFloat {
return self.navigationController?.navigationBar.frame.height ?? 0
}
}

Navigation bar title and navigation buttons not appearing on iOS 11

Prior to iOS 11, the UINavigationBar buttons and title are being displayed correctly.
Yesterday I downloaded Xcode 9 with iOS 11 and, after building and running without doing changes, both navigation buttons and the title are not being displayed anymore. It shows the UINavigationBar with the correct color I am setting but nothing else.
I tried on different simulators and also I updated an iPhone 7 to iOS 11 beta 5 and the result is the same. Nothing being displayed.
Has someone faced the same problem? I have tried changing different parts of the code and storyboard but nothing affects...
EDIT with screenshots: http://imgur.com/a/Hy46c
Thanks in advance!
For Xcode 9, it appears that it is no longer enough to just set the frame of a custom view that is being injected into the navigationItem titleView. The intrinsic content size of your titleView now must be overriden and set as well.
Here's the code, adjust the width and height to suit your needs:
class NavigationBarTitleView: UIView {
override var intrinsicContentSize: CGSize {
return CGSize(width: bounds.width - 100, height: 50)
}
...
}
use sizeToFit()! ios 11 automatically sizes it, but ios 10 does not
I had the same issue and for me it was caused by subclassing UITabBarController
Did you set "window,rootViewController = ..." in your code ? Try remove it can fix your problem
I had the same problem in my project where the titles were missing from the navigation bars after updating to Xcode 9 and iOS 11. I solved it by going to the navigation bar of my navigation controller on the storyboard, keeping the Prefers Large Titles unchecked and changing the Title Font under Title Text attributes, which was set by default in Xcode 9 to System 0 to some other option like Caption 1 or Headline. I also changed its children viewcontrollers' navigation bar settings For Large Title to Never instead of Automatic or Always.
I found this code in some inherited codebase, commented it out and everything worked as it did before iOS 11.x.
if (appDelegate.window.rootViewController != self) {
appDelegate.window.rootViewController = self;
}
Try to use:
UINavigationBar.appearance().titleTextAttributes = [NSForegroundColorAttributeName: UIColor.white]
or without appearance proxy setting directly to the current navigationBar...It solves my problem, should Apple changed titleText to clear as default in iOS11...?
Also use this if you want the same look as iOS 10:
if #available(iOS 11, *) {
nav.navigationBar.prefersLargeTitles = false
}
Had the same issue with the navigationButton not displayed. I solved it by setting the renderingMode to .alwaysOriginal. (I didn't use templates)
Swift 3 code:
var img =R.image.smt()?.withRenderingMode(.alwaysOriginal)
I had that same issue and none of the above fixed.
Although, #Justin Vallely lead to me fix it.
All I did was to set a width on the titleView and everything worked just fine!
EDIT:
Every UIViewController has a navigationItem property, and every navigationItem has an optional titleView.
For reference: https://developer.apple.com/documentation/uikit/uinavigationitem/1624935-titleview
In my case, I was using a custom titleView and I think that's the cause of the problem, since Apple changed the API to support the new navigation bar layout.
Based on the Justin Vallely's comment I've reworked the code a little to ensure proper sizing of the view:
class NavigationBarTitleView: UIView {
private var width: CGFloat = 0.0
private var height: CGFloat = 0.0
override init(frame: CGRect) {
super.init(frame: frame)
width = frame.width
height = frame.height
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override var intrinsicContentSize: CGSize {
return CGSize(width: width, height: height)
}
}
In my particular case I've used this view as a container to UISearchBar and now it is well sized and worked perfectly with Swift 4 & iOS 11, just as it used to work on previous iOS & Swift versions
We were facing the same issue where the navigation bar color is there but the title and the buttons are not showing up. We have double checked the bar was there by triggering a navigation bar background color change 2 seconds after the navigation controller showed up on the screen, so we know the navigation bar was there and we were adding buttons to the correct instance. Same as the OP, this issue only appears on iOS 11 and not iOS 10, and we are using Swift 3.2 running Xcode 9.1.
After hours of fiddling around, it turns out that presenting a navigation controller, then making it as the UIApplication.shared.delegate.window.rootViewController (after the present animation) caused the issue in our case.
If you just skip the present view controller and make the navigation controller as the root view controller, then everything works fine. Of course, you lose the present animation in the case.

Remove line under custom navigation bar

I've been trying to create a Navigation Bar with a background image but have been running into a lot of trouble.
Two problems that I can't solve:
1) The pink line under the image
2) The back button should be moved up a little
This is the code I use to place the image:
class CustomNavController: UINavigationController {
override func viewDidLoad() {
super.viewDidLoad()
if let img = UIImage(named: "topbar60.png"){
UINavigationBar.appearance().setBackgroundImage(img, for: .default)
}
}
}
Original bar image:
If anyone is feeling really charitable you can just plug the image and Navigation Controller subclass into an empty project to try to solve this.
Thanks a lot for any help.
For your first question, You are getting the pink underline because the image's height is 60 while the navigation bar's height is 64. If you change your image's height to 64, the pink line will disappear.
As for your second question, it is a bit more complicated. Your best bet would be probably to create a custom UIBarButtonItem

Resources