David Seek David Seek - 4 months ago 30
Swift Question

Swift / UIView with a TableView and gesture recognizers issue

I have a UIViewController with a TableView and 2 (tap) gesture recognizers.
The First recognizer lets the keyboard disappear. The second one a menu.

let tap: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomeVC.dismissKeyboard))
view.addGestureRecognizer(tap)


-

@IBAction func menuBtn(sender: AnyObject) {

let menuView = (NSBundle.mainBundle().loadNibNamed("Menu", owner: self, options: nil).last) as! Menu
menuView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, 100)

self.view.addSubview(menuView)

UIView.animateWithDuration(0.6, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: .CurveEaseInOut, animations: { () -> Void in
var newMenuFrame = menuView.frame
newMenuFrame.origin.y = self.view.bounds.size.height - 63
menuView.frame = newMenuFrame
self.view.layoutIfNeeded()



}) { (success) -> Void in

let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomeVC.hideOnTap(_:)))
gestureRecognizer.numberOfTapsRequired = 1
self.view.addGestureRecognizer(gestureRecognizer)
}

}


With the gesture regonizers the
didSelectRowAtIndexPath
will not be called. What can I do to keep my gesture recognizers AND my tableView. Or. How can I deactivate the gesture recognizers only for the tableView? Help is very appreciated.

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

print("You selected cell #\(indexPath.row)!")
// this is only working if both gesture recognizers are gone.

}


///// COMPLETE CODE

//
// HomeVC.swift
// cya
//
// Created by David Seek on 25.07.16.
// Copyright © 2016 David Seek. All rights reserved.
//

import UIKit
import FBSDKCoreKit
import FBSDKLoginKit
import GoogleMobileAds
import SDWebImage

protocol ChooseUserDelegade {
func createChatroom(withUser: BackendlessUser)
}

class HomeVC: UIViewController, UITextFieldDelegate, UINavigationControllerDelegate, UIImagePickerControllerDelegate, UITableViewDelegate, UITableViewDataSource {

var deejays: [BackendlessUser] = []
var delegade: ChooseUserDelegade!

@IBOutlet weak var avatarImageView: UIImageView!
@IBOutlet weak var coverImageView: UIImageView!

@IBOutlet weak var statusTextField: UITextField!
@IBOutlet weak var googleAdBannerView: GADBannerView!

@IBOutlet weak var tableView: UITableView!
var menu: Menu!

override func viewDidLoad() {
super.viewDidLoad()

print("Google Mobile Ads SDK version: \(GADRequest.sdkVersion())")
//googleAdBannerView.adUnitID = "//" //live ad
googleAdBannerView.adUnitID = "//" //test ad
googleAdBannerView.rootViewController = self
googleAdBannerView.loadRequest(GADRequest())

avatarImageView.layer.cornerRadius = avatarImageView.frame.size.width / 2
avatarImageView.layer.masksToBounds = true
avatarImageView.layer.borderWidth = 1
avatarImageView.layer.borderColor = UIColor.whiteColor().CGColor

updateUI()

let tapGestureRecognizer: UITapGestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomeVC.dismissKeyboard))
tapGestureRecognizer.delegate = self
view.addGestureRecognizer(tapGestureRecognizer)


self.statusTextField.delegate = self

self.tableView.rowHeight = 80
loadDeejays()


}

@IBAction func menuBtn(sender: AnyObject) {

let menuView = (NSBundle.mainBundle().loadNibNamed("Menu", owner: self, options: nil).last) as! Menu
menuView.frame = CGRectMake(0, self.view.bounds.size.height, self.view.bounds.size.width, 100)

self.view.addSubview(menuView)

UIView.animateWithDuration(0.6, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 0.8, options: .CurveEaseInOut, animations: { () -> Void in
var newMenuFrame = menuView.frame
newMenuFrame.origin.y = self.view.bounds.size.height - 63
menuView.frame = newMenuFrame
self.view.layoutIfNeeded()

}) { (success) -> Void in

let gestureRecognizer = UITapGestureRecognizer(target: self, action: #selector(HomeVC.hideOnTap(_:)))
gestureRecognizer.numberOfTapsRequired = 1
gestureRecognizer.delegate = self
self.view.addGestureRecognizer(gestureRecognizer)
}

}

func hideOnTap(recognizer: UITapGestureRecognizer) {
self.view.viewWithTag(5)?.removeFromSuperview()
}

@IBAction func changeAvatarBtn(sender: AnyObject) {

changePhoto()
}

override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}

func updateUI() {

if let imageLink = backendless.userService.currentUser.getProperty("Avatar") as? String {

getImageFromURL(imageLink, result: { (image) in
self.avatarImageView.image = image
})
}
}

@IBAction func testLogout(sender: AnyObject) {
showLogoutView()
}

func showLogoutView() {

let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
let logout = UIAlertAction(title: "Logout", style: .Destructive) { (alert : UIAlertAction!) in
self.logoutFunc()
}

let cancel = UIAlertAction(title: "Cancel", style: .Cancel) { (alert : UIAlertAction) in
//
}

optionMenu.addAction(logout)
optionMenu.addAction(cancel)

self.presentViewController(optionMenu, animated: true, completion: nil)
}

func logoutFunc() {

if FBSDKAccessToken.currentAccessToken() != nil {
let loginManager = FBSDKLoginManager()
loginManager.logOut()
}

backendless.userService.logout()
let registerVC = storyboard?.instantiateViewControllerWithIdentifier("RegisterVC")
self.presentViewController(registerVC!, animated: true, completion: nil)
}

