Can't Select UITextField in UITableView

Summary

Hello Apple Developers,

I've made a custom UITableViewCell that includes a UITextField and UILabel. When I run the simulation the UITableViewCells pop up with the UILabel and the UITextField, but the UITextField isn't clickable so the user can't enter information. Please help me figure out the problem.

Thank You!

Sampson

What I want:

What I have:

Screenshot Details:

As you can see when I tap on the cell the UITextField isn't selected. I even added placeholder text to the UITextField to see if I am selecting the UITextField and the keyboard just isn't popping up, but still nothing.

Relevant Code:

UHTextField

import UIKit

class UHTextField: UITextField {

    override init(frame: CGRect) {
        super.init(frame: frame)
        configure()
    }
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    convenience init(placeholder: String) {
        self.init(frame: .zero)
        
        self.placeholder = placeholder
    }
    
    private func configure() {
        translatesAutoresizingMaskIntoConstraints = false
        
        borderStyle                 = .none
        
        textColor                   = .label
        tintColor                   = .blue
        textAlignment               = .left
        font = UIFont.preferredFont(forTextStyle: .body)
        adjustsFontSizeToFitWidth   = true
        minimumFontSize             = 12
        
        backgroundColor             = .tertiarySystemBackground
        autocorrectionType          = .no
    }
    
}

UHTableTextFieldCell

import UIKit

class UHTableTextFieldCell: UITableViewCell, UITextFieldDelegate {
    
    static let reuseID  = "TextFieldCell"
    let titleLabel      = UHTitleLabel(textAlignment: .center, fontSize: 16, textColor: .label)
    let tableTextField  = UHTextField()
    
    
    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        configure()
    }
    
    
    required init?(coder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    
    func set(title: String) {
        titleLabel.text = title
        tableTextField.placeholder = "Enter " + title
    }
    
    
    private func configure() {
        addSubviews(titleLabel, tableTextField)
        
        let padding: CGFloat = 12
        
        NSLayoutConstraint.activate([
            titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding),
            titleLabel.heightAnchor.constraint(equalToConstant: 20),
            titleLabel.widthAnchor.constraint(equalToConstant: 80),
            
            tableTextField.centerYAnchor.constraint(equalTo: centerYAnchor),
            tableTextField.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 24),
            tableTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding),
            tableTextField.heightAnchor.constraint(equalToConstant: 20)
        ])
    }
}

LoginViewController

class LoginViewController: UIViewController, UITextFieldDelegate {
    let tableView                   = UITableView()
    let loginTableTitle             = ["Username", "Password"]

    override func viewDidLoad() {
        super.viewDidLoad()

        configureTableView()
        updateUI()
        createDismissKeyboardTapGesture()
    }


    func createDismissKeyboardTapGesture() {
        // create the tap gesture recognizer
        let tap = UITapGestureRecognizer(target: self.view, action: #selector(UIView.endEditing))
        
        // add it to the view (Could also add this to an image or anything)
        view.addGestureRecognizer(tap)
    }


    func configureTableView() {
        view.addSubview(tableView)
        
        tableView.layer.borderWidth = 1
        tableView.layer.borderColor = UIColor.systemBackground.cgColor
        tableView.layer.cornerRadius = 10
        tableView.clipsToBounds = true
        
        tableView.rowHeight     = 44
        tableView.delegate      = self
        tableView.dataSource    = self
        
        tableView.translatesAutoresizingMaskIntoConstraints = false
        
        tableView.removeExcessCells()
        
        NSLayoutConstraint.activate([
            tableView.topAnchor.constraint(equalTo: loginTitleLabel.bottomAnchor, constant: padding),
            tableView.leadingAnchor.constraint(equalTo: view.leadingAnchor, constant: padding),
            tableView.trailingAnchor.constraint(equalTo: view.trailingAnchor, constant: -padding),
            tableView.heightAnchor.constraint(equalToConstant: 88)
        ])
        
        tableView.register(UHTableTextFieldCell.self, forCellReuseIdentifier: UHTableTextFieldCell.reuseID)
        
    }


    func updateUI() {
        DispatchQueue.main.async {
            self.tableView.reloadData()
            self.view.bringSubviewToFront(self.tableView)
        }
    }
}


extension LoginViewController: UITableViewDelegate, UITableViewDataSource{
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return 2
    }
    
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: UHTableTextFieldCell.reuseID, for: indexPath) as! UHTableTextFieldCell
        let titles = loginTableTitle[indexPath.row]
        cell.set(title: titles)
        cell.titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .bold)
        cell.tableTextField.delegate = self
        return cell
    }
}

Again thank you all so much for your help. If you need more clarification on this let me know.

Accepted Reply

I figured out the solution. Thank you so much Claude31 your solution put me on the right path.

LoginViewController

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: UHTableTextFieldCell.reuseID, for: indexPath) as! UHTableTextFieldCell
        let titles = loginTableTitle[indexPath.row]
        cell.set(title: titles)
        cell.titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .bold)
        cell.contentView.isUserInteractionEnabled = false  // <----
        return cell
    }

UHTableTextFieldCell

The selection still worked without this next section, but I think I should still include it.

    private func configure() {
        addSubviews(titleLabel, tableTextField)
        
        self.isUserInteractionEnabled   = true // <----
        tableTextField.delegate         = self // <----
        
        let padding: CGFloat = 12
        
        NSLayoutConstraint.activate([
            titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding),
            titleLabel.heightAnchor.constraint(equalToConstant: 20),
            titleLabel.widthAnchor.constraint(equalToConstant: 80),
            
            tableTextField.centerYAnchor.constraint(equalTo: centerYAnchor),
            tableTextField.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 24),
            tableTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding),
            tableTextField.heightAnchor.constraint(equalToConstant: 20)
        ])
    }

Replies

Check that userInteraction is enabled.

For instance, in private func configure()

         self.isUserInteractionEnabled = true
  • Hello Claude! I added this to the code and the UITextField is still not clickable. Do you have any more suggestions?

Add a Comment

I figured out the solution. Thank you so much Claude31 your solution put me on the right path.

LoginViewController

    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: UHTableTextFieldCell.reuseID, for: indexPath) as! UHTableTextFieldCell
        let titles = loginTableTitle[indexPath.row]
        cell.set(title: titles)
        cell.titleLabel.font = UIFont.systemFont(ofSize: 16, weight: .bold)
        cell.contentView.isUserInteractionEnabled = false  // <----
        return cell
    }

UHTableTextFieldCell

The selection still worked without this next section, but I think I should still include it.

    private func configure() {
        addSubviews(titleLabel, tableTextField)
        
        self.isUserInteractionEnabled   = true // <----
        tableTextField.delegate         = self // <----
        
        let padding: CGFloat = 12
        
        NSLayoutConstraint.activate([
            titleLabel.centerYAnchor.constraint(equalTo: centerYAnchor),
            titleLabel.leadingAnchor.constraint(equalTo: leadingAnchor, constant: padding),
            titleLabel.heightAnchor.constraint(equalToConstant: 20),
            titleLabel.widthAnchor.constraint(equalToConstant: 80),
            
            tableTextField.centerYAnchor.constraint(equalTo: centerYAnchor),
            tableTextField.leadingAnchor.constraint(equalTo: titleLabel.trailingAnchor, constant: 24),
            tableTextField.trailingAnchor.constraint(equalTo: trailingAnchor, constant: -padding),
            tableTextField.heightAnchor.constraint(equalToConstant: 20)
        ])
    }