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

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.

Related

Crash: Attempted to dequeue multiple cells for the same index path, which is not allowed

I have tableview datasource func to build a cell from a factory method function.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
return OWTableViewOrganizer.instance.configureCell(at: indexPath)!
}
The factory method is here:
func configureCell(at indexPath: IndexPath) -> UITableViewCell? {
var cell = UITableViewCell()
switch indexPath.section {
case thisWorkoutSections.barbel.sectionNumber():
cell = barebellCell(indexPath: indexPath)
break
case thisWorkoutSections.lastWorkout.sectionNumber():
cell = lastWorkoutCell(indexPath: indexPath)
break
case thisWorkoutSections.personalRecord.sectionNumber():
cell = personalRecordCell(indexPath: indexPath)
break
case thisWorkoutSections.notes.sectionNumber():
break
default:
break
}
return cell
}
I have this code to build the cell:
func lastWorkoutCell(indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
if OWTableViewOrganizer.instance.lastWorkoutExerciseSets.count > 0 {
if indexPath.row < OWTableViewOrganizer.instance.lastWorkoutExerciseSets.count {
let logExerciseSet = OWTableViewOrganizer.instance.lastWorkoutExerciseSets[indexPath.row]
let setNumber = indexPath.row + 1
if let weight = logExerciseSet.weight?.doubleValue, let reps = logExerciseSet.reps?.intValue {
cell.setupCellWithData(setNumber: setNumber, weight: weight, reps: reps)
}
} else {
cell.setupCellWithData(setNumber: -1, weight: 0, reps: 0)
}
} else {
cell.setupCellWithData(setNumber: -1, weight: 0, reps: 0)
}
return cell
}
But time to time this line crashes for me:
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
With error:
Attempted to dequeue multiple cells for the same index path, which is not allowed. If you really need to dequeue more cells than the table view is requesting, use the -dequeueReusableCellWithIdentifier: method (without an index path)
I know code style and design is not ideal here, please skip this if you have comments.
I don't know where to look, I tried simply remove indexPath, but it looks does not help or bring even more issues:
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier()) as! WorkoutSetTableViewCell
I have one controller which presents another one at the top of it (like in Apple music) and I can swipe down to show bottom controller and swipe up to bring back top controller. I noticed in log that I have some presentation alert, not sure if this something I need to deal with to resolve the issue above but JFY info.
It seems like there are two table view trigger
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
and you only dequeue cell from 1 table view at
let cell = tableView.dequeueReusableCell(withIdentifier: WorkoutSetTableViewCell.cellIdentifier(), for: indexPath) as! WorkoutSetTableViewCell
You should try to pass tableView from
tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath)
to
lastWorkoutCell(indexPath: IndexPath)
(which will become lastWorkoutCell(indexPath: IndexPath, tableView: UITableView)) and dequeue cell from tableView

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.

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

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
}
}

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.

Why is the width of cell in UItableview not same as width of screen in simulator?

The table cell is running shorter than it is supposed to be. (I use different background colour which shows difference width) The setting of cell is custom (only row height is change to 140). The playerCell class has nothing but some IBoutlets. Thanks.
(image: storyboard
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
var count: Int
if playerBank.count == 0
{
count = 1
}
else{
count = playerBank.count
}
return count
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! playerCell
if playerBank.isEmpty{
let p = Player()
playerBank = setInvalidPlayer(pBank: p, userInput: userInputPlayerName)
}
let playerInBank: Player = playerBank[indexPath.row]
passImageUrl = cell.setPlayerCell(p: playerInBank)
urlBank.append(passImageUrl)
let bgColorView = UIView()
bgColorView.backgroundColor = UIColor.red
cell.selectedBackgroundView = bgColorView
return cell
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
myIndex = indexPath.row
DispatchQueue.main.async {
self.performSegue(withIdentifier: "ShowPlayerInfo", sender: self)
}
}
My first guess is that, while you have a custom cell with custom outlets, that there are no layout constraints in place. So the items that you put into the storyboard are retaining their intrinsic values and not adapting to the device screen size.
If you add constraints to those outlets, especially enough to where the width of the cell can be determined based on the rest of the elements, then your cell should display full width.