Passing parameters to a Selector in Swift using UITapGestureRecognizer, UIImageView and UITableViewCell - swift

I need to identify the image that the user clicked on a TableCell.
How to pass TAG?
class CustomCell: UITableViewCell {
#IBOutlet weak var imgPost1: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
imgPost1.tag=1
let tap = UITapGestureRecognizer(target: self, action: #selector(CustomCell.tappedMe))
imgPost1.addGestureRecognizer(tap)
imgPost1.userInteractionEnabled = true
}
func tappedMe(xTag:Int) {
print(xTag)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
}

You can use the view property of the UIGestureRecognizer.
Register for tap gesture:
let tap = UITapGestureRecognizer(target: self, action: "tappedMe:")
imgPost1.addGestureRecognizer(tap)
imgPost1.userInteractionEnabled = true
Now define the tappedMe method
func tappedMe(sender: UITapGestureRecognizer) {
print(sender.view?.tag)
}
PS: Don't forget to set the tag for image

Related

PerformSegue from long press on a a custom UiTableViewCell

maybe the question has been asked several times, but can't find it.
I'm a newbie.
I have a UITableView with a custom UITableViewCell.
in the cell there are 3 different labels.
I added the gesture recognizer on the custom cell, so that if long press is done on a label :
- label 1 should show another UiViewController
- label 2 should do a call
- label 3 should create a mail
for labels 2 and 3 i had no problem
but how to perform the segue to open the view controller ?
This is the storyboard
This is the custom tableviewcell
import UIKit
import MessageUI
class OfficeCell: UITableViewCell, MFMailComposeViewControllerDelegate {
#IBOutlet weak var lbOffice: UILabel!
#IBOutlet weak var lbAddress: UILabel!
#IBOutlet weak var lbPhone: UILabel!
#IBOutlet weak var lbMail: UILabel!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
}
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
self.setupLabelTap()
// Configure the view for the selected state
}
func setupLabelTap() {
let lbAddressTap = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressReconizer(_:)))
self.lbAddress.isUserInteractionEnabled = true
self.lbAddress.addGestureRecognizer(lbAddressTap)
let lbAddressTap2 = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressReconizer(_:)))
self.lbMail.isUserInteractionEnabled = true
self.lbMail.addGestureRecognizer(lbAddressTap2)
let lbAddressTap3 = UILongPressGestureRecognizer(target: self, action: #selector(self.longPressReconizer(_:)))
self.lbPhone.isUserInteractionEnabled = true
self.lbPhone.addGestureRecognizer(lbAddressTap3)
}
#objc func longPressReconizer(_ sender: UITapGestureRecognizer) {
print("labelTapped")
let etichetta :UILabel = sender.view as! UILabel
print (etichetta.text!)
switch etichetta.tag {
case 0:
self.performSegue(withIdentifier: "moveToMaps", sender: self)
case 1:
let telNumber = etichetta.text!.replacingOccurrences(of: " ", with: "")
if let phoneCallURL = URL(string: "telprompt://\(telNumber)") {
let application:UIApplication = UIApplication.shared
if (application.canOpenURL(phoneCallURL)) {
application.open(phoneCallURL, options: [:], completionHandler: nil)
}
}
case 2:
if MFMailComposeViewController.canSendMail() {
let mail = MFMailComposeViewController()
mail.mailComposeDelegate = self
mail.setToRecipients([etichetta.text!])
mail.setSubject("Informazioni")
self.window?.rootViewController?.present(mail, animated: true)
} else {
// show failure alert
}
default:
print("default")
}
}
func mailComposeController(_ controller:MFMailComposeViewController, didFinishWith result: MFMailComposeResult, error: Error?) {
controller.dismiss(animated: true)
}
}
but Xcode give me this error
Value of type 'OfficeCell' has no member 'performSegue'
on
self.performSegue(withIdentifier: "moveToMaps", sender: self)
how to achieve what i need ?
Thanks in advance
Fabrizio
you need to implement delegate and perform segue from main class because cell class can't perform segue ... in storyBoard attach "moveToMaps" segue from main controller
protocol CellDelegate {
func didTapAddressButton()
}
class OfficeCell: UITableViewCell, MFMailComposeViewControllerDelegate {
var delegate: CellDelegate?
}
In your main View controller class
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "OfficeCell", for: indexPath) as! OfficeCell
cell.delegate = self
return cell
}
extension MainController: CellDelegate {
func didTapAddressButton(){
self.performSegue(withIdentifier: "moveToMaps", sender: self)
}
}

