Как получить текст TextField, расположенный внутри collectionviewcell?

Я новичок в Swift, я пытаюсь получить текст, введенный пользователем в TextField, который находится внутри ячейки представления коллекции. У меня есть CollectionViewCell с именем «PestañaCero», где я создал TextField, вот этот:

import Foundation
import UIKit

class PestañaCero: UICollectionViewCell
{


    let NombreUsuarioTextField: UITextField =
    {
       let nombre = UITextField()
        nombre.borderStyle = UITextBorderStyle.roundedRect
        nombre.placeholder = "Nombre de Usuario"
        nombre.textAlignment = .center
        return nombre
    }()

    let NumerodeContactoTextField: UITextField =
    {
        let nombre = UITextField()
        nombre.borderStyle = UITextBorderStyle.roundedRect
        nombre.placeholder = "Numero de Contacto"
        nombre.textAlignment = .center
        return nombre
    }()

    let DireccionOrigenTextField: UITextField =
    {
        let nombre = UITextField()
        nombre.borderStyle = UITextBorderStyle.roundedRect
        nombre.placeholder = "Direccion de Origen"
        nombre.textAlignment = .center
        return nombre
    }()

    let DireccionDestinoTextField: UITextField =
    {
        let nombre = UITextField()
        nombre.borderStyle = UITextBorderStyle.roundedRect
        nombre.placeholder = "Direccion de Destino"
        nombre.textAlignment = .center
        return nombre
    }()

    func setupViews()
    {
        addSubview(NombreUsuarioTextField)
        addSubview(NumerodeContactoTextField)
        addSubview(DireccionOrigenTextField)
        addSubview(DireccionDestinoTextField)


        //VERTICAL CONSTRAINT

        addConstraintsWithFormat("H:|-16-[v0]-16-|", views: NombreUsuarioTextField)
        addConstraintsWithFormat("H:|-16-[v0]-16-|", views: NumerodeContactoTextField)
        addConstraintsWithFormat("H:|-16-[v0]-16-|", views: DireccionOrigenTextField)
        addConstraintsWithFormat("H:|-16-[v0]-16-|", views: DireccionDestinoTextField)

        addConstraintsWithFormat("V:|-100-[v0(30)]-12-[v1(30)]-12-[v2(30)]-12-[v3(30)]", views:
        NombreUsuarioTextField,NumerodeContactoTextField, DireccionOrigenTextField ,DireccionDestinoTextField)
    }

}

Я пытаюсь напечатать текст при нажатии на кнопку, созданную в моем cellForItemAt, код, который находится в моем классе UICollectionViewController.

@objc func confirmarbutton()
    {
        print("123")
    }

    override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
    {

        var myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "PestañaCero", for: indexPath)
        myCell.backgroundColor = UIColor.black

        let nombre = UIButton(frame: CGRect(x: myCell.frame.width/2-100, y: 400, width: 200, height: 25))
        nombre.setTitle("Pedir Domicilio", for: .normal)
        nombre.backgroundColor = UIColor.orange
        nombre.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
        nombre.addTarget(self, action: #selector(confirmarbutton) , for: .touchUpInside)
        myCell.addSubview(nombre)



    }  

Любая помощь будет очень признательна, спасибо всем


person JORGE LUIS QUINTERO MEDINA    schedule 23.08.2018    source источник


Ответы (3)


Вы можете установить делегата textField внутри ячейки на контроллер при создании ячейки, cell.NumerodeContactoTextField.delegate = self, а затем использовать делегата в контроллере. Однако проблема с этим подходом заключается в том, что вам придется делать это для всех текстовых полей, поэтому лучшим решением будет создание собственного делегата в ячейке, например:

protocol CollectionCellTextFieldDelegate: class {
    func textDidChanged(_ textField: UITextField)
}

А затем добавьте это в свою ячейку:

class PestañaCero: UICollectionViewCell {
    weak var textFieldDelegate: CollectionCellTextFieldDelegate?
}

Теперь при создании вашей ячейки в контроллере вы делаете:

cell.textFieldDelegate = self

Соответствуйте и реализуйте делегата в контроллере:

