简体   繁体   中英

tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) Doesn't work when I add a UITapGestureRecognizer to my custom UITableViewCell

I have a very primitive problem at hand and that is when I have a tap gesture recognizer added to my custom cell I cant call the didSelectRowAt method.

My Code is the following:

import UIKit

class LanguageViewController: UIViewController {

    @IBOutlet weak var titleLabel: AvenirUILabel!
    @IBOutlet weak var backButton: UIButton!
    @IBOutlet weak var submitButton: PinkUIButton!
    @IBOutlet weak var addLanguageButton: UIButton!
    @IBOutlet weak var addAnotherLanguageLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!

    @IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!

    var numberOfLanguagesSpoken = 2
    var pickersStartHeight: CGFloat!
    let downArrowImage = UIImage(named: "arrow_drop_down")
    let BGColor = UIColor.white.withAlphaComponent(0.1)
    var tag = 1001
    var selectedCellHeight: CGFloat = 88.0
    var unselectedCellHeight: CGFloat = 44.0
    var selectedCellIndexPath: IndexPath?
    let languages = ["Akan", "Amharic", "Arabic", "Assamese", "Awadhi", "Azerbaijani", "Balochi", "Belarusian", "Bengali", "Bhojpuri", "Burmese", "Cebuano", "Chewa", "Chhattisgarhi", "Chittagonian", "Czech", "Deccan", "Dhundhari", "Dutch", "Eastern Min", "English", "French", "Fula", "Gan Chinese", "German", "Greek", "Gujarati", "Haitian Creole", "Hakka", "Haryanvi", "Hausa", "Hiligaynon/Ilonggo", "Hindi ", "Hmong", "Hungarian", "Igbo", "Ilocano", "Italian", "Japanese", "Javanese", "Jin", "Kannada", "Kazakh", "Khmer", "Kinyarwanda", "Kirundi", "Konkani", "Korean", "Kurdish", "Madurese", "Magahi", "Maithili", "Malagasy", "Malay", "Malayalam", "Mandarin", "Marathi", "Marwari", "Mossi", "Nepali", "Northern Min", "Odia", "Oromo", "Pashto", "Persian", "Polish", "Portuguese", "Punjabi", "Quechua", "Romanian", "Russian", "Saraiki", "Serbo-Croatian", "Shona", "Sindhi", "Sinhalese", "Somali", "Southern Min", "Spanish", "Sundanese", "Swedish", "Sylheti", "Tagalog/Filipino", "Tamil", "Telugu", "Thai", "Turkish", "Turkmen", "Ukrainian", "Urdu", "Uyghur", "Uzbek", "Vietnamese", "Wu", "Xhosa", "Xiang ", "Yoruba", "Yue ", "Zhuang", "Zulu"]

    var proficiency = ["Basic","Conversational","Proficient","Fluent","Native"]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = backgroundTint

        //  initial set up

        let height = self.view.bounds.height

        titleLabel.textColor = .white

        backButton.addTarget(self, action: #selector(goBack), for: .allTouchEvents)

        tableView.dataSource = self
        tableView.delegate = self
        tableView.register(LanguageProficiencyTableViewCell.self, forCellReuseIdentifier: "Language")
        tableView.backgroundColor = backgroundTint
        tableView.allowsSelection = true
        tableViewHeightConstraint.constant = 2*height/9


        addLanguageButton.tintColor = .white
        addLanguageButton.addTarget(self, action: #selector(addNewLanguage), for: .allTouchEvents)

        addAnotherLanguageLabel.textColor = .white

        submitButton.addTarget(self, action: #selector(submitChanges), for: .allEvents)
    }

    override func viewWillLayoutSubviews() {
        unselectedCellHeight = self.view.bounds.height/9
        selectedCellHeight = CGFloat(unselectedCellHeight * 2.0)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

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

    func goBack() {
        self.dismiss(animated: true, completion: nil)
    }

    func submitChanges() {
        self.dismiss(animated: true) {
            //
        }
    }

    func addNewLanguage() {
        numberOfLanguagesSpoken += 1
        UIView.animate(withDuration: 0.5) {
            //
        }
    }

    /*
     // MARK: - Navigation

     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destinationViewController.
     // Pass the selected object to the new view controller.
     }
     */

}
extension LanguageViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfLanguagesSpoken
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Language", for: indexPath) as! LanguageProficiencyTableViewCell
        cell.parentVC = self
        cell.backgroundColor = .clear
        cell.languages = self.languages
        cell.proficiency = self.proficiency
        return cell
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if selectedCellIndexPath == indexPath {
            return selectedCellHeight
        } else {
            return unselectedCellHeight
        }
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        //
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if selectedCellIndexPath != nil && selectedCellIndexPath == indexPath as IndexPath {
            selectedCellIndexPath = nil
        } else {
            selectedCellIndexPath = indexPath as IndexPath
        }

        tableView.beginUpdates()
        tableView.endUpdates()

        if selectedCellIndexPath != nil {
            // This ensures, that the cell is fully visible once expanded
            tableView.scrollToRow(at: indexPath as IndexPath, at: .none, animated: true)
        }
    }

    func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        return indexPath
    }
}

