How to Get Textfields from Static Cells in UItableviewcontroller? Swift

How to get textFields from static cells in UITableViewController? Swift

Well first I can give you an answer that might satisfy you and fix your loop but I would recommend not doing it that way to alter your textfields. I would recommend doing it in cellForRow even though they may be static cells. Depending on your view setup in the cells it would look like this if the textfield is added directly to the cells and not to another view.

 override func viewWillAppear(_ animated: Bool) {
super.viewWillAppear(animated)
print("Testing")
for cell in tableView.visibleCells{
for sub in cell.contentView.subviews{
if sub is UITextField{
print("Textfield")
}
}
}
}

Read Data From Text Field in TableView Dynamic Cell in Swift

I would change couple of things,

1. Get rid of numberOfTextFields

2. Use var cards = [Cards]() to return the number of cells in tableView

3. Initialize cards with a single Cards instance and set its property to nil. So I would have Cards implementation as

struct Cards {
var frontLabel: String?
var backLabel: String?
}

4. Initialize cards array as

var cards = [Cards()]

5. Return number of rows from arrays count

    func numberOfSections(in tableView: UITableView) -> Int {
return cards.count
}

6. I would migrate text field delegate responsibilities to Cell instead of moving it to ViewController and I would have a delegate in AddFCCell to update the ViewController about text changes

@objc protocol AddFCCellDelegate {
func updateCard(with frontText: String?, backText: String?, for cell: AddFCCell)
}

class AddFCCell: UITableViewCell {
weak var delegate:AddFCCellDelegate?
//.... other codes of yours
}

extension AddFCCell: UITextFieldDelegate {
func textFieldDidEndEditing(_ textField: UITextField) {
self.delegate?.updateCard(with: self.textField1.text, backText: self.textField2.text, for: self)
}
}

7. Finally, implement/confirm to AddFCCellDelegate in viewController and reload TableView bu updating text

extension ViewController: AddFCCellDelegate {
func updateCard(with frontText: String?, backText: String?, for cell: AddFCCell) {
guard let indexPath = self.tableView.indexPath(for: cell) else {
return
}
self.cards[indexPath.row].frontLabel = frontText
self.cards[indexPath.row].backLabel = backText
self.tableView.reloadRows(at: [indexPath], with: .automatic)
}
}

8. Update CellForRowAtIndexPath

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {

let cell = tableView.dequeueReusableCell(withIdentifier: "AddFCCell") as! AddFCCell
cell.selectionStyle = .none
cell.delegate = self
cell.textField1.text = cards[indexPath.row].frontLabel
cell.textField2.text = cards[indexPath.row].backLabel

cell.backgroundColor = .purple

return cell
}

You can obviously implement a efficient protocol and return/update only specific variable in Cards struct based on which textField was modified n all, but the code posted here is only to give you an idea and to get started with

EDIT 1:

Make sure you have set your TextFields delegate right

    override init(style: UITableViewCell.CellStyle, reuseIdentifier: String?) {
super.init(style: style, reuseIdentifier: reuseIdentifier)
contentView.addSubview(textField1)
textField1.delegate = self
contentView.addSubview(textField2)
textField2.delegate = self

configureTextBox1(textField: textField1)
configureTextBox2(textField: textField2)
}

How to get the textfield value of each dynamically created cell in UITableView

There seems to be a problem with your code:

[cell addSubview:scheduelText];
[cell addSubview:dateText];
[cell addSubview:accountText];

Everytime you dequeue the cell will add a new subview to the cell,but never removed.
In my suggestion,you'd better identifier 4 kind of cells with different identifiers,or removesubviews whenever dequeue the cell.

Add cell to UITableView if textfield of previous cell is filled in

You can check, whether textfield is empty or not in viewController itself. You just confirm the delegate for textfield from storyboard and in cellForRowAt and give the tag to that text field

e.g,

cell.yourTextField.delegate = self
cell.yourTextField.tag = indexPath.row

and check the textfield is empty or not in textField delegate method. Create object of cell in method like

