Trying to bind an output to my tableviewCell UI Element in RxSwift - swift

I have an output that lives in my VM and based on some change I want my textfield that resides in my custom tableviewCell to change in some way. I am unsure about how to have my UItextfield that lives in the tableviewcell bind to my output.

let index = IndexPath(row: 0, section: 0)
if let cell = tbl.cellForRow(at: index) as? TableViewCell {
print(cell.textF.text)
// Do whatever you want
}

I am not sure when you want to get the data, but if you want to do this when the user touches the cell, just implement the following method of UITableViewDelegate:
override func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? YourTableViewCellClass {
let cellLabelText = cell.yourTextField.text
// Do whatever you want with cellLabel
}
}

Related

how to get the value of a label placed on table view cell

I have a number of cells in my tableview each containing different label values
when i tap on the cell I want that value of label in next view controller. how do I get that?
public func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell") as!
MeetingsListTableViewCell
if self.meeting.count > 0{
let eachMeeting = self.meeting[indexPath.row]
cell.meetingTimeLabel?.text = (eachMeeting["time"] as? String) ?? "No Time"
cell.meetingDateLabel?.text = (eachMeeting["date"] as? String) ?? "No Date"
cell.idLabel?.text = (eachMeeting["id"] as? String) ?? "NO ID"
}
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let vc = UIStoryboard.init(name: "Main4", bundle:Bundle.main).instantiateViewController(withIdentifier: "MeetingDetailVC") as? MeetingDetailVC
self.navigationController?.pushViewController(vc!, animated: true)
}
i want that idLabel value to send in the next viewcontroller
Get the data always from the data source array meeting, never from the cell, for example
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let aMeeting = self.meeting[indexPath.row]
let identifier = aMeeting["id"] as! String
guard let vc = UIStoryboard.init(name: "Main4", bundle:Bundle.main).instantiateViewController(withIdentifier: "MeetingDetailVC") as? MeetingDetailVC else { return }
vc.identifier = identifier
self.navigationController?.pushViewController(vc, animated: true)
}
The code assumes that there is a property identifier in MeetingDetailVC
Notes:
For better readability you should name arrays in plural form (meetings).
The check self.meeting.count > 0 is pointless, cellForRowAt is not being called if the data source array is empty.
It's highly recommended to use a custom struct as data source rather than an array of dictionaries. You will get rid of all those annoying type casts.
Tapped cell can be accessed in didSelectRowAt function of tableVeiw. Extract tableView cell and cast int into your custom cell, after casting you can directly access value of lableId, add an optional property in MeetingDetailVC and pass value to it.

Textfield values deleted when scrolling tableview?

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.

How to display a label on the last cell only?

I have a chat message table view with two cells to display, depending on whom sent the message.
I want the last cell to display the time, and only the last one. When I use tableView(:willDisplay cell:forRowAt indexPath:), the last cell doesn't show anything...
How can I display the time on that last cell?
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if chatBubbles[indexPath.row].user == UserDefaultsService.shared.userID {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.senderCellIdentifier.rawValue, for: indexPath) as! SenderTVC
populateSenderChatBubble(into: cell, at: indexPath)
return cell
}
else {
let cell = tableView.dequeueReusableCell(withIdentifier: CustomCell.conversationCellIdentifier.rawValue, for: indexPath) as! ConversationTVC
populateConversationChatBubble(into: cell, at: indexPath)
return cell
}
}
func tableView(_ tableView: UITableView, willDisplay cell: UITableViewCell, forRowAt indexPath: IndexPath) {
if indexPath.row == chatBubbles.count - 1 {
// What to do in here to display the last cell time?
}
}
Here is the method that display the cell content:
func populateSenderChatBubble(into cell: SenderTVC, at indexPath: IndexPath) {
let bubble = chatBubbles[indexPath.row]
let isoDateString = bubble.date
let trimmedIsoString = isoDateString.replacingOccurrences(of: StaticLabel.dateOccurence.rawValue, with: StaticLabel.emptyString.rawValue, options: .regularExpression)
let dateAndTime = ISO8601DateFormatter().date(from: trimmedIsoString)
date = dateAndTime!.asString(style: .short)
time = dateAndTime!.asString()
if dateAndTime!.isGreaterThanDate(dateToCompare: Date()) {
dateToShow = "\(date!) \(time!)"
}
else {
dateToShow = "\(time!)"
}
cell.senderDateLabel.text = dateToShow
cell.senderConversationLabel.text = bubble.content
}
The cell doesn't know it's last unless you tell it, but the tableView does know who's last. With that in mind, I would add a boolean in your cell like this:
var isLastCell: Bool = false {
didSet {
// do stuff if it's the last cell
if isLastCell {
// configure for isLastCell
} else {
// configure it for !isLastCell
}
}
}
When your custom UITableViewCell class initializes, it'll be with isLastCell = false, so assume that in your configuration. Whenever the boolean is updated to true, the cell will update via the didSet.
Then, in your cellForRow method, test the indexPath to see if it's the last indexPath of the datasource, if so, cell.isLastCell = true and the didSet in the cell will trigger to do whatever adjustments you need to do.
Another thing you'll need to do with this implementation is use cellForRow to update isLastCell for not just the last cell, but the cells that aren't last, since cells are created and destroyed all the time and the last cell at one moment might not be the last cell in another.

