Textfield values deleted when scrolling tableview? - swift

I have tableview cell with a textfield but when I add new row and scroll tableview up or down disappeared textfield values deleted. I make lots of research about that previous question about that in 2015 and its not answered correctly. How can I fix this issue? How can I use textfield delegate method if it is working for this? Here my code:
var i = 0
while i <= taskArrForRead.count {
let indexPath = IndexPath(row: i, section: 0)
let cell = self.tableView.cellForRow(at: indexPath) as? taslakDuzenlemeCell
if let item = cell?.taslakTextField.text! {
arrayOfNames.append(item)
}
i = i + 1
}
In this code I get all textfield values from tableview but if tableview scroll disappeared values turn with default values. How can I fix it? Thanks.
Here my tableview code:
extension taslakOlusturmaController: UITableViewDelegate, UITableViewDataSource, UITextFieldDelegate {
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return taskArrForRead.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "taslakCell", for: indexPath) as! taslakDuzenlemeCell
cell.taslakTextField.text = taskArrForRead[indexPath.item]
cell.taslakTextField.delegate = self
return cell
}
func textFieldDidEndEditing(_ textField: UITextField) {
print(textField.text!)
self.arrayOfNames.append(textField.text!)
}
func tableView(_ tableView: UITableView, didEndDisplaying cell: UITableViewCell, forRowAt indexPath: IndexPath) {
let cell = tableView.dequeueReusableCell(withIdentifier: "taslakCell", for: indexPath) as! taslakDuzenlemeCell
cell.taslakTextField.text = taskArrForRead[indexPath.item]
print(arrayOfNames[indexPath.item])
}
}
With textfield delegate method I can get deleted textfield values but I can't bring it again to textfield. User can't see value after scroll again also I can get deleted values with didEndDisplaying cell method too.

You could use the method PrepareForReuse to set the text back when the cell recreated again.

Related

Bug when reloading a certain row of a UTableView

I have a strange bug when I reload a certain row of UITableView via the .reloadRows() method.
Snippets of code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return news_section.count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell_section", for: indexPath) as! NewsSectionCell
cell.delegate_press_btn = self
var news_index = self.news_section[indexPath.row]
cell.number = news_index
cell.indexPath = indexPath
return cell
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
var highCell = self.needs_high_cell(news_sect: self.news_section[indexPath.row])
return highCell ? 150 : 90.0
}
The cell has a button when pressed via delegate does following:
self.news_section[index] = 0
self.news_table_view.reloadRows(at: [indexPath], with: .none)
Sometimes it works sometimes it produces this:
NSMutableRLEArray objectAtIndex:effectiveRange:: Out of bounds
I tried to change the cell number by changing the array from where the cell gets his number. And then reload only that row.
Use this code may be helpfull for you:---
let indexPath = IndexPath(item: rowNumber, section: 0)
tableView.reloadRows(at: [indexPath], with: .top)
For anybody looking for a similar problem :
// Reconfigures any existing cells for the rows. Reconfiguring is more efficient than reloading a row, as it does not replace the
// existing cell with a new cell. Prefer reconfiguring over reloading unless you actually need an entirely new cell for the row.
#available(iOS 15.0, *)
open func reconfigureRows(at indexPaths: [IndexPath])

UITextField can't become first responder in UITableView

Context
Basic list. When user press '+', code creates a new item with default text that user can change.
Problem
I want to focus the new item as soon as user press '+' so that user can type desired name. I try to achieve this with this code:
func focus() {
title.becomeFirstResponder()
title.selectAll(nil)
}
But becomeFirstResponder() always returns false.
How can I give focus to UITextField in my UITableviewCell after creation ?
Here is full code of UITableViewController for reference:
import UIKit
class ViewController: UITableViewController{
var model: [String] = ["Existing item"]
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return model.count
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemUI", for: indexPath) as! ItemUI
cell.update(with: model[indexPath.item])
return cell
}
#IBAction func createItem(_ sender: UIBarButtonItem) {
let indexPath = IndexPath(item: model.count, section: 0)
model.append("new item")
tableView.reloadData()
tableView.scrollToRow(at: indexPath, at: .top, animated: true)
DispatchQueue.main.asyncAfter(deadline: .now() + 0.25) {
let cell = self.tableView(self.tableView, cellForRowAt: indexPath) as! ItemUI
cell.focus()
}
}
}
class ItemUI: UITableViewCell{
#IBOutlet var title: UITextField!
func update(with: String) {
title.text = with
}
func focus() {
title.becomeFirstResponder()
title.selectAll(nil)
}
}
Ok I found the problem!
I was using method self.tableView(self.tableView, cellForRowAt: indexPath) instead of self.tableView.cellForRow(at: indexPath).
Here is what the documentation has to say:
"Never call this method yourself. If you want to retrieve cells from your table, call the table view's cellForRow(at:) method instead."
You can add a boolean in your view controller to keep track of adding item i.e isAddingItem with default value false and when you add new item simply update isAddingItem to true. In tableview cellForRowAt method check for last cell of tableview and if isAddingItem is true then selected all text of textfield and make it first responder.
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "ItemUI", for: indexPath) as! ItemUI
cell.update(with: model[indexPath.item])
if isAddingItem && indexPath.item == model.count {
// make your textfield first here and select text here
}
return cell
}
Also check if you have set textfield delegate.

