How to hide keyboard in swift on press of navigationBar - ios

I am developing an swift 3 app that has a navigation bar in every page. The navigation bar also has a button in the left.
I need to resign the keyboard on touch of any object in the screen.
I tried with the usual
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
but it works for all other parts of the view except the navigation bar.
I tried adding the following code:
self.navigationController?.navigationBar.endEditing(true)
to the touchesBegan function but it did not work, presumable because I do not have a navigation controller, I just added the searchbar in the storyboard.
How can I get the keyboard to resign on tap of the navigation bar, including the button in the navigation bar?
This is important to my app, because, as you can see below, it is the largest space available for the user to tap without changing the view.
I need to make the resigning work in the area enclosed in yellow, including the button shown by the arrow.

for e.g
override func viewDidLoad() {
super.viewDidLoad()
let hideKeyboard = UITapGestureRecognizer(target: self, action: #selector(self.navigationBarTap))
hideKeyboard.numberOfTapsRequired = 1
navigationController?.navigationBar.addGestureRecognizer(hideKeyboard)
}
and handle the action as
func navigationBarTap(_ recognizer: UIGestureRecognizer) {
view.endEditing(true)
// OR USE yourSearchBarName.endEditing(true)
}

Try to add tap gesture on navigation bar :
override func viewDidLoad() {
super.viewDidLoad()
let navSingleTap = UITapGestureRecognizer.init(target: self, action: #selector(self.tap(_:)))
navSingleTap.numberOfTapsRequired = 1
self.navigationController?.navigationBar.subviews[1].isUserInteractionEnabled = true
self.navigationController?.navigationBar.subviews[1].addGestureRecognizer(navSingleTap)
}
func tap() {
// do your work
}

Subclass UINavigationBar and set it as the custom class of the Navigation Bar in the Storyboard.
// NavigationBar.swift
import UIKit
class NavigationBar: UINavigationBar {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.window?.endEditing(true)
}
}

Call this line inside of your button action BEFORE you are calling your MENU on button:
YourSearchOutlet.resignFirstResponder()

Related

How to detect when pressing down on UIBarButtonItem?

I want to implement a scale animation when the user presses down on a UITabBarItem. How can I detect when a tabBarItem in a tabBar is being pressed down?
My thinking so far is that perhaps there is a method in the UITabBarControllerDelegate?
I haven't seen a SO question on this...
Thanks, this issue has been holding me back hours!
The general idea is, you need to create your own custom UIView, and then pass that into this initialiser.
let customView = MyCustomBarButtonItem()
let barButtonItem = UIBarButtonItem(customView: customView)
As for how you implement the custom view so that you can detect touch downs, you have many choices.
You can either use touchesBegan to detect the touch down, and touchesEnded to detect a "tap" on the bar button item.
class MyCustomBarButtonItem: UIView {
// ...
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
// ...
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
// ...
}
}
Another way is to subclass UIButton, and add target/action pairs for the .touchDown/.touchUpInside control events.
These are the delegate methods which get called when a user selects a tabBarItem:
// UITabBarDelegate
override func tabBar(_ tabBar: UITabBar, didSelect item: UITabBarItem) {
print("Selected item")
}
// UITabBarControllerDelegate
func tabBarController(_ tabBarController: UITabBarController, didSelect viewController: UIViewController) {
print("Selected view controller")
}

Restrict navigation bar from hide on button tap

I wants to hide navigation bar on tap. So i used this method of navigation bar.
self.navigationController?.hidesBarsOnTap = true
Have 2 button on screen and when i tap on that button for perform some action it is also hiding navigation bar. I think button click consider as tap.
Can you please let me know, is it correct behaviour ? Also please let me know if there is any way to restrict this. I don't want to hide navigation bar on button tap, rest of parts of screen will be fine.
You can create your custom button and handle touches on to enable/disable hiding bars e.g.:
class BarHideOnTapButton : UIButton {
weak var navigationController: UINavigationController?
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesBegan(touches, with: event)
self.navigationController?.hidesBarsOnTap = false
}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesEnded(touches, with: event)
self.navigationController?.hidesBarsOnTap = true
}
}
class ViewController: UIViewController {
#IBOutlet var button: BarHideOnTapButton?
override func viewDidLoad() {
super.viewDidLoad()
self.button?.navigationController = self.navigationController
self.navigationController?.hidesBarsOnTap = true
}
...
}