import UIKit

class LanguageProficiencyTableViewCell: UITableViewCell {

    let languageLabel = IndentedTextUILabel()
    var languagePicker = UIPickerView()
    weak var parentVC: LanguageViewController!
    var cellHeight: CGFloat = 80
    var open = false
    var languages = [""]
    var proficiency = [""]
    var pickedLanguage = ""
    var pickedProficiency = ""

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.contentView.addSubview(languageLabel)
        self.contentView.addSubview(languagePicker)
        self.contentView.backgroundColor = .clear
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }

    override func layoutSubviews() {

        let width = self.bounds.width
        let height = cellHeight
        let BGColor = UIColor.white.withAlphaComponent(0.1)

        languageLabel.frame = CGRect(x: 0.0, y: 1.0, width: width, height: height - 1.0)
        languageLabel.textColor = .white
        languageLabel.backgroundColor = BGColor
        languageLabel.text = "Language(Proficiency)"
        languageLabel.leftInset = 25.0
        let downArrow = UIButton()
        let downArrowImage = UIImage(named: "arrow_drop_down")
        downArrow.setImage(downArrowImage, for: .normal)
        downArrow.center.y = height/2
        downArrow.center.x = 4 * width/5
        languageLabel.addSubview(downArrow)

        let tap = UITapGestureRecognizer(target: self, action: #selector(cellTapped))
        self.addGestureRecognizer(tap)

        languagePicker.frame = CGRect(x: 0.0, y: self.cellHeight + 1.0, width: self.bounds.width, height: 0.0)
        languagePicker.delegate = self
        languagePicker.dataSource = self
        languagePicker.backgroundColor = UIColor.white.withAlphaComponent(0.05)
        languagePicker.selectRow(20, inComponent: 0, animated: true)

        let backGroundView = UIView(frame: CGRect(x: 0.0, y: 1.0, width: width, height: height - 1.0))
        backGroundView.backgroundColor = .clear
        self.selectedBackgroundView = backGroundView
    }

    func cellTapped() {
        UIView.animate(withDuration: 0.2, animations: {
            if !self.open {
                self.languagePicker.frame.size.height = self.cellHeight - 2.0
            } else {
                self.languagePicker.isHidden = true
            }
            }, completion: { (_) in
                if self.open {
                    self.languagePicker.frame.size.height = 0.0
                    self.languagePicker.isHidden = false
                }
                self.open = !self.open
        })
    }
}

It will not work because the tap gesture is taking the tap on itself and not sending the tap to the views underneath it.

You can make the tap gesture send the tap to be passed to the background views by

mySwipeGesture.cancelsTouchesInView = false

as described in How to pass a 'tap' to UIButton that is underneath UIView with UISwipeGestureRecognizer?

Also if you are using tap gesture just to dismiss your keyboard you can do so in didSelectAt method of the tableView and do any other thing after dismissing the keyboard in that method.

I'm doing something like what you have done and it's working for me.

You have to add the gesture recognizer not inside the TableViewCell class but from your Controller class when you set the cell.

Like this:

