Expand tableviewcell when selected and compact when deselected Swift 3 - ios

So I have a mainTableView of type ExpyTableView (https://github.com/okhanokbay/ExpyTableView). All fine , i managed to implement it and make it work but as it can be seen in the gif below i need to make +1 extra action for DidSelect and DidDeselect.
The thing is i want when selected to highlight with the green color and immediately expand the other rows , and when clicked on it right after to deselect and make the row back to normal . So normally this need to happen only after 2 taps on the screen... instead i make 4 as seen in the gif.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
//MARK : Print
print("Selected Section \(indexPath.section), Row : \(indexPath.row)")
///////////////
if let cell = tableView.cellForRow(at: indexPath) {
if (indexPath.section == 1) || (indexPath.section == 2) || (indexPath.section == 3) {
cell.layer.borderWidth = 2.0
cell.layer.borderColor = Theme.defaultColor().cgColor
cell.layer.shadowOffset = CGSize.init(width: 0.5, height: 0.5)
}
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
tableView.deselectRow(at: indexPath, animated: false)
cell.layer.borderWidth = 0.1
cell.layer.borderColor = UIColor.lightGray.cgColor
}
}
Where did I go wrong?

Basically you listen to table changes for didDeselectRow which means following:
The code is executed once the table view cell is deselected. So you can forget about that code unless you really need it. However what you did is that you selects the row twice. Once for expansion, secondly to collapse.
What you need to do is to remember the index of selected cell and then deselect it while id didSelectRowAt
So declare a property fileprivate var currentlySelectedCellIndexPath: IndexPath? and then in didSelectRowAt use following.
var currentlySelectedCellIndexPath: IndexPath?
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let currentlySelectedCellIndexPath = currentlySelectedCellIndexPath {
// unselect the selected one
makeCellUnSelected(in: tableView, on: currentlySelectedCellIndexPath)
guard currentlySelectedCellIndexPath != indexPath else {
tableView.deselectRow(at: currentlySelectedCellIndexPath , animated: true)
self.currentlySelectedCellIndexPath = nil
return
}
}
// Highlight the proper cell
makeCellSelected(in: tableView, on: indexPath)
currentlySelectedCellIndexPath = indexPath
}
func makeCellSelected(in tableView: UITableView, on indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
if (indexPath.section == 1) || (indexPath.section == 2) || (indexPath.section == 3) {
cell.layer.borderWidth = 2.0
cell.layer.borderColor = Theme.defaultColor().cgColor
cell.layer.shadowOffset = CGSize.init(width: 0.5, height: 0.5)
}
}
}
func makeCellUnSelected(in tableView: UITableView, on indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.layer.borderWidth = 0.1
cell.layer.borderColor = UIColor.lightGray.cgColor
}
}
To explain what it does:
The functions makeCellselected & makeCellUnselected just apply the style changes to highlight / unhighlight the cell as you did previously.
in the function func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) just check for currently visible and selected cell. If it is the same cell, then collapse it in guard and return, since you require only to expand / collapse. If it is not the same cell, then just discard the selection by calling makeCellUnselected and select the new one. This should solve your problem so far. If you have any other questions, just let me know.

What I would do is to have a property in your model isExpanded that will store if the cell needs to be expanded. That way you can use it in heightForRowAtIndexPath where you will get the item and read the isExpanded property.

Related

How to have checkmarks icons (accessory view) on tableview already checked after cells rendered?

