touchesBegan not responding in my code - swift

//
// CommentViewController.swift
// Bordy
//
// Created by Micheal Tyler on 9/22/17.
// Copyright © 2017 Bordy,LLC. All rights reserved.
//
import UIKit
import FirebaseDatabase
import FirebaseAuth
class CommentViewController: UIViewController {
#IBOutlet weak var commentTextField: UITextField!
#IBOutlet weak var sendButton: UIButton!
#IBOutlet weak var tableView: UITableView!
#IBOutlet weak var constraintToBottom: NSLayoutConstraint!
let postId = "-KuXb-8C5kijYNqOOihB"
var comments = [Comment]()
var users = [Users]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.dataSource = self
tableView.estimatedRowHeight = 77
tableView.rowHeight = UITableViewAutomaticDimension
empty()
handleTextField()
loadComments()
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillShow(_:)), name: NSNotification.Name.UIKeyboardWillShow, object: nil)
NotificationCenter.default.addObserver(self, selector: #selector(self.keyboardWillHide(_:)), name: NSNotification.Name.UIKeyboardWillHide, object: nil)
}
/* This is where I have the code placed, when I tap on the screen in the simulator nothing is printed, my keyboard also doesnt hide if a user clicks on the screen to exit the textField. */
override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
view.endEditing(true)
print("12121")
}

Since you're using a table view here, it's very likely that your table view's scroll view absorbs the touches before your view can get them.
If you want to hide the keyboard whenever the user taps on your table view, you may consider doing this with a UITapGestureRecognizer instead :
// MARK: LifeCycle
override func viewDidLoad() {
super.viewDidLoad()
tableView.addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(handleHideKeyboard)))
}
// MARK: User Interaction
func handleHideKeyboard() {
commentTextField.resignFirstResponder()
}
Note that you can use resignFirstResponder() method to hide your keyboard:
resignFirstResponder()
Notifies this object that it has been asked to relinquish its status
as first responder in its window.

Related

swift mapView and a button . I am unable to get any touch events from the mapKit

I have a tableviewController and it uses a custom cell class for it's data.
The custom cell has a Mapview and a button.
I was able to connect the button to an event like this
class MyTVCellTableViewCell: UITableViewCell {
var placeButtonAction : (() -> ())?
var mapViewAction : (() -> ())?
#IBOutlet weak var mapView: MKMapView!
#IBOutlet weak var placeButton: UIButton!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
self.deleteButton.addTarget(self, action: #selector(placeButtonSelected(_:)),for: .touchUpInside)
// This is where it fails as it does not recognize touchUpInside
self.mapView.addTarget(self, action: #selector(mapViewSelected()),for: .touchUpInside)
}
#IBAction func placeButtonSelected(_ sender: UIButton) {
placeButtonAction?()
}
func mapViewSelected(){
mapViewAction?()
}
Any events that I can insert in this line?
self.mapView.addTarget(self, action: #selector(mapViewSelected()),for: .touchUpInside)
If you want to see the tap position over the map as a geographic location, the following should do the job.
import UIKit
import MapKit
class MapViewController: UIViewController, MKMapViewDelegate {
#IBOutlet weak var mapView: MKMapView!
override func viewDidLoad() {
super.viewDidLoad()
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(mapTapped))
tapGesture.numberOfTapsRequired = 1
mapView.addGestureRecognizer(tapGesture)
mapView.delegate = self
}
#objc func mapTapped(_ sender: UITapGestureRecognizer) {
let tapPoint = sender.location(in: mapView)
let geoPoint = mapView.convert(tapPoint, toCoordinateFrom: mapView)
print(geoPoint)
}
}

textfield not empty show save button in Swift