func textFieldDidEndEditing(_ textField: UITextField) {
rowBeingEditedInt = textField.tag
let indexPath = IndexPath(row:rowBeingEdited! , section:0 )
let cell = yourTableView.cellForRow(at: indexPath) as! yourTableViewCell
// check cell.yourtextField.text isempty and do your condition
}

Get all values from tableViewCell from TextFields

TextFields in TableView cells can be tricky. First, use the data model and reloadData() instead of insertRows(at:) like this:

@objc func addHourlyRate(sender: UIButton) {
let newRow: String = ""
secondRowText.append(newRow)
self.tableView.reloadData()
}

Now, set the text in the cells, and tag the UITextField with the row number in cellForRowAt() like this:

func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let hourlyRateCell = tableView.dequeueReusableCell(withIdentifier: "hourlyRateCell", for: indexPath) as! SettingsHourlyRateCell
hourlyRateCell.rubHourTF.text = secondRowText[indexPath.row]
hourlyRateCell.rubHourTF.tag = indexPath.row
return hourlyRateCell

}

Next, use UITextFieldDelegate to keep track of any changes in the text fields, something like:

func textFieldDidEndEditing(_ textField: UITextField) {
let tableRow = textField.tag
secondRowText[tableRow] = textField.text
}

Notice how the textField tag that was set in cellForRow() is now used to know which row the textField is at in the table.

How to simultaneously change textField.text in a prototype cell?

At a high level:

  1. You need to have a model to store your data being updated
  2. You need to observe the text being entered using UITextFieldDelegate
  3. As your text is being entered, update all rows except active cell with new calculations

The most interesting work is in textFieldDidChangeSelection and cellForRowAt indexPath

Here is an example of how I would do something like this:

1. Set up some custom types

// Your model to store data in text fields
// Maybe for you, you will store currencies
// and base currency to multiply against
// I am just storing a random number for example
struct FinanceModel
{
var number: Int?
}

// Custom UITextField which will store info
// about cell index path as we need to identify
// it when editing
class MappedTextField: UITextField
{
var indexPath: IndexPath!
}

2. Example of UITableView Cell, you can ignore if you have your own

fileprivate class CustomCell: UITableViewCell
{
// Use custom text field
var textField: MappedTextField!

static let tableViewCellIdentifier = "cell"

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

configureTextField()
}

required init?(coder: NSCoder)
{
fatalError("init(coder:) has not been implemented")
}

// Configure text field and auto layout
private func configureTextField()
{
textField = MappedTextField()
textField.keyboardType = .numberPad
textField.translatesAutoresizingMaskIntoConstraints = false
contentView.addSubview(textField)

textField.layer.borderWidth = 2.0
textField.layer.borderColor = UIColor.blue.cgColor
textField.layer.cornerRadius = 5.0

// auto-layout
textField.leadingAnchor.constraint(equalTo: contentView.leadingAnchor,
constant: 20).isActive = true
textField.trailingAnchor.constraint(equalTo: contentView.trailingAnchor,
constant: -20).isActive = true
textField.topAnchor.constraint(equalTo: contentView.topAnchor,
constant: 20).isActive = true
textField.bottomAnchor.constraint(equalTo: contentView.bottomAnchor,
constant: -20).isActive = true
}
}

3. Set up in view controller - you can skip if already set up, just here for completeness

class InputViewController: UIViewController
{
let tableView = UITableView()

// Initialize your mode
var financeModel = FinanceModel()

// This will store current editing cell which is active
var activeTextFieldIndexPath: IndexPath?

override func viewDidLoad()
{
super.viewDidLoad()

// This is just view set up for me,
// You can ignore this
title = "TableView Input"
navigationController?.navigationBar.tintColor = .white
view.backgroundColor = .white

configureTableView()
}

// Configure TableView and layout
private func configureTableView()
{
tableView.translatesAutoresizingMaskIntoConstraints = false
tableView.register(CustomCell.self,
forCellReuseIdentifier: CustomCell.tableViewCellIdentifier)

tableView.dataSource = self
tableView.delegate = self

// remove additional rows
tableView.tableFooterView = UIView()

view.addSubview(tableView)

// Auto layout
tableView.leadingAnchor
.constraint(equalTo: view.safeAreaLayoutGuide.leadingAnchor).isActive = true
tableView.topAnchor
.constraint(equalTo: view.safeAreaLayoutGuide.topAnchor).isActive = true
tableView.trailingAnchor
.constraint(equalTo: view.safeAreaLayoutGuide.trailingAnchor).isActive = true
tableView.bottomAnchor
.constraint(equalTo: view.safeAreaLayoutGuide.bottomAnchor).isActive = true
}
}