I have model data, which has a boolean value that says if checkmark should be shown (accessoryType is .checkmark)...
So for example, I want to have two of five rows checkmarked at start (based on my model as I said)... The thing is, I am able to show checkmarks, but after I tap on them, toggling doesn't work right:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
model[indexPath.row].isCellSelected = true
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
model[indexPath.row].isCellSelected = false
}
}
And here is a cellForRowAt:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = model[indexPath.row]
let identifier = data.subtitle != nil ? kSubtitleID : kNormalID
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = data.title
cell.detailTextLabel?.text = data.subtitle
return cell
}
I am able to show check mark like this:
cell.accessoryType = data.isCellSelected ? .checkmark : .none
But when I tap on it, it cause it is selected (allowsMultipleSelection is set to true), it doesn't get toggled, but rather stays for the first time.
Here is the model I use. It is really simple:
struct CellModel{
var title:String?
var subtitle:String?
var isCellSelected:Bool = false
}
You should perform toggling in tableView:didSelectRowAt: only, and reload the necessary cell afterwards. You should omit tableView:didDeselectRowAt:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
// Toggle the value - true becomes false, false becomes true
model[indexPath.row].isCellSelected = !model[indexPath.row].isCellSelected
tableView.reloadRowsAtIndexPaths([indexPath], withRowAnimation: .none)
}
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = model[indexPath.row]
let identifier = data.subtitle != nil ? kSubtitleID : kNormalID
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = data.title
cell.detailTextLabel?.text = data.subtitle
// Set the checkmark or none depending on your model value
cell.inputAccessoryType = data.isCellSelected ? .checkmark : .none
return cell
}
Edit:
Use this for single selection only + ability to deselect selected item:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
// Loop through all model items
for (index, item) in model.enumerated() {
if (index == indexPath.row) {
// Toggle tapped item
item.isCellSelected = !item.isCellSelected
} else {
// Deselect all other items
item.isCellSelected = false
}
}
tableView.reloadData();
}
You dont have to use select and deselect until you have a model that saves the boolean value
In tableview didselect method
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if model[index.row].isCellSelected == true {
model[indexpath.row].isCellSelected = false
}
else {
model[indexpath.row].isCellSelected = true
}
tableview.reloadData
}
And in cell for row check
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
if model[index.row].isCellSelected{
cell.accessoryType = .checkmark
}
else {
cell.accessoryType = .none
}
}
What I did to make all work is:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let data = model[indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .checkmark
model[indexPath.row].isCellSelected = true
self.selectedData?(model.filter{$0.isCellSelected})
}
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let data = model[indexPath.row]
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
model[indexPath.row].isCellSelected = false
self.selectedData?(model.filter{$0.isCellSelected})
}
}
and
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = model[indexPath.row]
let identifier = data.subtitle != nil ? kSubtitleID : kBasicID
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = data.title
cell.detailTextLabel?.text = data.subtitle
cell.accessoryType = data.isCellSelected ? .checkmark : .none
return cell
}
but I had to initially setup which cells are selected actually:
func setSelectedCells(){
let selectedIndexes = self.model.enumerated().compactMap { (index, element) -> IndexPath? in
if element.isCellSelected{
return IndexPath(row: index, section: 0)
}
return nil
}
selectedIndexes.forEach{
selectRow(at: $0, animated: false, scrollPosition: .none)
}
}
and then called this in viewDidAppear, cause I had to be sure that table has drawn its content (cause this will fail if we try something (cell) that doesn't exist yet). Not a best way, but it solved the issue for single and multiple selections with initial states.
Then, cellForRowAt method becomes as simple as:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = model[indexPath.row]
let identifier = data.subtitle != nil ? kSubtitleID : kNormalID
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = data.title
cell.detailTextLabel?.text = data.subtitle
cell.accessoryType = data.isCellSelected ? .checkmark : .none
return cell
}
Then, didSelectRowAt method becomes as simple as:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath) {
let isCellSelected = !(model[indexPath.row].isCellSelected)
cell.accessoryType = isCellSelected ? .checkmark : .none
model[indexPath.row].isCellSelected = isCellSelected
}
}
Note we had to toggle the flag and update the cell and the model based on the new value.
Even better, you can replace the .accessory type updating line with:
tableView.reloadRows(at: [indexPath], with: .none)
So the method would look like this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
tableView.deselectRow(at: indexPath, animated: true)
if let cell = tableView.cellForRow(at: indexPath) {
let isCellSelected = !(model[indexPath.row].isCellSelected)
model[indexPath.row].isCellSelected = isCellSelected
tableView.reloadRows(at: [indexPath], with: .none)
}
}
Note that we update the model, then we reload the cell that will cause cellForRowAt to be called, and that method takes care on proper configurations based on model.
More generally, I'd recommend to use some StateController object to keep the state for each cell / row and take care of the toggling.
I've wrote a whole article a while ago that does exactly what you need to do, and showcases a lot of best practices too:
https://idevtv.com/how-to-display-a-list-of-items-in-ios-using-table-views/
#Whirlwind, Hi its not so complicate if you need to show selections only inside the tableView, here i am delivering my ans after your model update.
This can be done by maintaining isCellSelected property in didSelectRowAt only.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
model[indexPath.row].isCellSelected = model[indexPath.row].isCellSelected ? false : true
tableView.reloadData()
}
Here is cellForRowAt you can also alter some more lines here.
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let data = model[indexPath.row]
let identifier = "kNormalID"
let cell = tableView.dequeueReusableCell(withIdentifier: identifier, for: indexPath)
cell.textLabel?.text = data.title
cell.detailTextLabel?.text = data.subtitle
cell.accessoryType = data.isCellSelected ? .checkmark : .none
return cell
}
Hope i delivered you my best. Let me know if i missed anything.
Why don't you try following!
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) {
cell.accessoryType = .none
model[indexPath.row].isCellSelected = false
tableView.reloadRows(at: [indexPath], with: <UITableViewRowAnimation>)
}
}

