I'm trying to use the library ExpandableCell to add collapsable table view cells to my app. I'm using the latest version of the library which is 1.3.0.
Below is the full code.
import UIKit
import ExpandableCell
class ViewController: UIViewController {
@IBOutlet weak var tableView: ExpandableTableView!
private var passengers = [Passenger]()
override func viewDidLoad() {
super.viewDidLoad()
tableView.tableFooterView = UIView(frame: .zero)
tableView.expandableDelegate = self
passengers = [
Passenger(id: 1, name: "Mark", trips: [Trip(id: 1, route: "NY to NJ")]),
Passenger(id: 2, name: "Jesica", trips: [Trip(id: 1, route: "NY to NJ"), Trip(id: 2, route: "LA to LV")]),
Passenger(id: 3, name: "Brian", trips: [Trip(id: 2, route: "Kansas City to Denver")])
]
tableView.reloadData()
}
}
extension ViewController: ExpandableDelegate {
func expandableTableView(_ expandableTableView: ExpandableTableView, numberOfRowsInSection section: Int) -> Int {
return passengers.count
}
func expandableTableView(_ expandableTableView: ExpandableTableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier: PassengerCell.reuseIdentifier, for: indexPath) as! PassengerCell
let passenger = passengers[indexPath.row]
cell.textLabel?.text = passenger.name
cell.detailTextLabel?.text = "\(passenger.trips?.count ?? 0) trips"
return cell
}
func expandableTableView(_ expandableTableView: ExpandableTableView, expandedCellsForRowAt indexPath: IndexPath) -> [UITableViewCell]? {
let cell = tableView.dequeueReusableCell(withIdentifier: TripCell.reuseIdentifier, for: indexPath) as! TripCell
let passenger = passengers[indexPath.row]
if let trips = passenger.trips {
var cells = [TripCell]()
for trip in trips {
cell.textLabel?.text = trip.route
cells.append(cell)
}
return cells
} else {
return nil
}
}
func expandableTableView(_ expandableTableView: ExpandableTableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return 60
}
func expandableTableView(_ expandableTableView: ExpandableTableView, heightsForExpandedRowAt indexPath: IndexPath) -> [CGFloat]? {
let count = passengers[indexPath.row].trips?.count ?? 0
let heightArray = [CGFloat](repeating: 50, count: count)
return heightArray
}
func expandableTableView(_ expandableTableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool {
return true
}
}
The data is loaded correctly and the tableview appears as expected. But the problem is when you tap on a collapsed cell. It acts...weird.
Notice how some cells don't appear at all (the second group should show 2 yellow cells). And some cells appear in other groups that they don't belong in. It looks like a cell reuse issue.
I tried overriding the prepareForReuse
method and reset the controls manually as well but that didn't work either.
override func prepareForReuse() {
super.prepareForReuse()
textLabel?.text = nil
backgroundColor = nil
}
I saw some similar issues in the library's Github repo but there aren't any answers or fixes.
If anyone has used this library before, any idea what might be causing this issue and how to fix it?
Looking at your Demo Project...
In expandedCellsForRowAt
in ViewController
, you are creating one cell object, then assigning it different text values and appending it to an array.
func expandableTableView(_ expandableTableView: ExpandableTableView, expandedCellsForRowAt indexPath: IndexPath) -> [UITableViewCell]? {
// here, you create a cell object
let cell = tableView.dequeueReusableCell(withIdentifier: TripCell.reuseIdentifier, for: indexPath) as! TripCell
let passenger = passengers[indexPath.row]
if let trips = passenger.trips {
var cells = [TripCell]()
for trip in trips {
// here, you repeatedly set the text of the SAME cell object
cell.textLabel?.text = trip.route
cells.append(cell)
}
return cells
} else {
return nil
}
}
Use this instead:
func expandableTableView(_ expandableTableView: ExpandableTableView, expandedCellsForRowAt indexPath: IndexPath) -> [UITableViewCell]? {
// Don't create the cell here
//let cell = tableView.dequeueReusableCell(withIdentifier: TripCell.reuseIdentifier, for: indexPath) as! TripCell
let passenger = passengers[indexPath.row]
if let trips = passenger.trips {
var cells = [TripCell]()
for trip in trips {
// create a NEW cell for each trip (don't use indexPath)
let cell = tableView.dequeueReusableCell(withIdentifier: TripCell.reuseIdentifier) as! TripCell
cell.textLabel?.text = trip.route
cells.append(cell)
}
return cells
} else {
return nil
}
}