func changePhoto() {

let camera = Camera(delegate_: self)

let optionMenu = UIAlertController(title: nil, message: nil, preferredStyle: .ActionSheet)
let takePhoto = UIAlertAction(title: "Camera", style: .Default) { (alert : UIAlertAction!) in
camera.presentPhotoCamera(self, canEdit: true)
}
let sharePhoto = UIAlertAction(title: "Library", style: .Default) { (alert : UIAlertAction) in
camera.presentPhotoLibrary(self, canEdit: true)
}
//MARK: TODO
/*let showPicture = UIAlertAction(title: "Show Picture", style: .Default) { (alert : UIAlertAction) in
//
}
let loadPicFromFacebook = UIAlertAction(title: "Load from Facebook", style: .Default) { (alert : UIAlertAction) in
//
}*/
let cancel = UIAlertAction(title: "Cancel", style: .Cancel) { (alert : UIAlertAction) in
//
}

optionMenu.addAction(takePhoto)
optionMenu.addAction(sharePhoto)
//optionMenu.addAction(showPicture)
//optionMenu.addAction(loadPicFromFacebook)
optionMenu.addAction(cancel)

self.presentViewController(optionMenu, animated: true, completion: nil)
}

func imagePickerController(picker: UIImagePickerController, didFinishPickingMediaWithInfo info: [String : AnyObject]) {

let image = info[UIImagePickerControllerEditedImage] as! UIImage
uploadAvatar(image) { (imageLink) in
let properties = ["Avatar" : imageLink!]
backendless.userService.currentUser.updateProperties(properties)
backendless.userService.update(backendless.userService.currentUser, response: { (updatedUser : BackendlessUser!) in

print("User: \(updatedUser.name) successfully updated")
self.updateUI()
}, error: { (fault : Fault!) in


print(fault)
})
}

picker.dismissViewControllerAnimated(true, completion: nil)
}

func dismissKeyboard() {
view.endEditing(true)
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
self.view.endEditing(true)
return false
}

override func preferredStatusBarStyle() -> UIStatusBarStyle {
return UIStatusBarStyle.LightContent;
}

func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCellWithIdentifier("djListCell", forIndexPath: indexPath) as! DJListCell
let user = deejays[indexPath.row]
//cell.textLabel?.text = user.name

cell.djNameLabel.text = user.getProperty("deejayName") as? String
cell.djGenreLabel.text = user.getProperty("genre") as? String

let imgURL = NSURL(string: user.getProperty("Avatar") as! String)
cell.djAvatarImageView.sd_setImageWithURL(imgURL)

let residentAt = user.getProperty("residentAt") as? String
cell.djResidentAtLabel.text = residentAt

/*
if let imageLink = user.getProperty("Avatar") as? String {

getImageFromURL(imageLink, result: { (image) in
cell.djAvatarImageView.image = image
})
}*/

let date = dateFormatter().dateFromString(user.getProperty("lastOnlineString") as! String)
let seconds = NSDate().timeIntervalSinceDate(date!)

if timeElapsed(seconds) != "Just now" {
cell.djLastOnlineLabel.text = "last online: \(timeElapsed(seconds)) ago"
} else {
cell.djLastOnlineLabel.text = timeElapsed(seconds)
}
return cell
}

func tableView(tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return deejays.count
}

func numberOfSectionsInTableView(tableView: UITableView) -> Int {
return 1
}

func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {

print("You selected cell #\(indexPath.row)!")
//let user = deejays[indexPath.row]
//delegade.createChatroom(user)

//self.tableView.deselectRowAtIndexPath(indexPath, animated: true)
//self.dismissViewControllerAnimated(true, completion: nil)

//let vc = UIStoryboard(name: "Main", bundle: nil).instantiateViewControllerWithIdentifier("DJProfileAsUserVC")


//dispatch_async(dispatch_get_main_queue()) {
// self.presentViewController(vc, animated: true, completion: nil)
//}



}

func loadDeejays() {

//let whereClause = "objectId != '\(backendless.userService.currentUser.objectId)'"
let whereClause = "isDJ = True"
let dataQuery = BackendlessDataQuery()
dataQuery.whereClause = whereClause

let dataStore = backendless.persistenceService.of(BackendlessUser.ofClass())
dataStore.find(dataQuery, response: { (users : BackendlessCollection!) in

self.deejays = users.data as! [BackendlessUser]
self.tableView.reloadData()

}) { (fault : Fault!) in
print("error: \(fault)")
}
}

func timeElapsed(seconds: NSTimeInterval) -> String {
let elapsed: String?
if seconds < 60 {
elapsed = "Just now"
} else if (seconds < 60 * 60) {
let minutes = Int(seconds / 60)

var minText = "min"
if minutes > 1 {
minText = "mins"
}
elapsed = "\(minutes) \(minText)"
} else if (seconds < 24 * 60 * 60) {
let hours = Int(seconds / (60 * 60))
var hourText = "hour"
if hours > 1 {
hourText = "hours"
}
elapsed = "\(hours) \(hourText)"
} else {
let days = Int(seconds / (24 * 60 * 60))
var dayText = "day"
if days > 1 {
dayText = "days"
}
elapsed = "\(days) \(dayText)"
}
return elapsed!
}

}

extension HomeVC: UIGestureRecognizerDelegate {
func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
return true
}
}

Answer

You should make your recognizer work with other recognizers by letting the method shouldRecognizeSimultaneouslyWithGestureRecognizer return true.

This can be done by extending your Controller:

extension YourViewController: UIGestureRecognizerDelegate {
    func gestureRecognizer(gestureRecognizer: UIGestureRecognizer, shouldRecognizeSimultaneouslyWithGestureRecognizer otherGestureRecognizer: UIGestureRecognizer) -> Bool {
        return true
    }
}

Additionally, you have to set the delegate your viewDidLoad:

gestureRecognizer.delegate = self
tap.delegate = self