Programmatically highlighting UITableViewCell in Swift

How do I programmatically highlight a table view cell?
I am using:
tableView.selectRow(at: indexPath, animated: true, scrollPosition: .none)
tableView.delegate?.tableView!(self.ordersTableView, didSelectRowAt: indexPath)
The problem I am having is that the cell IS being selected (all the actions specified in my didSelectRowAt are being performed) but the cell does now highlight. It doesn't appear selected.
What I am trying to achieve is like the Settings app on the iPad. You launch the app and see the "general" cell already selected and highlighted.
The cells highlight properly when touched by the user.
I have even tried overwriting the isSelected variable in my subclass of UITableViewCell.
Ok turns out it was a problem with background tasks. The cells were loaded again after I selected them and that's why the selection wasn't visible.
Note: Your question title says, you have a query with cell highlight and your question description says, you have a problem with cell selection. Both are different events.
Here is an answer, how you can manage (set color) on tableview row (cell) selection:
// make sure your tableview row selection is enabled
yourTableViewInstance.allowsSelection = true
// handle highlighted background in data source method also
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "textview") as! YourTableViewCell
cell.contentView.backgroundColor = cell.isSelected ? UIColor.red : UIColor.gray
return cell
}
// didSelectRowAtIndexPath - change background color
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? YourTableViewCell {
cell.contentView.backgroundColor = UIColor.red
}
}
// didDeselectRowAtIndexPath - change background color
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
if let cell = tableView.cellForRow(at: indexPath) as? YourTableViewCell {
cell.contentView.backgroundColor = UIColor.gray
}
}
Try this:-
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath)
{
var selectedCell:UITableViewCell = tableView.cellForRowAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor.redColor()
}
Here is another option to handle cell background selection
class YourTableViewCell: UITableViewCell {
// override cell selection
override func setSelected(_ selected: Bool, animated: Bool) {
super.setSelected(selected, animated: animated)
if self.selectedBackgroundView == nil {
let bgView = UIView()
self.selectedBackgroundView = bgView
}
self.selectedBackgroundView?.backgroundColor = selected ? UIColor.red : UIColor.gray
}
}
// enable row/cell selection
yourTableViewInstance.allowsSelection = true
// handle highlighted background in data source method also
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "textview") as! YourTableViewCell
if self.selectedBackgroundView == nil {
let bgView = UIView()
self.selectedBackgroundView = bgView
}
self.selectedBackgroundView?.backgroundColor = selected ? UIColor.red : UIColor.gray
return cell
}

UITableView How to call a function after reordering cells