My save button is hidden with the function saveBtnHidden() in the code below. However, the save button won't reappear when text is typed into the text field. I have tried multiple solutions similar to this. Every time that I type into the text field, the save button just won't show up.
import UIKit
class TableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var saveBtn: UIButton!
#IBOutlet var nicknameField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
saveBtnHidden()
}
func saveBtnHidden() {
if (nicknameField.text?.isEmpty ?? true) {
// is empty
saveBtn.isHidden = true
} else {
saveBtn.isHidden = false
}
}
#IBAction func saveBtnPressed(_ sender: Any) {
performSegue(withIdentifier: "nextPage", sender: nil)
}
}
You are getting this error because your function saveBtnHidden() is only called once in viewDidLoad(). It does not get called again when the text in your text field changes. To detect when text changes, you will need to add a target to your text field that calls a function when it changes (.editingChanged) like this:
nicknameField.addTarget(self, action: #selector(textFieldDidChange(_:)), for: .editingChanged)
Then in the textFieldDidChange call your saveBtnHidden() function:
func textFieldDidChange(_ textField: UITextField) {
saveBtnHidden()
}
Code adapted from: How do I check when a UITextField changes?
Use delegate to be notify of any change. Delegates is a key part of iOS development and Apple's framework.
class TableViewController: UITableViewController, UITextFieldDelegate {
#IBOutlet weak var saveBtn: UIButton!
#IBOutlet var nicknameField: UITextField!
override func viewDidLoad() {
super.viewDidLoad()
saveBtnHidden()
nicknameField.delegate = self
}
func textFieldDidChange(_ textField: UITextField) {
saveBtnHidden()
}
// More of your source code below...

onClick Action with Label does not work [duplicate]

I would like to make a UILabel clickable.
I have tried this, but it doesn't work:
class DetailViewController: UIViewController {
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
let tap = UITapGestureRecognizer(target: self, action: Selector("tapFunction:"))
tripDetails.addGestureRecognizer(tap)
}
func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
}
}
Have you tried to set isUserInteractionEnabled to true on the tripDetails label? This should work.
Swift 3 Update
Replace
Selector("tapFunction:")
with
#selector(DetailViewController.tapFunction)
Example:
class DetailViewController: UIViewController {
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
let tap = UITapGestureRecognizer(target: self, action: #selector(DetailViewController.tapFunction))
tripDetails.isUserInteractionEnabled = true
tripDetails.addGestureRecognizer(tap)
}
#objc
func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
}
}
SWIFT 4 Update
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
let tap = UITapGestureRecognizer(target: self, action: #selector(GameViewController.tapFunction))
tripDetails.isUserInteractionEnabled = true
tripDetails.addGestureRecognizer(tap)
}
#objc func tapFunction(sender:UITapGestureRecognizer) {
print("tap working")
}
Swift 5
Similar to #liorco, but need to replace #objc with #IBAction.
class DetailViewController: UIViewController {
#IBOutlet weak var tripDetails: UILabel!
override func viewDidLoad() {
super.viewDidLoad()
...
let tap = UITapGestureRecognizer(target: self, action: #selector(DetailViewController.tapFunction))
tripDetails.isUserInteractionEnabled = true
tripDetails.addGestureRecognizer(tap)
}
#IBAction func tapFunction(sender: UITapGestureRecognizer) {
print("tap working")
}
}
This is working on Xcode 10.2.
Swift 3 Update
yourLabel.isUserInteractionEnabled = true
Good and convenient solution:
In your ViewController:
#IBOutlet weak var label: LabelButton!
override func viewDidLoad() {
super.viewDidLoad()
self.label.onClick = {
// TODO
}
}
You can place this in your ViewController or in another .swift file(e.g. CustomView.swift):
#IBDesignable class LabelButton: UILabel {
var onClick: () -> Void = {}
override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
onClick()
}
}
In Storyboard select Label and on right pane in "Identity Inspector" in field class select LabelButton.
Don't forget to enable in Label Attribute Inspector "User Interaction Enabled"
You need to enable the user interaction of that label.....
For e.g
yourLabel.userInteractionEnabled = true
For swift 3.0 You can also change gesture long press time duration
label.isUserInteractionEnabled = true
let longPress:UILongPressGestureRecognizer = UILongPressGestureRecognizer.init(target: self, action: #selector(userDragged(gesture:)))
longPress.minimumPressDuration = 0.2
label.addGestureRecognizer(longPress)
Pretty easy to overlook like I did, but don't forget to use UITapGestureRecognizer rather than UIGestureRecognizer.
Thanks researcher
Here's my solution for programmatic user interface using UIKit.
I've tried it only on Swift 5. And It worked.
Fun fact is you don't have to set isUserInteractionEnabled = true explicitly.
import UIKit
open class LabelButon: UILabel {
var onClick: () -> Void = {}
public override init(frame: CGRect) {
super.init(frame: frame)
isUserInteractionEnabled = true
}
public required init?(coder: NSCoder) {
super.init(coder: coder)
}
public convenience init() {
self.init(frame: .zero)
}
open override func touchesEnded(_ touches: Set<UITouch>, with event: UIEvent?) {
onClick()
}
}
Uses:
override func viewDidLoad() {
super.viewDidLoad()
let label = LabelButton()
label.text = "Label"
label.onClick = {
// TODO
}
}
Don't forget to set constraints. Otherwise it won't appear on view.
On top of all of the other answers, this depends on where the label is, it might be behind some subviews. You might think you tap on the label but maybe click the top view. To solve this you can bring the label view to the front with the following line.
self.view.bringSubviewToFront(lblView)
As described in the above solution
you should enable the user interaction first and add the tap gesture
this code has been tested using
Swift4 - Xcode 9.2
yourlabel.isUserInteractionEnabled = true
yourlabel.addGestureRecognizer(UITapGestureRecognizer(){
//TODO
})

UIPanGestureRecognizer does not work

It's weird, but when I add a UIPanGestureRecognizer to a view it does not work. It's my view, that white view is a subview of the red view:
Main View:
#IBOutlet weak var redView: UIView!
#IBOutlet weak var whiteView: UIView!
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let panRecognizer = UIPanGestureRecognizer(target:self, action:#selector(ViewController.handlePan))
whiteView.gestureRecognizers = [panRecognizer]
}
func handlePan(recognizer:UIPanGestureRecognizer) {
//foo
}
When I tap and drag the white view it won't move.
try this:
whiteView.isUserInteractionEnabled = true
From the Apple's docs:
If the code for your pan gesture recognizer is not called, check to see if the following conditions are true, and make corrections as needed:
The isUserInteractionEnabled property of the view is set to true. Image views and labels set this property to false by default.
The number of touches is between the values specified in the minimumNumberOfTouches and maximumNumberOfTouches properties.
For a UIScreenEdgePanGestureRecognizer object, the edges property is configured and touches start at the appropriate edge.
Handling Pan Gestures
Here is the answer:
class ViewController: UIViewController {
#IBOutlet weak var redView: UIView!
#IBOutlet weak var whiteView: UIView!
var lastLocation:CGPoint = CGPointMake(0, 0)
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let panRecognizer = UIPanGestureRecognizer(target:self, action:#selector(ViewController.handlePan))
whiteView.addGestureRecognizer(panRecognizer)
}
func handlePan(recognizer:UIPanGestureRecognizer) {
let translation = recognizer.translationInView(redView)
whiteView.center = CGPointMake(lastLocation.x + translation.x, lastLocation.y + translation.y)
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
// Promote the touched view
lastLocation = whiteView.center
}
}
If you are using swift language for method you can't use [].
var PanGesture = UIPanGestureRecognizer(target: self, action: "respondToPanGesture:")
whiteView.addGestureRecognizer(PanGesture)
Hope it helps.

Swift: Scroll View only when a TextField or Button is hidden by the Keyboard

Below is the code that I'm trying to use to have the view scroll only when the focused textField or UIButton is hidden by the keyboard:
import UIKit
class ViewController: UIViewController, UITextFieldDelegate {
#IBOutlet weak var buttonToBottomConstraint: NSLayoutConstraint!
#IBOutlet weak var textFieldUsername: UITextField!
#IBOutlet weak var textFieldPassword: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad() {
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeShown:", name: UIKeyboardWillShowNotification, object: nil)
}
func textFieldDidBeginEditing(textField: UITextField) {
}
func textFieldShouldReturn(textField: UITextField) -> Bool {textField.resignFirstResponder()
return true
}
func keyboardWillBeHidden(notification: NSNotification){
self.scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}
func keyboardWillBeShown(notification: NSNotification){
let userInfo = notification.userInfo!
if let kbsize = userInfo[UIKeyboardFrameBeginUserInfoKey]?.CGRectValue().size{
self.scrollView .setContentOffset(CGPointMake(0, kbsize.or), animated: true)
}
}
}
Problem: The View scrolls even when the keyboard is not hiding anything.
View at Launch:
View Upon Tapping on a TextField:
Question: How do I check to see if the focused field is hidden by the keyboard, and ONLY if it is, push it above it?
Project: TextFieldScroll
EDIT
App works fine in Portrait mode, however, not in landscape mode. Also in landscape mode, when the Username textField keyboard is up and I tap the Password textField, it remains hidden behind the keyboard. I updated the project on Github and fixed the link. Thanks
Screen shot in landscape:
var currentTextField:UITextField?
#IBOutlet weak var textFieldUsername: UITextField!
#IBOutlet weak var textFieldPassword: UITextField!
#IBOutlet weak var scrollView: UIScrollView!
override func viewDidLoad()
{
super.viewDidLoad()
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeHidden:", name: UIKeyboardWillHideNotification, object: nil)
NSNotificationCenter.defaultCenter().addObserver(self, selector:"keyboardWillBeShown:", name: UIKeyboardWillShowNotification, object: nil)
}
func textFieldDidBeginEditing(textField: UITextField)
{
currentTextField=textField;
}
func textFieldShouldReturn(textField: UITextField) -> Bool {
textField.resignFirstResponder()
return true
}
func keyboardWillBeHidden(notification: NSNotification){
currentTextField=nil;
self.scrollView.setContentOffset(CGPointMake(0, 0), animated: true)
}
func keyboardWillBeShown(notification: NSNotification){
let userInfo = notification.userInfo!
if let kbsize = userInfo[UIKeyboardFrameBeginUserInfoKey]?.CGRectValue().size
{
let contentInsets = UIEdgeInsets(top: 0, left: 0, bottom: kbsize.height, right: 0)
let screenSize: CGRect = UIScreen.mainScreen().bounds
let screenHeight = screenSize.height
let height:CGFloat=screenHeight-(kbsize.height)-(currentTextField!.frame.size.width)
if(currentTextField!.frame.origin.y>=height )
{
var scrollPoint: CGPoint = CGPointMake(0.0, currentTextField!.frame.origin.y - (kbsize.height));
self.scrollView .setContentOffset(scrollPoint, animated: true)
}
}
}
func textFieldDidEndEditing(textField: UITextField) {
currentTextField=nil;
}
I don't see you setting the scrollView's contentSize. Thus, the scrollView scrolls with the keyboard since it uses the screen's size.