Views not performing segue

I have a collection of views and I want to make that when they are tapped, it will perform the same segue. and no view performs any segue.
class ViewController: UIViewController {
#IBOutlet var categoryViews: [UIView]!
let tapGesture = UIGestureRecognizer(target: self, action: #selector(ViewController.move(tap:)))
override func viewDidLoad() {
super.viewDidLoad()
for category in (0..<categoryViews.count) {
categoryViews[category].addGestureRecognizer(tapGesture)
categoryViews[category].isUserInteractionEnabled = true
}
// Do any additional setup after loading the view.
}
#objc func move(tap: UIGestureRecognizer) {
performSegue(withIdentifier: "Animals", sender: nil)
}
}
A single instance of UITapGestureRecognizer can be added to a single view.
In your code, since you're using a single instance of UITapGestureRecognizer for each view, the tapGesture will be added only to the last view in categoryViews array.
You need to create different UITapGestureRecognizer instance for each view in categoryViews, i.e.
class ViewController: UIViewController {
#IBOutlet var categoryViews: [UIView]!
override func viewDidLoad() {
super.viewDidLoad()
categoryViews.forEach {
let tapGesture = UITapGestureRecognizer(target: self, action: #selector(move(tap:)))
$0.addGestureRecognizer(tapGesture)
$0.isUserInteractionEnabled = true
}
}
#objc func move(tap: UITapGestureRecognizer) {
performSegue(withIdentifier: "Animals", sender: nil)
}
}
The problem is that this code doesn't do what you think it does:
class ViewController: UIViewController {
let tapGesture = UIGestureRecognizer(target: self, action: #selector(ViewController.move(tap:)))
Your let tapGesture is an instance property declaration, and what follows the equal sign is its initializer. But you can't speak of self in an instance property initializer; there is no instance yet. So self here is taken to be the class. Thus, your tap gesture recognizer "works", but the move message is not sent to your ViewController instance; in effect, it is sent into empty space.
To fix this, you can initialize tapGesture at a time when self does exist. For example:
class ViewController: UIViewController {
let tapGesture : UIGestureRecognizer!
func viewDidLoad() {
self.tapGesture = UITapGestureRecognizer(target: self, action: #selector(ViewController.move(tap:)))

Deselect the text in a NSTextField

Is there an easy way to deselect an NSTextField after pressing enter?
First you will need to make your view controller the delegate of your text field. Then you override NSControl instance method controlTextDidEndEditing(_:), get your textfield current editor selected range
and from the main thread set it back to your textfield:
import Cocoa
class ViewController: NSViewController, NSTextFieldDelegate {
#IBOutlet weak var textField: NSTextField!
override func viewDidLoad() {
super.viewDidLoad()
textField.delegate = self
}
override func controlTextDidEndEditing(_ obj: Notification) {
if let selectedRange = textField.currentEditor()?.selectedRange {
DispatchQueue.main.async {
self.textField.currentEditor()?.selectedRange = selectedRange
}
}
}
}
Here is one way I did it.
By disabling it with isSelectable and isEditable and then setting a timer to re-enable it after 0.5s
#IBAction func timeCodeChanged(_: NSTextField) {
timecodeLabel.isSelectable = false
timecodeLabel.isEditable = false
Timer.scheduledTimer(timeInterval: 0.5, target: self, selector: #selector(reEnableLabel), userInfo: nil, repeats: false)
}
#objc func reEnableLabel() {
timecodeLabel.isSelectable = true
timecodeLabel.isEditable = true
}

How to get cell index from uiview in uitableviewcell (swift/xcode)

I have two UIViewControllers called upVote and downVote in MyTableViewCell class. I have added the gesture recognizers for tapping these views programmatically but am not sure how to get the parent cell or index of the cell so I know which cell the UIView that was tapped is in. How do I get the cell or index of the tapped cell in the functions handleTapUp and handleTapDown?
Here is my class
class MyTableViewCell: UITableViewCell {
// MARK: Properties
#IBOutlet weak var nameLabel: UILabel!
#IBOutlet weak var upVote: UIImageView!
#IBOutlet weak var downVote: UIImageView!
override func awakeFromNib() {
super.awakeFromNib()
// Initialization code
let tapUp = UITapGestureRecognizer(target: self, action: "handleTapUp:")
tapUp.delegate = self
upVote.addGestureRecognizer(tapUp)
let tapDown = UITapGestureRecognizer(target: self, action: "handleTapDown:")
tapDown.delegate = self
downVote.addGestureRecognizer(tapDown)
}
override func setSelected(selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
// Configure the view for the selected state
}
func handleTapUp(sender: UITapGestureRecognizer? = nil) {
// handling code
// get cell(index)
}
func handleTapDown(sender: UITapGestureRecognizer? = nil) {
// handling code
// get cell()
}
}
I have tried self.superclass to get the uitableviewcell, and when i print the debug description it say uitableviewcell, but whenever I try to do anything else with the object I get an error that self.superclass is type AnyObject. I have tried declaring/casting self.superclass in many different ways and none have worked. This seems like it should be simple so hopefully I am missing something.
Declare a variable in your customCellClass:-
var indexForCell : NSIndexPath!
In your ViewControllers where you are dequeing the cells in the function func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell add this :-
cell.indexForCell = indexPath
Now access the indexForCell in your functions in your class:-
func handleTapUp(sender: UITapGestureRecognizer? = nil) {
let rowValue = indexForCell.row
}
func handleTapDown(sender: UITapGestureRecognizer? = nil) {
// handling code
// get cell()
}

Possible to add tag to a static cell within a Dynamic Prototype UITableView? (Swift)

I have a Dynamic Prototype table that also has a few static cell. I am trying to allow one of these static cells to have two textfields within the single cell. I believe to do this, I will need to set tags for each of the textfields.
But, I am not sure how (if possible) to assign the tags to the below lines.
TableViewController:
case DiveMasterIndex:
cell = tableView.dequeueReusableCellWithIdentifier(Resource.DiveMasterCell)
(cell as! DiveMasterTableViewCell).textField.placeholder = Strings.DiveMaster.localized // tag 1001
case DiveMasterIDIndex:
cell = tableView.dequeueReusableCellWithIdentifier(Resource.DiveMasterCell)
(cell as! DiveMasterIDTableViewCell).textField.placeholder = Strings.DiveMasterID.localized // tag 1002
The two TableViewCells
class DiveMasterTableViewCell: UITableViewCell, UITextFieldDelegate
{
#IBOutlet var textField: UITextField!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
func textFieldDidEndEditing(textField: UITextField)
{
(self.tableViewController as! DiveDetailsNew2TableVC).diveModel.name = textField.text!
}
the second
class DiveMasterIDTableViewCell: UITableViewCell, UITextFieldDelegate
{
#IBOutlet var textField: UITextField!
override func awakeFromNib()
{
super.awakeFromNib()
}
override func setSelected(selected: Bool, animated: Bool)
{
super.setSelected(selected, animated: animated)
}
func textFieldDidEndEditing(textField: UITextField)
{
(self.tableViewController as! DiveDetailsNew2TableVC).diveModel.name = textField.text!
}
If you want one cell to have 2 textfields better way would be to create 2 outlets with different names for text fields instead of assigning tags to them. You do not need 2 cells for such case.