I am doing Swift project, there it has view more/view less option for each cell. I have did it with following code. And it was for for View more/View less options.
//ViewController Class
var expanded:[IndexPath] = [] //Custom protocol func viewMoreTapped(cell: tableviewcell) { let indexpath = EntriesTableView.indexPath(for: cell) let indexPath = IndexPath(item: indexpath!.row, section: indexpath!.section) if(expanded.contains(indexPath)) { expanded.removeAll { (checkPath) -> Bool in return checkPath == indexPath } } else { expanded.append(indexPath) } entriesTableView.beginUpdates() entriesTableView.reloadRows(at: [indexPath], with: .none) entriesTableView.endUpdates() } @IBAction func expandAllBtnAction(_ sender: Any) { isExpandedAll = !isExpandedAll expandAllButton.titlelabel.text = isExpandedAll ? "Open All" : "Close All" self.entriesTableView.reloadData() } func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { let cell = tableView.dequeueReusableCell(withIdentifier:"cellIdentifier", for: indexPath) as! MyTableViewCell let checkPath = IndexPath(row:indexPath.row, section: indexPath.section) if expanded.contains(checkPath) { cell.cellConfigure(index: indexPath.row, isexpanded: true, info: Info, expandedAll: isExpandedAll) } else { cell.cellConfigure(index: indexPath.row, isexpanded: false, info: Info, expandedAll: isExpandedAll) } return cell } //Tableview cell class var isExpanded: Bool = false func cellConfigure(index: Int, isexpanded : Bool, info: Info, expandedAll: Bool) { //For open all/close all handling if expandedAll && isExpanded == false { isExpanded = true viewMoreBtn.titleLabel?.text = "View Less" } else { viewMoreBtn.titleLabel?.text = isExpanded ? "View Less" : "View More" } //view more/view less handling cellHeight.constant = isExpanded ? 40 : 120 } @IBAction func viewMoreBtnAction(_ sender: Any) { isExpanded = !isExpanded delegate?.viewMoreTapped(cell: self) // this is custom protocol }
It is working fine for each cell View more/View less, But after user taps on open all, it should be open all cells and each cell if user has taps on view less, it should be close selected cell only. But, it's not working that time.
The requirement is
Any suggestions?
I would use an IndexSet
to track the expanded rows; It is easier to insert, remove and check for the presence of index paths using a set.
To collapse all of the rows you can simply remove all of the elements from the set. To expand all you insert all index paths into the set.
You haven't provided detail on how your table data is stored. For the purposes of my answer I am going to use an array of arrays called data
- The outer array is the sections and each inner array are the rows in that section. ie numberOfSections
is data.count
and the number of rows in a section is data[indexPath.section].count
View Controller
var expanded = [IndexSet]()
//Custom protocol
func loadData() {
// After data is fetched
self.expanded = Array(repeating: IndexSet(),count:data.count)
self.tableView.reloadData()
}
func viewMoreTapped(cell: tableviewcell) {
guard let indexPath = entriesTableView.indexPath(for: cell) else {
return
}
let row = indexPath.row
let section = indexPath.section
if self.expanded[section].contains(row) {
self.expanded[section].remove(row)
} else {
self.expanded[section].insert(row)
}
self.entriesTableView.beginUpdates()
self.entriesTableView.reloadRows(at: [indexPath], with: .none)
self.entriesTableView.endUpdates()
}
@IBAction func expandAllBtnAction(_ sender: Any) {
isExpandedAll.toggle()
expandAllButton.titlelabel.text = isExpandedAll ? "Open All" : "Close All"
if isExpandedAll {
self.expanded = data.map { return IndexSet(integersIn: 0..<$0.count)}
} else {
self.expanded = Array(repeating: IndexSet(),count:data.count)
}
self.entriesTableView.reloadData()
}
func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell = tableView.dequeueReusableCell(withIdentifier:"cellIdentifier", for:
indexPath) as! MyTableViewCell
cell.cellConfigure(isExpanded: self.expanded[indexPath.section].contains(indexPath.row), info: info) // A cell should never need to know its index path
return cell
}
Cell
var isExpanded: Bool = false
func cellConfigure(isExpanded : Bool, info: Info) {
viewMoreBtn.titleLabel?.text = isExpanded ? "View less":"View more"
cellHeight.constant = isExpanded ? 40 : 120
}
@IBAction func viewMoreBtnAction(_ sender: Any) {
delegate?.viewMoreTapped(cell: self) // this is custom protocol
}
A general note, variables and functions should start with a lower case letter. Class and struct names should start with an upper case letter.