In my project I wanted to implement moving rows as well as deleting them but not with stock "Delete" button but by tapping the image that is within my custom UITableViewCell called QueueCell. I delete rows in function deleteByTap2 which uses the sender.tag (which is the cell.indexPath.row) to recognise which cell should be removed. Both moving and deleting work great on their own but when you move, for example, 6th row to 2nd it still carries the tag = 6 and because of that when I tap on image to delete the row, incorrect row gets deleted. I created a function reTag which is supposed to update tags of all cells within the sections and it works great after being called in deleteByTap2 function but when called at the end of
func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath)
it seems to not know the state of tableView after moving row. I searched the forum and I found that there was undocumented UITableViewDelegate function
- (void)tableView:(UITableView *)tableView didEndReorderingRowAtIndexPath:(NSIndexPath *)indexPath;
but I tried calling it and it seems it was removed (or maybe name changed)
When should I call the reTag function so it would work properly? So it would know the order of tableView after reordering it?
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "cell", for: indexPath) as! QueueCell
let item = sungs[indexPath.section].songsIn[indexPath.row]
cell.setup(item: item)
if indexPath.section == 2{
let tap = UITapGestureRecognizer(target: self, action: #selector(deleteByTap2(_:)))
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
cell.artwork.addGestureRecognizer(tap)
cell.artwork.isUserInteractionEnabled = true
cell.artwork.tag = indexPath.row
}
return cell
}
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
var toMove: MPMediaItem
tableView.beginUpdates()
if sourceIndexPath.section == 2{
if player.isShuffle{
toMove = player.shufQueue[player.shufIndex + sourceIndexPath.row + 1]
player.shufQueue.remove(at: player.shufIndex + sourceIndexPath.row + 1)
if destinationIndexPath.section == 2{
player.shufQueue.insert(toMove, at: player.shufIndex + destinationIndexPath.row + 1)
}
}else{
toMove = player.defQueue[player.defIndex + sourceIndexPath.row + 1]
player.defQueue.remove(at: player.defIndex + sourceIndexPath.row + 1)
if destinationIndexPath.section == 2{
player.defQueue.insert(toMove, at: player.defIndex + destinationIndexPath.row + 1)
}
}
}
tableView.endUpdates()
reTag(section: destinationIndexPath.section)
}
//the beginUpdates()-endUpdates() doesn't do much good here, actually it messes some of my cells
func reTag(section: Int){
var indexPath: IndexPath
for row in 0 ..< tableView.numberOfRows(inSection: section){
indexPath = IndexPath(row: row, section: section)
if let cell = tableView.cellForRow(at: indexPath) as? QueueCell{
cell.artwork.tag = row
}
}
}
func deleteByTap2(_ sender: UITapGestureRecognizer){
let tag = (sender.view?.tag)!
if player.isUsrQueue{
player.usrQueue.remove(at: player.usrIndex + tag + 1)
player.usrQueueCount! -= 1
sungs[2].songsIn.remove(at: tag)
}else{
player.defQueue.remove(at: player.defIndex + tag + 1)
sungs[2].songsIn.remove(at: tag)
player.defQueueCount! -= 1
}
let indexPath = IndexPath(row: tag, section: 2)
tableView.deleteRows(at: [indexPath], with: .fade)
reTag(section: 2)
}
This is a good example of why it's a bad idea to use .tag on objects to try and track them in this way.
I'd suggest that you move the tap gesture inside your cell class, and add a "call back" closure. This sample is, of course, missing your data class and cell.setup() code, but you should be able to see what needs to be changed:
// cell class
class QueueCell: UITableViewCell {
#IBOutlet weak var artwork: UIImageView!
var tapCallback: ((QueueCell) -> ())?
func addTap() {
if artwork.gestureRecognizers == nil {
// cells are reused, so only add this once
let tap = UITapGestureRecognizer(target: self, action: #selector(artworkTap(_:)))
tap.numberOfTapsRequired = 1
tap.numberOfTouchesRequired = 1
artwork.addGestureRecognizer(tap)
artwork.isUserInteractionEnabled = true
}
}
func artworkTap(_ sender: UITapGestureRecognizer) -> Void {
tapCallback?(self)
}
}
// table view class
override func tableView(_ tableView: UITableView, moveRowAt sourceIndexPath: IndexPath, to destinationIndexPath: IndexPath) {
// all you have to do is manage your data,
// no need to reload() or "re-tag" anything
}
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "QueueCell", for: indexPath) as! QueueCell
// your cell configuration
//let item = sungs[indexPath.section].songsIn[indexPath.row]
//cell.setup(item: item)
if indexPath.section == 2 {
// tell the cell to add the gesture recognizer
cell.addTap()
// set the "call back" closure
cell.tapCallback = {
theCell in
if let iPath = tableView.indexPath(for: theCell) {
self.deleteByTap2(tableView, indexPath: iPath)
}
}
}
return cell
}
func deleteByTap2(_ tableView: UITableView, indexPath: IndexPath) -> Void {
print("Tapped on artwork at:", indexPath)
// you now have a reference to the table view and the indexPath for the cell that
// contained the artwork image view that was tapped
}
Now your deleteByTap2() function will match the familiar didSelectRowAt function, and you can handle your deleting there.

How do I have a single select and a multiselect in my tableview?