Weird display behaviour when selecting tableview row

I have this table view, that populates through Core Data. Everything looks fine, even when scrolling, until I press and hold any row - then that row distorts like in the second image below.
(source: staticflickr.com)
(source: staticflickr.com)
Here's the code to display the tableview
override func viewDidLoad() {
super.viewDidLoad()
animateBackground(colors)
tableView.delegate = self
tableView.dataSource = self
tableView.fetchData(fetchedResultsController as! NSFetchedResultsController<NSFetchRequestResult>)
self.tableView.tableFooterView = UIView(frame: .zero)
}
func numberOfSections(in tableView: UITableView) -> Int {
guard fetchedResultsController.sections?.count != nil else { return 0 }
return fetchedResultsController.sections!.count
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
guard fetchedResultsController.sections != nil else { return 0 }
let data = fetchedResultsController.sections![section]
return data.numberOfObjects
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "SkillCell", for: indexPath) as! SkillCell
configureCell(cell: cell, indexPath: indexPath as NSIndexPath)
return cell
}
func configureCell(cell: SkillCell, indexPath: NSIndexPath) {
let skill = fetchedResultsController.object(at: indexPath as IndexPath)
cell.skill = skill
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) { }
}
From the code above, everything looks normal, yet this distortion occurs. Please help me to see why and how to stop it happening.
As the comment suggests, it's just a visual effect called selectionStyle of your UITableViewCell. Inside your cellForRowAt indexPath method, you can disable it like:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "myCell") as! MyCell
cell.selectionStyle = .none // this removes the effect.
return cell
}
yes you should set tableView selection style to none.
1.Select the tableview in storyboard in the right panel set selection style to none.
or
2.in your tableview cellforrow method set
tableView.selectionstyle = none

How to maintain highlighted multiple UITableView rows after reloading UITableView?

I have a UITableView.
I can select multiple cells make them highlighted.
But, whenever I reload App, the selected and highlighted state disappears.
I think I need to put some codes in 'viewDidAppear' and 'didSelectRowAt'. But I don't have any idea of specific codes.
What do I have to put in this syntax?
class ViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
tableView.reloadData()
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
}
}
I recommend u add to dataSource item field selected, and in method cellForRowAtindexPath configure by your dataSource items.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
guard let cellClass = (self.cellClass(for: indexPath) ?? self.cellClasses.first) else { return UITableViewCell() }
let cell = tableView.dequeueReusableCell(withIdentifier: cellClass.identifier, for: indexPath)
if let configurable = cell as? ConfigurableComponent, let object = self.object(at: indexPath) {
let item = self.dataSource[indexPath.row]
configurable.selected = item.selected
}
return cell
}
When call didSelectRowAt, just take item and change selected field, sample:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let item = self.dataSource[indexPath.row]
item.selected = !item.selected
tableView.reloadData()
}

tableview persisting cell image after reloading

I have a tableview with cells that when selected displays an image within the selected cell, this image then disappears when the cell is selected again, and so on. When i press a submit button the selected cells are remembered and the tableview reloads with new data. But when doing this all the new data loads but the selected cell image persists. I have tried calling tableView.reloadData() on the main queue but it still persists. The image also persists when i press the submit button several times.
Heres my code:
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return currentQuestion.answers.count
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return tableView.frame.height/CGFloat(currentQuestion.answers.count)
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
setSelectedArray()
let cell: AnswersTableViewCell = tableView.dequeueReusableCell(withIdentifier: "answersTableViewCell") as! AnswersTableViewCell
let text = currentQuestion.answers[indexPath.row]
let isAnAnswer = currentQuestion.answerKeys[indexPath.row]
cell.answerTextLabel.text = text
cell.answerView.backgroundColor = UIColor.white.withAlphaComponent(0.5)
cell.contentView.sendSubview(toBack: cell.answerView)
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell: AnswersTableViewCell = tableView.cellForRow(at: indexPath) as? AnswersTableViewCell {
if cell.answerImageView.image == nil {
cell.answerImageView.image = UIImage(named: "paw.png")
selected[indexPath.row] = true
} else {
cell.answerImageView.image = nil
selected[indexPath.row] = false
}
}
}
#IBAction func submitButtonWasPressed() {
if questionNumber < questions.count - 1 {
questionNumber += 1
setCurrentQuestion()
self.answersTableView.reloadData()
self.view.setNeedsDisplay()
}
}
Any help would be great. Thanks
You need to set the image back to its correct value in cellForRow. Cells in your table are reused between calls to reloadData, and since you're not touching the imageView, it's keeping its previous value. Looks to me like you want:
cell.answerImageView.image = selected[indexPath.row] ? UIImage(named: "paw.png") : nil
inside of tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath).