Custom TableViewCell, с textField и внутренним DatePicker


#1

Добрый вечер. В TextField кодом встроен DatePicker. Пытаюсь сделать так, чтобы при изменении значения DatePicker в поле TextField обновлялось значение. Но получить доступ к sender: UITextField, чтобы обратиться к text не могу. Как быть? Спасибо.


#2

Сделайте кастомный textfield:

class DateTextField: UITextField {

    var date: Date {
        get { return (inputView as! UIDatePicker).date }
        set { (inputView as! UIDatePicker).date = newValue }
    }
    
    private lazy var dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"
        return dateFormatter
    }()
    
    override func awakeFromNib() {
        super.awakeFromNib()
        let toolBar = UIToolbar()
        toolBar.translatesAutoresizingMaskIntoConstraints = false
        toolBar.items = [
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
            UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneButtonAction))
        ]
        inputAccessoryView = toolBar
        
        let datePicker = UIDatePicker()
        datePicker.datePickerMode = .date
        datePicker.addTarget(self, action: #selector(changeDate), for: .valueChanged)
        inputView = datePicker
    }
    
    @objc func changeDate() {
        text = dateFormatter.string(from: date)
    }
    
    @objc func doneButtonAction() {
        _ = delegate?.textFieldShouldReturn?(self)
    }
}

Пример.


#3

Скажите, как обратиться к DateTextField чтобы получить datePicker в ViewController и в дальнейшем присвоить ячейке под определенным индексом?
Пробовала через экземпляр, но к Void обратиться нельзя. Также ещё пыталась присвоить dateTextField.inputView, но ничего не происходит. Как быть? Спасибо.


#4

Смотрите пример, там две ячейки у одной из которых DateTextField (присвоен в IB)

И обратиться к нему можно через ячейку:

let cell = tableView.cellForRow(at: [0, 1]) as! TableViewCell
let dateTextField = cell.textField as! DateTextField

#5

Одни ошибки. Скоро с ума сойду. :dizzy_face:
Не могли бы Вы помочь?


#6

Поняла в чём ошибка, но как её исправить – не пойму.
Вы на скриншоте показали на класс. Вот в нём и загвоздка. Я не могу присвоить textField этот класс способом показанным Вами. Можно ли это как-то в коде совершить?
Прим.: у меня есть индекс ячейки textField [0,3], и когда по итерации идёт он, присвоить этому textField класс DateTextField.


#7

Нужно выбрать UITextField.

Придётся всю ячейку делать в коде, что для вас явно не проще.


#8

Ну, проще или нет – за этим вопрос не стоит. Главное – как.
Я правильно Вас понимаю, что в файле TableViewCell, нужно делегировать UITextField и его методы, а дальше там присваивать поля text? Или нет?


#9
class DateTextField: UITextField {

    var date: Date {
        get { return (inputView as! UIDatePicker).date }
        set { (inputView as! UIDatePicker).date = newValue }
    }
    
    private lazy var dateFormatter: DateFormatter = {
        let dateFormatter = DateFormatter()
        dateFormatter.dateFormat = "MM/dd/yyyy"
        return dateFormatter
    }()
    
    init() {
        super.init(frame: CGRect())
        let toolBar = UIToolbar()
        toolBar.translatesAutoresizingMaskIntoConstraints = false
        toolBar.items = [
            UIBarButtonItem(barButtonSystemItem: .flexibleSpace, target: nil, action: nil),
            UIBarButtonItem(title: "Done", style: .plain, target: self, action: #selector(doneButtonAction))
        ]
        inputAccessoryView = toolBar
        
        let datePicker = UIDatePicker()
        datePicker.datePickerMode = .date
        datePicker.addTarget(self, action: #selector(changeDate), for: .valueChanged)
        inputView = datePicker
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
    
    @objc func changeDate() {
        text = dateFormatter.string(from: date)
    }
    
    @objc func doneButtonAction() {
        _ = delegate?.textFieldShouldReturn?(self)
    }
}
class TableViewCell: UITableViewCell {

    var label: UILabel!
    var textField: DateTextField!
    
    override init(style: UITableViewCellStyle, reuseIdentifier: String?) {
        super.init(style: style, reuseIdentifier: reuseIdentifier)
        label = UILabel()
        label.translatesAutoresizingMaskIntoConstraints = false
        contentView.addSubview(label)
        label.leftAnchor.constraint(equalTo: contentView.leftAnchor, constant: 16).isActive = true
        label.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        label.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        label.heightAnchor.constraint(equalToConstant: 40).isActive = true
        label.widthAnchor.constraint(equalToConstant: 100).isActive = true
        
        textField = DateTextField()
        textField.backgroundColor = .red
        contentView.addSubview(textField)
        textField.translatesAutoresizingMaskIntoConstraints = false
        textField.leftAnchor.constraint(equalTo: label.rightAnchor, constant: 8).isActive = true
        textField.topAnchor.constraint(equalTo: contentView.topAnchor).isActive = true
        textField.rightAnchor.constraint(equalTo: contentView.rightAnchor, constant: 16).isActive = true
        textField.bottomAnchor.constraint(equalTo: contentView.bottomAnchor).isActive = true
        
    }
    
    required init?(coder aDecoder: NSCoder) {
        fatalError("init(coder:) has not been implemented")
    }
}
class TableViewController: UITableViewController {

    override func viewDidLoad() {
        super.viewDidLoad()
        tableView.register(TableViewCell.self, forCellReuseIdentifier: "tableViewCell")
    }

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

    override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! TableViewCell
        cell.label.text = "\(indexPath)"
        cell.textField.placeholder = "\(indexPath)"
        return cell
    }
}

Делегатом должен быть контроллер. Лучше создаете пустой проект и попробуйте сделать в нём всё как в моём примере, так есть шанс что вы самостоятельно разберетесь и сможете использовать это в своём проекте.


#10

Возвращаюсь к началу.
Имеется файл DateTextField, как его присвоить sender в editingBeginTextField, без явного указания class в Identity inspector? Причём, присвоить нужно только одному полю по индексу [0,3].
Ну вот никак не могу разобраться, который день над этой проблемой сижу.


#11

В итоге, китайскими путями да получилось.
Перед основным классом сделала счётчик, и потом в файле DateTextField присваивала, когда нужно.