How to create custom navigation bar in swift? - ios

I need to do a task that is about when I scroll my view to the top the navigation bar gets smaller and becomes like in the pictures below.
This is the code that I am using
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "navBarImg"), for: UIBarPosition.any, barMetrics: .default)
//set navigation height
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
let height = CGFloat(200)
navigationController?.navigationBar.frame = CGRect(x: 0, y: 0, width: view.frame.width, height: height)
}
// when scroll
func scrollViewDidScroll(_ scrollView: UIScrollView) {
self.navigationController?.navigationBar.setBackgroundImage(UIImage(named: "back"), for: UIBarMetrics.default)
}
But nothing happens. Please can you tell me how to solve this problem? I know that in android there is solution and it's name is CoordinatorLayout, but in iOS I could not find any solution.

Related

tabbar middle tab out of tabbar corner

I want to make a tab bar with 5 tab items. I want the middle one ( third ) to be out of tab bar's corner it may be tough to understand therefore I decided to add screenshot
I want to make something like you can see above but I don't know how it's possible.
I would appreciate any way you recommend to do it.
select tabbar Item and set its image insets
Make sure to get proper image (if using an image) goto Assets-> select desired image -> set property to always original
create a class of UITabBarController and assign it to the TabBarController.
initialise Variable
let button = UIButton.init(type: .custom)
Then in viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
button.setImage(UIImage(named: "IMAGE_NAME_FROM_ASSETS"), for: .normal)
button.backgroundColor = UIStyle.Color.CameraBG
button.layer.cornerRadius = 40
button.addShadow(offset: CGSize(width: 5, height: 5), color: UIStyle.Color.CameraShadow, radius: 5, opacity: 0.1)
button.addTarget(self, action: #selector(pressedAction(_:)), for: .touchUpInside)
self.view.insertSubview(button, aboveSubview: self.tabBar)
}
Add viewDidLayoutSubviews in your class
override func viewDidLayoutSubviews() {
super.viewDidLayoutSubviews()
// safe place to set the frame of button manually
button.frame = CGRect.init(x: self.tabBar.center.x - 40, y: self.view.bounds.height - 100, width: 80, height: 80)
}
Action You Want To Perform on button click
#objc func pressedAction(_ sender: UIButton) {
// do your stuff here
let nc = UINavigationController(rootViewController: YOURVC.storyboardInstance())
nc.modalPresentationStyle = .fullScreen
present(nc, animated: true, completion: nil)
}

Create UIButton on top layer UITableViewController like as AirBnB

How to create UIButton in UITableViewController like as AirBnB map.
Highlighted in red in screenshot.
It's quite easy actually, just create the table view as you always do (either storyboard or code) then create the button, position it correctly, set constraints and make sure it's not a subview of the table view but the view that contains the table view.
Since you didn't specify whether you use the storyboard or not, I did use it for the example below.
See this extremely simple demo I've just created:
This is the view hierarchy:
And these are the constraints for the button:
Create a button first and then then override the function scrollViewDidScroll():
import UIKit
class YourTableViewController: UITableViewController {
private let button = UIButton(type: UIButton.ButtonType.custom) as UIButton
override func viewDidLoad() {
let image = UIImage(named: "Image.png")
button.frame = CGRect(x: yourXpos, y: yourYPos, width: 60, height: 60)
button.setImage(image, for: .normal)
button.clipsToBounds = true
button.layer.cornerRadius = 30
button.addTarget(self, action: #selector(buttonClicked(_:)), for:.touchUpInside)
areaOfTableView.addSubview(button)
}
override func scrollViewDidScroll(_ scrollView: UIScrollView) {
let offset = self.areaOfTableView.contentOffset.y
button.frame = CGRect(x: yourXpos, y: offset + yourYpos, width: btn.frame.size.width, height: btn.frame.size.height)
}
#objc private func buttonClicked(_ button: UIButton) {
// Action when you tapped the button
}
}

Position UIButton in UITextview

