Reputation: 49
Im kind of new with Swift, what I am trying to do is to get the text typed by an user in a TextField which is located inside a collection view cell. I have a CollectionViewCell named "PestañaCero" where I created the TextField, this one:
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)
}
}
Im trying to print the text when touching in a button created in my cellForItemAt, code which is located in my UICollectionViewController class
@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)
}
Any help would be really appreciated, thanks everyone
Upvotes: 2
Views: 2083
Reputation: 1015
You can set the delegate of the textField inside the cell to controller when the cell is created, cell.NumerodeContactoTextField.delegate = self
and then use the delegate in the controller. However, the problem with this approach is that you will have to do it for all textFields, so the better solution would be create your own delegate, in cell, like this:
protocol CollectionCellTextFieldDelegate: class {
func textDidChanged(_ textField: UITextField)
}
And then add this to your cell:
class PestañaCero: UICollectionViewCell {
weak var textFieldDelegate: CollectionCellTextFieldDelegate?
}
Now in your cell creation in the controller you do:
cell.textFieldDelegate = self
Conform and implement the delegate in the controller:
func textDidChanged(_ textField: UITextField) {
//Here you will get the textField, and you can extract the textFields text
}
This is just an example of how you would approach this situation. you should be able to modify based on your requirement.
A Small Sample of how You would go about doing this with above approach
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")
}
}
}
You will probably have to handle dequeueing of cells as well but for now test this code and modify accordingly.
Upvotes: 1
Reputation: 191
Here is a simple solution which I personally follow :
First we have should be able to figure it out that at which index/row's button user has clicked so to know that we will set the "indexPath" to button layer like below in * cellForItemAt* method:
nombre.layer.setValue(indexPath, forKey: "indexPath")
then we need change signature of confirmarbutton method like below (as written in answer by @Mahesh Dangar):
@objc func confirmarbutton(sender:UIButton)
Then we need the indexPath in confirmarbutton method so we can get the cell First and then text field to access the value of that text field :
@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.
}
}
Upvotes: 0
Reputation: 804
@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)
}
you can access Any row using the indexpath you just need to pass specific indexpath in cellForItem method to get that row so i just pass my sender and find that row to get that textfield value you just replace my code with yours and it will work :)
Upvotes: 1