func textDidChanged(_ textField: UITextField) {
    //Here you will get the textField, and you can extract the textFields text
}

Это просто пример того, как вы поступите в этой ситуации. вы должны иметь возможность изменять в зависимости от ваших требований.

Небольшой пример того, как вы будете делать это с вышеуказанным подходом

My Cell Class

import UIKit

    protocol CollectionCellTextFieldDelegate: class {
            func cellTextFields(_ fields: [UITextField])
    }

    class Cell: UICollectionViewCell {

        @IBOutlet weak var fieldOne: UITextField!
        @IBOutlet weak var fieldTwo: UITextField!
        @IBOutlet weak var button: UIButton!

        weak var textFieldDelegate: CollectionCellTextFieldDelegate?

        @IBAction func buttonClicked(_ sender: UIButton) {
            guard let textFieldDelegate = textFieldDelegate else { return } //we don't have do anything if not conformed to delegate
    //otherwise pass all textFields
            textFieldDelegate.cellTextFields([fieldOne, fieldTwo])
        }
     }

My Controller Class

import UIKit

class ViewController: UIViewController, UICollectionViewDelegate, UICollectionViewDataSource, UICollectionViewDelegateFlowLayout, CollectionCellTextFieldDelegate {


    @IBOutlet weak var collectionView: UICollectionView!


    override func viewDidLoad() {
        super.viewDidLoad()

    //register the cell xib
        collectionView.register(UINib(nibName: "Cell", bundle: nil), forCellWithReuseIdentifier: "Cell")
    }

    //MARK:- CollectionView
    func numberOfSections(in collectionView: UICollectionView) -> Int {
        return 1
    }

    func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 2
    }

    func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
        let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "Cell", for: indexPath) as! Cell
        cell.textFieldDelegate = self
        return cell
    }

    func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize {
        return CGSize(width: collectionView.bounds.width - 20.0, height: 175.0)
    }

    //you could write this delegate anyway you want, its just for a sample
    func cellTextFields(_ fields: [UITextField]) {

        //loop over each fields and get the text value
        fields.forEach {
            debugPrint($0.text ?? "Empty Field")
        }
    }

}

Возможно, вам также придется обрабатывать удаление ячеек из очереди, но пока протестируйте этот код и измените его соответствующим образом.

person kathayatnk    schedule 23.08.2018
comment
Кнопка также принадлежит ячейке. Его не следует создавать и добавлять в контроллере представления. Затем ячейка должна реагировать на кнопку и вызывать делегата ячейки, передавая текущие данные ячейки. Вдобавок ко всему этому модель данных, используемая для заполнения представления коллекции, должна отслеживать весь текст, чтобы она могла заполнять ячейки в cellForItemAt по мере прокрутки пользователем. Здесь много недостающих деталей. - person rmaddy; 23.08.2018
comment
да, ты прав @rmaddy. Однако предоставление всего кода шаг за шагом никому не поможет. Я лишь указал, что это как раз и пример подхода к ситуации. ОП нужно дать время, чтобы понять это самостоятельно. - person kathayatnk; 23.08.2018
comment
Соглашаться. Вот почему я не опубликовал ответ. Там слишком много, чтобы покрыть, чтобы получить все это. - person rmaddy; 23.08.2018
comment
Я очень благодарен за вашу помощь, я попробовал то, что вы мне порекомендовали, единственная проблема заключалась в том, что я не был уверен, где было создание ячейки, это на cellForItemAt?, спасибо - person JORGE LUIS QUINTERO MEDINA; 24.08.2018
comment
@JORGELUISQUINTEROMEDINA: да, в своем cellForItemAt вы установили cell.textFieldDelegate = self - person kathayatnk; 24.08.2018
comment
Спасибо за ваш ответ, Катя, это код, который у меня есть на моем cellForItemAT: var myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "PestañaCero", for: indexPath) myCell.textFieldDelegate = self Xcode возвращает ошибку UICollectionViewCell не имеет члена textFieldDelegate, я не совсем уверен, как это исправить - person JORGE LUIS QUINTERO MEDINA; 24.08.2018
comment
@JORGELUISQUINTEROMEDINA: Это потому, что вы должны сообщить компилятору, что ячейка, на которую вы ссылаетесь, на самом деле PestañaCero. Поэтому ваш код здесь следует изменить на var myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "PestañaCero", for: indexPath) as! PestañaCero - person kathayatnk; 24.08.2018
comment
@JORGELUISQUINTEROMEDINA: я обновил свой ответ примером кода. Пожалуйста, проверьте и попробуйте кусочки. Я использовал xib и раскадровку, но вы можете использовать код напрямую. - person kathayatnk; 24.08.2018
comment
Большое спасибо, Kathayatnk, я очень благодарен за всю вашу помощь. К счастью, код компилируется отлично, единственная проблема, которую я до сих пор не могу получить текст текстового поля с помощью кнопки, причина, по которой я не создал кнопку в коде ячейки, заключалась в том, что когда мне это нравилось, кнопка не была нажата, читая форумы, которые я обнаружил, создание, как я сделал, было решением, во всяком случае, я пытаюсь изменить это и успешно получить его текст. Мне интересно, читали ли вы какую-нибудь книгу о Swift, чтобы вы могли порекомендовать ее мне, я действительно хочу научиться. Еще раз спасибо тебе за все. - person JORGE LUIS QUINTERO MEDINA; 24.08.2018

