Reputation: 303
I'm new to iOS UI design, and I'm working on writing code that displays highly customized navigation bar, which will be used my transportation app.
Here are features of my navigation bar (see figure below):
Layout Margins
are 18
, and Space
between its subviews is 9
.height
is 44
, and all UIBarButtonItem
is rectangle.backBarButtonItem
should be positioned same as leftBarButtonItem
.height
is 80
.titleView
will contain two UITextField
s, so its height
should be 136
.See Real Design Screenshots
So I've declared subclass of
UINavigationBar
, and connected custom class to Navigation Bar
object in storyboard using Identity Inspector. However, I'm not sure where to begin. Though I overrode sizeThatFits(_ size:)
function to make its height
long for now, the subviews are close to bottom. I could't find a best practice to customize UINavigationBar
like Google Maps, Uber, etc.
How can I implement such navigation bar by subclassing UINavigationBar
? Or are there any other solutions?
Upvotes: 3
Views: 1461
Reputation: 754
You can subclass UINavigationBar with the following steps..
Add a new class(subclass of UINavigationBar), select your ViewController's NavigationController. Select ViewController Navigation Bar from the Document Outline. Set the class to your custom class.
In your custom class, do as following..
override func sizeThatFits(_ size: CGSize) -> CGSize {
var bound = super.sizeThatFits(size)
bound.height += sizeToAdd //The height you want
return bound
}
override init(frame: CGRect) {
super.init(frame: frame)
self.setup()
}
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
self.setup()
}
override func layoutSubviews() {
super.layoutSubviews()
//If you don't override this function and do as follows, you'll
//find that all NavigationButtons and the Title positioned at the
//bottom of your navigation bar.(for the Title, we still need to
//add one line in setup())
let classes = ["UIButton", "UINavigationItemView",
"UINavigationButton"]
for object in self.subviews{
let classOfObject = String(describing: type(of: object))
if classes.contains(classOfObject){
var objectFrame = object.frame
objectFrame.origin.y -= self.sizeToAdd
object.frame = objectFrame
}
}
}
Now in setup(), add the following code to get the Title uplifted as one would want(typically!)
func setup() -> Void {
self.setTitleVerticalPositionAdjustment(-self.sizeToAdd, for:
.default)
}
Now, you can design a view as you want (Here, I've loaded a custom view with XIB, you can do with code too.) and add as a subview to your navigation bar, in your ViewController. For example, in your viewDidLoad..
YOURVIEW.frame = CGRect(x: 0, y: 44, width:
(self.navigationController?.navigationBar.bounds.width)!, height:
(self.navigationController?.navigationBar.bounds.height)! +
self.sizeToAdd)//The height
self.navigationController?.navigationBar.
addSubview(YOURVIEW)
So, you can subclass your navigation bar this way. But when you'll push any other viewController onto this one, you'll see (if you haven't embedded another NavigationController to the viewController that you're pushing) that the view remains as it was in pushed viewController too. You can remove it from super view before pushing any other viewController. Just removing it will not give a good user experience as the other system elements(if there are any) will fade out nicely. So, do the following to give a good user experience...
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(true)
if(!(self.navigationController?.navigationBar.subviews.contains
(YOURVIEW))!){ //Either get it working with setting a tag to
//your view and checking it against all subviews
//if you haven't use XIB
self.navigationController?.navigationBar.
addSubview(YOURVIEW)
}else {
UIView.transition(with: YOURVIEW,
duration: 0.5, options: [ANYOPTIONS], animations: {
self.profileNavigationView.alpha = 1.0
}) { (success) in
}
}
}
override func viewWillDisappear(_ animated: Bool) {
super.viewWillDisappear(true)
UIView.transition(with: YOURVIEW, duration:
0.5,
options: [ANYOPTIONS], animations: {
self.profileNavigationView.alpha = 0.0
}) { (success) in
//remove it here if you want
}
}
Upvotes: 2