I would like to place a "forgot?" Button into my Password Textfield. If nothing is in the Textfield the user should be able to click it and another ViewController should pop up. The only thing I managed to do is what you can see in the picture down below. My problem is that the button is not clickable and that it is not on the same level as the placeholder text. Any ideas on how to solve this two problems?
let button = UIButton(type: .custom)
button.setTitle("vergessen?", for: .normal)
button.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(100), height: CGFloat(100))
button.addTarget(self, action: #selector(self.refresh), for: .touchUpInside)
passwordTextField.rightView = button
passwordTextField.rightViewMode = .unlessEditing
In the file you have subclassed from my answer add another function in that file
// Modify the values as required
override func rightViewRect(forBounds bounds: CGRect) -> CGRect {
let offset = -20
let width = 100
let height = width
let x = Int(bounds.width) - width - offset
let y = offset
let rightViewBounds = CGRect(x: x, y: y, width: width, height: height)
return rightViewBounds
}
Now you can remove the follow line
button.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(100), height: CGFloat(100))
Output
And regarding the button click event. Remove your code as you mention its not connected
IBAction func refresh(_ sender: Any) { }
And add the following code in the same file where the button is created.
#objc func refresh() {
// your vc code here
print("in refresh")
}
The above code hooks in with addTarget code you have.
button.addTarget(self, action: #selector(self.refresh), for: .touchUpInside)
Hope this helps.
I suggest to create a xib file and its relevant view for text items that have a button inside it. So you would be able to reuse it elsewhere in the future (this or another projects)
By defining constant height (100) you will experience ugly and misplaced UI in different iOS devices.
Here it is what you should do :
Define a xib file for your custom UITextView
Create constraints for it so it width and height defined by its parent.Also define your forgot UIButton in relative to your UITextView.
Define its (xib) relevant UIView class
Use it in your Storyboard
You can use Storyboard. Make a helper view for the password TextField and Forgot Button.
-Set the Helper view same width and height with the email TextField.
-Add a TextField and a Button inside the helper view and then you can decide for the password TextField width and the Forgot Button width.
-Set constrains for the TextField and Button
I set green color to understand what the helper View does.
Update
I just used your code and it works fine.Check your textfield constrains again. This is what I used.
override func viewDidLoad() {
super.viewDidLoad()
let button = UIButton(type: .system)
button.setTitle("vergessen?", for: .normal)
button.setTitleColor(#colorLiteral(red: 0.3647058904, green: 0.06666667014, blue: 0.9686274529, alpha: 1), for: .normal)
button.frame = CGRect(x: CGFloat(0), y: CGFloat(0), width: CGFloat(100), height: CGFloat(100))
button.addTarget(self, action: #selector(self.refresh), for: .touchUpInside)
textfFeld.rightView = button
textfFeld.rightViewMode = .unlessEditing
}
#objc func refresh(_ sender: Any) {
print("Hello")
}
The only think I changed is the button type from .custom to .system.

Expanding UINavigationBar Height

I followed along here to get a bigger navigation bar working. The result is that it looks bigger, however not all elements of the bar actually expand, meaning that I can only interact with items places in the original size of the navigation bar. This is my pain point because I am trying to expand the UINavigationBar to put buttons in the expanded area and these can't be pressed.
Here's my code:
#IBDesignable
class CustomNavigationBar: UINavigationBar {
var customHeight: CGFloat = 88
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
let button = UIButton(frame: CGRect(x: 0, y: 44, width: 100, height: 44))
button.setTitle("Button", for: .normal)
button.backgroundColor = .red
button.addTarget(self, action: #selector(buttonAction), for: .touchUpInside)
self.addSubview(button)
}
#objc func buttonAction() {
print("button pressed")
}
override func sizeThatFits(_ size: CGSize) -> CGSize {
return CGSize(width: UIScreen.main.bounds.width, height: customHeight)
}
override func layoutSubviews() {
super.layoutSubviews()
for subview in self.subviews {
var stringFromClass = NSStringFromClass(subview.classForCoder)
if stringFromClass.contains("UIBarBackground") {
subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: customHeight)
subview.backgroundColor = .green
subview.sizeToFit()
}
stringFromClass = NSStringFromClass(subview.classForCoder)
if stringFromClass.contains("UINavigationBarContentView") {
subview.frame = CGRect(x: 0, y: 0, width: self.frame.width, height: customHeight)
subview.backgroundColor = .black
subview.sizeToFit()
}
}
}
}
Here's the screenshot from that output:
You can see here that when I resized the UIBarBackground in the layoutSubviews() function, I made it green and set it to the custom height, which worked. However when I resized the UINavigationBarContentView and set its colour to black, the colour gets set fine, but the height stays at 44.
See a screen shot of the debug view hierarchy below and we see that there are actually two items that still have the original height of 44.
All of this means that I cannot press the button in the view at all. However, if I move it up a bit so that it is inside the 44 height, then I can press it.
Looking for some help as to how I can properly resize all aspects of this nav bar
EDIT
If I remove the subview.sizeToFit() from the UInavigationBarContentView it resizes it to the correct size. I also noticed that the overridden sizeThatFits is never called?
i was try to change the height before but also i couldn't ,but
i makes the custom navigation controller and am call it on the viewDidLoad and hide the native navigation controller by doing
self.navigationController?.navigationBar.isHidden = true
and i display the custom in the same place and i put my views on this navigation controller also you can do animations on height this custom nav bar if you want
i hope this help you

center navigation bar views vertically

I managed to increase the height of my navigation bar, but I faced with the problem, that title and buttons are situated in the bottom of navigator bar.
extension UINavigationBar {
open override func sizeThatFits(_ size: CGSize) -> CGSize {
let v = self.value(forKey: "frame") as? CGRect
return v?.size ?? CGSize(width: UIScreen.main.bounds.width, height: 44)
}
}
override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
navigationBar.frame = CGRect(x: 0, y: 0, width: bounds.width, height: 64)
}
I tried to set offset, using
navigationBar.setTitleVerticalPositionAdjustment(-10, for: .default)
navigationItem.leftBarButtonItem?.setBackgroundVerticalPositionAdjustment(-10, for: .default)
navigationItem.rightBarButtonItem?.setBackgroundVerticalPositionAdjustment(-10, for: .default)
navigationItem.rightBarButtonItem?.setBackButtonBackgroundVerticalPositionAdjustment(-10, for: .default)
navigationItem.leftBarButtonItem?.setBackButtonBackgroundVerticalPositionAdjustment(-10, for: .default)
Actually that setting only apply to my title, and the position of button bars remain the same.
But I don't think my solution is the best.
Its not a good practice to increase the size of the navigation bar. Instead you can add a uiview right under navigation bar with same color and remove the navigation bar border to make to look like height increased. Here is an example how yelp does it.
I posted the solution of this problem in another thread. Hope this helps.
vertically aligning UINavigationItems

Resources