class LanguageViewController: UIViewController {

    @IBOutlet weak var titleLabel: AvenirUILabel!
    @IBOutlet weak var backButton: UIButton!
    @IBOutlet weak var submitButton: PinkUIButton!
    @IBOutlet weak var addLanguageButton: UIButton!
    @IBOutlet weak var addAnotherLanguageLabel: UILabel!
    @IBOutlet weak var tableView: UITableView!

    @IBOutlet weak var tableViewHeightConstraint: NSLayoutConstraint!

    var numberOfLanguagesSpoken = 2
    var pickersStartHeight: CGFloat!
    let downArrowImage = UIImage(named: "arrow_drop_down")
    let BGColor = UIColor.white.withAlphaComponent(0.1)
    var tag = 1001
    var selectedCellHeight: CGFloat = 88.0
    var unselectedCellHeight: CGFloat = 44.0
    var selectedCellIndexPath: IndexPath?
    let languages = ["Akan", "Amharic", "Arabic", "Assamese", "Awadhi", "Azerbaijani", "Balochi", "Belarusian", "Bengali", "Bhojpuri", "Burmese", "Cebuano", "Chewa", "Chhattisgarhi", "Chittagonian", "Czech", "Deccan", "Dhundhari", "Dutch", "Eastern Min", "English", "French", "Fula", "Gan Chinese", "German", "Greek", "Gujarati", "Haitian Creole", "Hakka", "Haryanvi", "Hausa", "Hiligaynon/Ilonggo", "Hindi ", "Hmong", "Hungarian", "Igbo", "Ilocano", "Italian", "Japanese", "Javanese", "Jin", "Kannada", "Kazakh", "Khmer", "Kinyarwanda", "Kirundi", "Konkani", "Korean", "Kurdish", "Madurese", "Magahi", "Maithili", "Malagasy", "Malay", "Malayalam", "Mandarin", "Marathi", "Marwari", "Mossi", "Nepali", "Northern Min", "Odia", "Oromo", "Pashto", "Persian", "Polish", "Portuguese", "Punjabi", "Quechua", "Romanian", "Russian", "Saraiki", "Serbo-Croatian", "Shona", "Sindhi", "Sinhalese", "Somali", "Southern Min", "Spanish", "Sundanese", "Swedish", "Sylheti", "Tagalog/Filipino", "Tamil", "Telugu", "Thai", "Turkish", "Turkmen", "Ukrainian", "Urdu", "Uyghur", "Uzbek", "Vietnamese", "Wu", "Xhosa", "Xiang ", "Yoruba", "Yue ", "Zhuang", "Zulu"]

    var proficiency = ["Basic","Conversational","Proficient","Fluent","Native"]

