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
Related
I would like to round the two bottom corners of my navigation controllers's bar, so it looks like this:
I tried this:
final class RoundedNavigationController: UINavigationController {
override func viewDidAppear(_ animated: Bool) {
self.navigationBar.layer.cornerRadius = 20
self.navigationBar.clipsToBounds = true
self.navigationBar.layer.maskedCorners = [.layerMinXMaxYCorner,.layerMaxXMaxYCorner]
}
}
But here is the result I'm getting:
Why does the safe area part get clipped too?
Thank you for your help
Why does the safe area part get clipped too?
The bounds top of the navigation is at the bottom of the status bar. The drawing of the navigation bar is extended upward beyond its bounds into the "status bar" area (and on up to the top of the screen).
For this reason, you cannot set a navigation bar's clipsToBounds to true, as you will break the way it draws.
A better strategy might be to construct the navigation bar's background image to look the way you want it. So, for example, I was able to get this effect:
But not by rounding the layer corners and clipping.
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.
I have a custom UIView. Dead simple, just always wants to be 300x30 if possible.
class MyVoo: UIView {
override func sizeThatFits(size: CGSize) -> CGSize {
return CGSize(width: 300, height: 30)
}
}
I then set it to the navigationItem's titleView property like so:
let voo = MyVoo()
voo.backgroundColor = .magentaColor()
navigationItem.titleView = voo
voo.sizeToFit()
But when I run it, it looks like this:
As you can see width is weird. It's set to 246 for some reason, which is just slightly too much and causes the back button text to be cut off. I don't mind it being cut off, but it should occupy the space to the left better, or be the proper size and allow the back button text to show.
Basically my question is: how do I have this custom UIView be properly sized in the navigation bar? Right now it's very clearly "off", and I'd like it to effectively behave as if I just navigationItem.title (instead of titleView) to 300px worth of text. Properly shortened, the back button has proper text, etc. Rather than this weird solution where it's not properly sized for anything at all. How do I properly size it and how does it decide its sizing?
I have the code below which shows a popup. The popup has a main view which is black, and one subview which is white, and that subview has some labels, button and stuff the user interacts with. I want the surrounding black part to be partially transparent (alpha = 0.7), but the white part inside it to be fully opaque (alpha = 1.0). I could not achieve that, for some reason the value of the parent overrides its child values, and I get either a fully opaque view, or a view where also the labels and buttons are partially transparent.
What Can I do?
The code which shows the popup:
#IBAction func getLocation(sender: AnyObject) {
var p = PopupViewConrtoller(list: list, callback)
var x = UINib(nibName: "PickerPopup", bundle: nil).instantiateWithOwner(p, options: nil)
self.presentViewController(p, animated: false, completion: nil)
}
I changed opacity only in the attributes inspector.
It seems, it is not possible to make main view partially transparent without affecting the subviews added to main view.
What you can do is,
-set mainView background color as clear color
-add one more subview1 to mainView with size same as main view and set the background color as blackColor with desired transparency(alpha=0.7 as in required)
-add your subview2(which is having labels, buttons etc.) to mainView but above subview1 in layer order.
I hope it will help you to achieve what you want.
I figurred it is impossible to do it the way I was trying to. Rajeev has a good idea, but the best (and the one that apple reviewers will probably approve) is using popovers. This tutorial and this tutorial were helpful.
I'm took the Tabbar viewcontroller in this ,I added the 5 item and .I given the image insects is (24,0,0,6).
All button images are added in xib [under the Bar item -->image]Please help.
Thanks.
Adding to a similar answer here:
iOS Tab Bar icons keep getting larger
Not sure if this is an iOS7 bug but I've noticed that image insets need to be balanced.
You have specified insets for top and right but:
if you set a top inset, in order to balance it, you need to set the negative of it to the bottom inset
if you set a right inset, in order to balance it, you need to set the negative of it to the left inset
So, instead of having image insets like (24,0,0,6), use balanced image insets such as UIEdgeInsetsMake(24,-6,-24,6)
Doing so should protect your tabBarItem image from getting whacked on every tap.
If this doesn't suit your requirements, then redesign your tabBarItem image so you can have balance insets or... no insets at all.
Here's the workaround for a bug I've encountered with UITabBarController's UITabBar. If I tap a UITabBarItem once after it's selected, the icon shrinks. What I'd like to do is disable touches. UITabBarItem only has a setting for isEnabled, which grays it out if I set it to false...not what I was looking for.
I used a derivative of this answer to figure it out. With a UITabBarController with 3 tabs, printing tabBarController.subviews, I saw 3 UITabBarButtons and a UIBarBackground. The origin of UIBarBackground's frame was always (0, 0), putting it at the front of the sorted array, so I really don't need to know what the subview is, just "where it is" and whether it will always be there. The UIBarBackground is always going to be at the front of an array of tabBarController.subviews sorted by frame.minX, so I just need to remove it from the front.
Solution
Here's what the extension looks like:
extension UITabBarController {
var buttonViews: [UIView] {
var tabBarButtons = tabBar.subviews.sorted(by: {$0.frame.minX < $1.frame.minX})
tabBarButtons.removeFirst()
return tabBarButtons
}
}
I also created a struct in my Constants file, so I don't have to remember tab names:
struct TabBarItem {
static let firstTab = 0
static let secondTab = 1
static let thirdTab = 2
}
...and finally, where to use it:
In viewDidAppear (NOT viewDidLoad), add the following line to disable the UITabBarItem that you don't want to disable, but not gray out:
tabBarController?.buttonViews[TabBarItem.firstTab].isUserInteractionEnabled = false
In viewWillDisappear, re-enable the tab, as follows:
tabBarController?.buttonViews[TabBarItem.firstTab].isUserInteractionEnabled = true