4. TableView DataSource

extension InputViewController: UITableViewDataSource
{
func tableView(_ tableView: UITableView,
numberOfRowsInSection section: Int) -> Int
{
// Random number for me
return 10
}

func tableView(_ tableView: UITableView,
cellForRowAt indexPath: IndexPath) -> UITableViewCell
{
let cell =
tableView.dequeueReusableCell(withIdentifier:
CustomCell.tableViewCellIdentifier)
as! CustomCell

// Set index path of custom text field
cell.textField.indexPath = indexPath

// Set view controller to respond to text field events
cell.textField.delegate = self

// Check if any cell is currently active
// && if we are current cell is NOT the active one
// We want to leave active cell untouched
if let activeTextFieldIndexPath = activeTextFieldIndexPath,
activeTextFieldIndexPath.row != indexPath.row
{
updateCell(cell, atIndexPath: indexPath)
}
else
{
// no active cell, just set the text
updateCell(cell, atIndexPath: indexPath)
}

return cell
}

private func updateCell(_ cell: CustomCell,
atIndexPath indexPath: IndexPath)
{
// Retrieve number currently stored in model
if let number = financeModel.number
{
// Set text of number in model * row number
// Do any calculation you like, this is just an
// example
cell.textField.text =
"\(number) x \(indexPath.row) = \(number * indexPath.row)"
}
else
{
// If no valid number, set blank
cell.textField.text = ""
}
}
}

5. TextField Delegate

extension InputViewController: UITextFieldDelegate
{
// Respond to new text in the text field
func textFieldDidChangeSelection(_ textField: UITextField)
{
// 1. Convert generic UITextField to MappedTextField
// 2. && Retrieve index path from custom MappedTextField
// 3. && Retrieve text from the text field
// 4. && Check if text is valid number
if let textField = textField as? MappedTextField,
let indexPath = textField.indexPath,
let text = textField.text,
let number = Int(text)
{
// Assign local variable with index path we are editing
activeTextFieldIndexPath = indexPath

// Update number in the financial model
financeModel.number = number

// We only want to update data in visible rows so
// get all the index paths of visible rows
let visibleRows = self.tableView.indexPathsForVisibleRows ?? []

// We want to update all rows EXCEPT active row
// so do a filter for this
let allRowsWithoutActive = (visibleRows).filter
{
// Remove the active index path from the
// visible index paths
$0.section != indexPath.section ||
$0.row != indexPath.row
}

// Reload the visible rows EXCEPT active
self.tableView.reloadRows(at: allRowsWithoutActive,
with: .automatic)
}
}

// This is just to make current text field
// empty when editing, you can ignore
func textFieldDidBeginEditing(_ textField: UITextField)
{
textField.text = ""
}

// Reset when text field is no longer being edited
func textFieldDidEndEditing(_ textField: UITextField)
{
activeTextFieldIndexPath = nil
tableView.reloadData()
}
}

6. TableView Delegate

extension InputViewController: UITableViewDelegate
{
func scrollViewDidScroll(_ scrollView: UIScrollView)
{
// End editing when scrolling table view
// This is for me, you can have another way
view.endEditing(true)
}

func tableView(_ tableView: UITableView,
heightForRowAt indexPath: IndexPath) -> CGFloat
{
// Return a random height
return 80
}
}

End result is something like this:

Update all multiple text fields in UITableView Cell when typing UITableViewCell UITextFieldDelegate

Hope this gives you enough to set you on your way.

I could not get text field value in dynamic table view swift

Cells are reused, when you scroll and if visibility of cell goes out of screen area, then they are reused.

You must have to take temporary array to save values and make them in sync with cell indexes. Set those values in cellForRowAt Index path method from array you created.



Related Topics



Leave a reply



Submit