    override func viewDidLoad() {
        super.viewDidLoad()

        self.view.backgroundColor = backgroundTint

        //  initial set up

        let height = self.view.bounds.height

        titleLabel.textColor = .white

        backButton.addTarget(self, action: #selector(goBack), for: .allTouchEvents)

        tableView.dataSource = self
        tableView.delegate = self
        tableView.register(LanguageProficiencyTableViewCell.self, forCellReuseIdentifier: "Language")
        tableView.backgroundColor = backgroundTint
        tableView.allowsSelection = true
        tableViewHeightConstraint.constant = 2*height/9


        addLanguageButton.tintColor = .white
        addLanguageButton.addTarget(self, action: #selector(addNewLanguage), for: .allTouchEvents)

        addAnotherLanguageLabel.textColor = .white

        submitButton.addTarget(self, action: #selector(submitChanges), for: .allEvents)
    }

    override func viewWillLayoutSubviews() {
        unselectedCellHeight = self.view.bounds.height/9
        selectedCellHeight = CGFloat(unselectedCellHeight * 2.0)
    }

    override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
        self.view.endEditing(true)
    }

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

    func goBack() {
        self.dismiss(animated: true, completion: nil)
    }

    func submitChanges() {
        self.dismiss(animated: true) {
            //
        }
    }

    func addNewLanguage() {
        numberOfLanguagesSpoken += 1
        UIView.animate(withDuration: 0.5) {
            //
        }
    }

    /*
     // MARK: - Navigation

     // In a storyboard-based application, you will often want to do a little preparation before navigation
     override func prepare(for segue: UIStoryboardSegue, sender: Any?) {
     // Get the new view controller using segue.destinationViewController.
     // Pass the selected object to the new view controller.
     }
     */

}
extension LanguageViewController: UITableViewDataSource, UITableViewDelegate {

    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return numberOfLanguagesSpoken
    }

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Language", for: indexPath) as! LanguageProficiencyTableViewCell
        cell.parentVC = self
        cell.backgroundColor = .clear
        cell.languages = self.languages
        cell.proficiency = self.proficiency
        let tap = UITapGestureRecognizer(target: self, action: #selector("cellTapped:"))
        cell.addGestureRecognizer(tap)
        return cell
    }

    //Change here you can't call languagePicker with self but you have to get it from the object tapped that in your case is you cell
    func cellTapped(recognizer: UITapGestureRecognizer) {
        UIView.animate(withDuration: 0.2, animations: {
            if !self.open {
                self.languagePicker.frame.size.height = self.cellHeight - 2.0
            } else {
                self.languagePicker.isHidden = true
            }
            }, completion: { (_) in
                if self.open {
                    self.languagePicker.frame.size.height = 0.0
                    self.languagePicker.isHidden = false
                }
                self.open = !self.open
        })
    }

    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        if selectedCellIndexPath == indexPath {
            return selectedCellHeight
        } else {
            return unselectedCellHeight
        }
    }

    func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
        //
    }

    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if selectedCellIndexPath != nil && selectedCellIndexPath == indexPath as IndexPath {
            selectedCellIndexPath = nil
        } else {
            selectedCellIndexPath = indexPath as IndexPath
        }

        tableView.beginUpdates()
        tableView.endUpdates()

        if selectedCellIndexPath != nil {
            // This ensures, that the cell is fully visible once expanded
            tableView.scrollToRow(at: indexPath as IndexPath, at: .none, animated: true)
        }
    }

    func tableView(_ tableView: UITableView, willSelectRowAt indexPath: IndexPath) -> IndexPath? {
        return indexPath
    }
}

import UIKit

class LanguageProficiencyTableViewCell: UITableViewCell {

    let languageLabel = IndentedTextUILabel()
    var languagePicker = UIPickerView()
    weak var parentVC: LanguageViewController!
    var cellHeight: CGFloat = 80
    var open = false
    var languages = [""]
    var proficiency = [""]
    var pickedLanguage = ""
    var pickedProficiency = ""

    override func awakeFromNib() {
        super.awakeFromNib()
        // Initialization code
    }

    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)

        self.contentView.addSubview(languageLabel)
        self.contentView.addSubview(languagePicker)
        self.contentView.backgroundColor = .clear
    }

    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }

    override func layoutSubviews() {

        let width = self.bounds.width
        let height = cellHeight
        let BGColor = UIColor.white.withAlphaComponent(0.1)

        languageLabel.frame = CGRect(x: 0.0, y: 1.0, width: width, height: height - 1.0)
        languageLabel.textColor = .white
        languageLabel.backgroundColor = BGColor
        languageLabel.text = "Language(Proficiency)"
        languageLabel.leftInset = 25.0
        let downArrow = UIButton()
        let downArrowImage = UIImage(named: "arrow_drop_down")
        downArrow.setImage(downArrowImage, for: .normal)
        downArrow.center.y = height/2
        downArrow.center.x = 4 * width/5
        languageLabel.addSubview(downArrow)

        languagePicker.frame = CGRect(x: 0.0, y: self.cellHeight + 1.0, width: self.bounds.width, height: 0.0)
        languagePicker.delegate = self
        languagePicker.dataSource = self
        languagePicker.backgroundColor = UIColor.white.withAlphaComponent(0.05)
        languagePicker.selectRow(20, inComponent: 0, animated: true)

        let backGroundView = UIView(frame: CGRect(x: 0.0, y: 1.0, width: width, height: height - 1.0))
        backGroundView.backgroundColor = .clear
        self.selectedBackgroundView = backGroundView
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM