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")
}
Related
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
}
...
}
I have a couple textViews in one cell in a table view controller and I am trying to dismiss the keyboard when you touch anywhere outside the keyboard. I've tried the touches began method but it didn't work. The text views are not transparent and have user interaction enabled.
class RegisterTableViewController: UITableViewController {
override func viewDidLoad() {
// set all text views delegate to self
}
// dismiss keyboard on touch
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
print("touch")
super.touchesBegan(touches, with: event)
view.endEditing(true)
}
}
extension RegisterTableViewController: UITextViewDelegate {
func textViewDidBeginEditing(_ textView: UITextView) {
textView.text = ""
}
}
I'm new to swift and would appreciate any help!
Add touchesBegan code in your UITableViewCell file , which will work if you touch outside TextField but inside cell
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
self.Your_TextField.endEditing(true)
}
But it won't work outside cell (In UIVIew of another ViewController) , so add UITapGesture to achieve that
override func viewDidLoad() {
super.viewDidLoad()
let tapgest = UITapGestureRecognizer(target: self, action: #selector(taptoend))
self.Your_Table_View.addGestureRecognizer(tapgest)
}
#objc func taptoend()
{
self.Your_Table_View.endEditing(true)
print("Key-Board will be dismissed here")
}
You need to add Tap gesture recognizer inside your cell. Place all you text inputs in a UIView. make outlet of UIView inside cell. and than add this code in your cell.
#IBOutlet weak var myView: UIView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let tap = UITapGestureRecognizer(target: self, action: #selector(self.dismissKeyboard))
self.myView.addGestureRecognizer(tap)
}
#objc func dismissKeyboard() {
self.endEditing(true)
}
I have created a custom control for Uber like OTP TextField. I want to consume the touch in my control and not let it propagate through the UIResponder Chain. So I have overridden the methods as described in apple documentation.
extension BVAPasswordTextField {
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
becomeFirstResponder()
}
override func touchesMoved(Set<UITouch>, with: UIEvent?) {
}
override func touchesEnded(Set<UITouch>, with: UIEvent?) {
}
override func touchesCancelled(Set<UITouch>, with: UIEvent?) {
}
override func touchesEstimatedPropertiesUpdated(Set<UITouch>) {
}
}
Now in some view controller I want to dismiss the keyboard when the user taps anywhere outside my custom control.
override func viewDidLoad() {
super.viewDidLoad()
let tapGestureRecogniser = UITapGestureRecognizer(target: self, action: #selector(ViewController.backgroundTapped))
tapGestureRecogniser.numberOfTapsRequired = 1
view.addGestureRecognizer(tapGestureRecogniser)
// Do any additional setup after loading the view, typically from a nib.
}
#objc func backgroundTapped() {
self.view.endEditing(true)
}
But whenever I tap on the textfield backgroundTapped also gets called.
Note:- It is a control where based on enum values you can create different UI Components for taking input. So this control can be shared among the whole team... I won't be the only guy using it.... So I want it to behave exactly like UITextfield in touch scenario
You can handle the tap gesture using UITapGestureRecognizerDelegate. It allows you to decide whether or not gesture should begin. In your case, it should be done basing on the location of the touch.
extension ViewController: UIGestureRecognizerDelegate {
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let location = gestureRecognizer.location(in: self.view)
// return true is location of touch is outside our textField
return !textField.frame.contains(location)
}
}
Just make sure you've set a delegate for your gesture at viewDidLoad
tapGestureRecogniser.delegate = self
UPDATE
If I got your setup right, you have a view and some subviews that are used for input. And you want to resignFirstResponder when this super-view is touched. In that case you can use gestureRecognizerShouldBegin like that
func gestureRecognizerShouldBegin(_ gestureRecognizer: UIGestureRecognizer) -> Bool {
let location = gestureRecognizer.location(in: self.view)
for subview in self.view.subviews {
if subview.frame.contains(location) {
return false
}
}
return true
}
In my opinion, if you want to handle some view interaction in a specific way, you need to do it using that specific view. And what you're doing now feels like trying to change behavior on one view, using another view.
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()
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)
}
}