Swift tableview cell doesn't save the state with different identifier

I am very confused on the reuse of the cells.
I have a table, each cell is a cell with a switch on it. If I toggle a switch I set the background color of that cell to a different color. However every time I scroll these changes don't persist.
I am subclassing UITalbeViewCell to create my own custom cell. Each cell has a different identifier. However when I scroll through the table, whatever changes I made to the cell still doesn't save. I've read similar questions but none of them worked.. Some suggested subclass which I did, some suggested use different identifier which I also did...
Here is the code of my tableview.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let key = Array(dataSource[indexPath.section].keys)[indexPath.row]
let cell = CellWithSwitch.init(style: .subtitle, reuseIdentifier: key)
cell.awakeFromNib()
let val = Array(dataSource[indexPath.section].values)[indexPath.row]
cell.switchView?.addTarget(self, action: #selector(self.switchChanged(_:)), for: .valueChanged)
if let index = key.firstIndex(of: "."){
cell.textLabel?.text = String(key.suffix(from: key.index(index, offsetBy: 1)))
}else{
cell.textLabel?.text = key;
}
cell.switchView?.setOn(val, animated: true)
return cell
}
You can change array value in switchChange action
lets i take array for switch as below:
var arrSwitch = [false,false,false,false,false,false,false,false,false,false]
Below is my cellForRowAt Method
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "customCell") as! customCell
cell. switchView.setOn(self.arrSwitch[indexPath.row], animated: false)
cell. switchView.tag = indexPath.row
cell. switchView.addTarget(self, action: #selector(self.onSwitchTap(_:)), for: .valueChanged)
return cell
}
Here is my onSwitchTap Action
#IBAction func onSwitchTap(_ sender: UISwitch) {
self.arrSwitch[sender.tag] = !self.arrSwitch[sender.tag]
}
Now on scroll it will persist last changes you have done.

How to change the state of the image in cell made in xib?

There is a TableView and a "Locked" image, how do I get alpha = 0 when I click cell 1 in cell 2? There is the cellForRowAt function:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "tableViewCell", for: indexPath) as! TableViewCell
cell.commonInit("got_\(indexPath.item)", title: titleLessons[indexPath.item], sub: summary[indexPath.item], imageLock: imageZ[indexPath.item])
return cell
}
There is the didSelectRowAt function:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if unlockedRows.contains(indexPath.row) {
let nextIndex = indexPath.row + 1
if nextIndex < pdfArr.count {
let vc = DetailLessonsVC()
let ce = TableViewCell()
vc.pdfTitle = pdfArr[indexPath.row]
vc.numberList = pdfArr[indexPath.row]
vc.linkList = link[indexPath.row]
unlockedRows.append(indexPath.row + 1)
self.navigationController?.pushViewController(vc, animated: true)
self.tableView.deselectRow(at: indexPath, animated: true)
}
print("no")
}
}
TableViewCell is xib's custom class.
You need to access the cell, and change image property, you can access the cell in didselect method with this:
let cell = tableView.cellForRowAtIndexPath(indexPath)
In your cell's custom class (TableViewCell) create an outlet for your image. If I understand correctly you want to edit cell located in the row number N+1 when user taps on the cell located in the row above, right?
If that's the case then all you have to do is get a reference to the next cell in didSelectRowAt. You can do just that this way:
var nextCellsIndexPath = indexPath
nextCellsIndexPath.row += 1
// Use 'if let' in order to make sure the cell at that index path exists
if let nexCell = tableView.cellForRow(at: nextCellsIndexPath) {
nextCell.lockedImage.alpha = 0
}
Since you didn't specify the number of sections in your table view, I assumed it has just one.