@objc func confirmarbutton(sender:UIButton)
{

    let indexPath = self.collView.indexPathForItem(at: sender.convert(CGPoint.zero, to: self.collView))
    let cell = self.collView.cellForItem(at: indexPath!) as! PestañaCero

    print(cell.NombreUsuarioTextField.text) // use textfield value like this

    print("123")
}

override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell
{

    var myCell = collectionView.dequeueReusableCell(withReuseIdentifier: "PestañaCero", for: indexPath)
    myCell.backgroundColor = UIColor.black

    let nombre = UIButton(frame: CGRect(x: myCell.frame.width/2-100, y: 400, width: 200, height: 25))
    nombre.setTitle("Pedir Domicilio", for: .normal)
    nombre.backgroundColor = UIColor.orange
    nombre.titleLabel?.font = UIFont.boldSystemFont(ofSize: 16)
    nombre.addTarget(self, action: #selector(confirmarbutton(sender:)) , for: .touchUpInside)
    myCell.addSubview(nombre)

}

вы можете получить доступ к любой строке, используя indexpath, вам просто нужно передать определенный indexpath в методе cellForItem, чтобы получить эту строку, поэтому я просто передаю своего отправителя и нахожу эту строку, чтобы получить это значение текстового поля, вы просто замените мой код своим, и он будет работать :)

person Mahesh Dangar    schedule 23.08.2018

Вот простое решение, которому я лично следую:

Во-первых, мы должны быть в состоянии выяснить, на какую кнопку индекса/строки щелкнул пользователь, чтобы знать, что мы установим «indexPath» на слой кнопки, как показано ниже, в методе *cellForItemAt*:

nombre.layer.setValue(indexPath, forKey: "indexPath")

затем нам нужно изменить подпись метода confirmarbutton, как показано ниже (как написано в ответе @Mahesh Dangar):

@objc func confirmarbutton(sender:UIButton)

Затем нам нужен indexPath в методе confirmarbutton, чтобы мы могли сначала получить ячейку, а затем текстовое поле для доступа к значению этого текстового поля:

@objc func confirmarbutton(sender:UIButton){

    let indexPath = sender.layer.value(forKey: "indexPath") as! IndexPath
    let cell = collectionView.cellForItem(at: indexPath) as! PestañaCero

    let number = cell.NombreUsuarioTextField.text! // make sure you have value in textfield else you will get runTime error

   //below is safer alternative to above line...write one of them

    if let isNumberEntered = cell.NombreUsuarioTextField.text{
          //condition will be true if text field contains value
    }else{
         //This block will be executed if text field does not contain value/it is empty. you can show alert something like please enter the number etc.
    }
}
person Ganesh Pawar    schedule 23.08.2018