in my cellForRowAt Im inflating my xib and setting its content:
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: TableViewCell = tableView.dequeueReusableCell(withIdentifier: "MyCell", for: indexPath) as! TableViewCell
cell.label.text = data[indexPath.row]
let tap = UIGestureRecognizer(target: self, action: #selector(tableCellTap(_:cell:)))
cell.addGestureRecognizer(tap)
cell.selectionStyle = .none
cell.checkBox.isUserInteractionEnabled = false
cell.checkBox.boxType = .circle
cell.checkBox.markType = .radio
cell.checkBox.cornerRadius = 0
cell.checkBox.stateChangeAnimation = .expand(.fill)
if (indexPath.row == selectedIndex){
cell.checkBox.checkState = .checked
}else{
cell.checkBox.checkState = .unchecked
}
return cell
}
Then Im setting my deselect and select values
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
cell.checkBox.checkState = .checked
}
func tableView(_ tableView: UITableView, didDeselectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
cell.checkBox.checkState = .unchecked
}
I need a sense of direction in how i can make it select and deselect the same row and update my xib file checkbox?
m13checkbox is being used
when i click on the cell for the first time it selects it but when i click on the same cell again it does not call it and does nothing until a loop a completed in the checkboxes
you don't need didDeselectRowAt, you can achieve the same functionality by checking if the radio button is checked in your didSelectRowAt.
If the radio button is checked, simply uncheck it and vice versa.
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
let cell = tableView.cellForRow(at: indexPath) as! TableViewCell
if(cell.checkBox.isChecked){
cell.checkBox.checkState = .unchecked
}else{
cell.checkBox.checkState = .checked
}
}
Apple has already given very good sample code for that on its website,
you can check at:https://developer.apple.com/library/content/samplecode/TableMultiSelect/Introduction/Intro.html

Expanding tableview cell data being overwritten when selected

I have a transaction tableview with different types of expenses that expands to show more detail when selected.
However the detail appears to be overwritten when this happens. I can see it flash and sometimes it does get populated. The textfields get populated correctly. I have been trying to debug this for a while, but not sure how to work around this problem.
Here is my current implementation:
// MARK: Tableview
extension TransactionViewController: UITableViewDelegate, UITableViewDataSource {
// MARK: - Table View
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardTableViewCell
cell.delegate = self
var isDetailHidden = true
if indexPath.row == rowSelected {
isDetailHidden = false
}
let transaction = transactionList[indexPath.row]
cell.configureCell(transaction: transaction, isDetailHidden: isDetailHidden)
return cell
}
func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return transactionList.count
}
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == rowSelected {
// don't refresh and set again.
return
}
rowSelected = indexPath.row
transactionBeingEdited = transactionList[indexPath.row]
transactionTableView.setContentOffset(CGPoint(x: 0, y: rowSelected! * 76), animated: true)
let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardTableViewCell
cell.delegate = self
cell.configureDetailCell()
transactionTableView.reloadData()
}
func tableView(_ tableView: UITableView, commit editingStyle: UITableViewCellEditingStyle, forRowAt indexPath: IndexPath) {
let transaction = transactionList[indexPath.row]
coreDataManager.deleteTransaction(transaction: transaction)
}
func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
if indexPath.row != rowSelected {
return 76.5
} else {
return 323
}
}
The variables in the detail section are dropdown boxes using a library. I've configured it in the UITableViewCell class. Setting up the dropdown methods occurs in the awakefromnib method.
private func setupBillDropDown() {
billDropDown.anchorView = bill
billDropDown.bottomOffset = CGPoint(x: 0, y: bill.bounds.height)
billDropDown.dataSource = TransactionType.list
// Action triggered on selection
billDropDown.selectionAction = { [unowned self] (index, item) in
self.bill.setTitle(item, for: .normal)
self.bill.setTitleColor(UIColor.white, for: .normal)
// Update transaction
if let transactionBeingEdited = self.delegate?.transactionBeingEdited {
transactionBeingEdited.type = item
self.coreDataManager.saveToCoreData()
self.coreDataManager.nc.post(name: .transactionBeingEdited, object: nil, userInfo: nil)
}
}
}
Thanks in advance.
I think in func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) you are overwriting the configured cell by loading the table. Try this:
func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
if indexPath.row == rowSelected {
// don't refresh and set again.
return
}
rowSelected = indexPath.row
transactionBeingEdited = transactionList[indexPath.row]
transactionTableView.setContentOffset(CGPoint(x: 0, y: rowSelected! * 76), animated: true)
//let cell = tableView.dequeueReusableCell(withIdentifier: "CardCell", for: indexPath) as! CardTableViewCell
let cell = tableView.cellForRow(at: indexPath)
cell.configureDetailCell()
tableView.reloadRows(at: [indexPath], with: .none)
}
I figured out the issue after spending literally hours on it... It's because I was updating the buttons title using
bill.titleLabel!.text = transaction.type ?? "Select Bill"
insteaad of
bill.setTitle(transaction.type ?? "Select Bill", for: .normal)

Resources