Start touch outside a button and trigger an event when dragged into the bounds of button

If I have a button and starts a touch outside of the buttons bounds and then drag my finger across the screen until I hit the bounds of the button which then will trigger an event. Say change the background color of the button for example (which I know how to). How do I trigger something from that type of touch movement?
I also set my buttons programmatically.
Thanks in advance!
To trigger an action attached to a button when a finger is moving over the button you can use a method touchesMoved(_:with:) of UIViewController.
Firstly, add an action to the button for touchUpInside and touchDragInside inside InterfaceBuilder or in code.
Secondly, override touchesMoved(_:with:) method and call a super. If the super is not called the button UIKit will not trigger any actions on the button. Next, get a touch location inside the view and trigger a touchDragInside action on the button.
#IBOutlet weak var button: UIButton!
override func touchesMoved(_ touches: Set<UITouch>, with event: UIEvent?) {
super.touchesMoved(touches, with: event)
if let t = touches.first,
button.frame.contains(t.location(in: view)) {
button.sendActions(for: .touchDragInside)
} else {
print("false")
}
}
#IBAction
func didTapButton() {
print("true: touch inside the frame of a button")
}
#IBAction
func didDragInsideButton() {
print("true: touch drag inside the frame of a button")
}
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
}
override func viewDidLoad() {
super.viewDidLoad()
button.addTarget(self, action: #selector(didTapButton), for: .touchUpInside)
button.addTarget(self, action: #selector(didDragInsideButton), for: .touchDragInside)
}

How to Dismiss keyboard when touching away across the entire app

I have multiple textFields in different viewControllers where keyboard is popped up.
I know how to dismiss keyboard when user clicks on a different part of the screen but I don't want to go and hard code it into every corner of my app.
So is there anyway to enforce keyboard getting keyboard dismissed everywhere on the app when the user clicks anywhere on the screen other than keyboard?
I was thinking of extending the UIViewController, but I also have some textFields inside a view that I add as a subview. Perhaps there could be someway that I extend TextField class itself?
I suggest to create a base UIViewController and let each of your ViewControllers inherit it; override touchesBegan method in it:
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
view.endEditing(true)
}
OR you can override viewDidLoad -in the base ViewController- and add a UITapGestureRecognizer to the view, as follows:
override func viewDidLoad() {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(Base.endEditing))
view.addGestureRecognizer(tapGesture)
}
func endEditing() {
view.endEditing(true)
}
You can also use an extension of a view controller, if you want the keyboard dismissal to apply to all of them:
extension UIViewController {
open override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.view.endEditing(true)
}
}

touchesbegan for dismissing keyboard textview under scrollview not working

I have a text field under a view which is under a scroll view inside a view controller which is one of the view controllers of a navigation controller. I want to dismiss the keyboard when the user touches outside the textfield. I tried using touchesBegan:, but it is not firing when it's under the scrollview. I also tried disabling user interaction in the scroll view, but nothing worked. Could anyone help me out?
func dismissKeyboard(txtField:UITextField)
{
txtField.resignFirstResponder()
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
dismissKeyboard(firstNameTxt)
}
Changed the below way for it to work
extension AddEditHireViewController {
func hideKeyboard()
{
let tap: UITapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: "dismissKeyboardNew")
self.formView.addGestureRecognizer(tap)
}
func dismissKeyboardNew()
{
self.formView.endEditing(true)
// self.dismissKeyboard(self.firstNameTxt)
} }
Whilst the solution given by Matthew Bradshaw works too, it will not dismiss the keyboard if the user scrolls. If you want it to do that, another solution would be to subclass UIScrollView. You could then override the touchesBegan method in this subclass, and then end editing accordingly.
class DismissableScrollView: UIScrollView {
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
endEditing(false)
}
}
Once you have done this, simply change your existing UIScrollView's class to DismissableScrollView, or if you are already subclassing UIScrollView, you could add this to that subclass.
You could try to create an extension of the view controller. This has worked much smoother for me and with less hassle than trying to use .resignFirstResponder()
extension UIViewController
{
func hideKeyboard()
{
let tap: UITapGestureRecognizer = UITapGestureRecognizer(
target: self,
action: #selector(UIViewController.dismissKeyboard))
view.addGestureRecognizer(tap)
}
func dismissKeyboard()
{
view.endEditing(true)
}
}
Call self.hideKeyboard() in the viewDidLoad

Resources