0

I researched all StackOverflow about Expandable Table View, but they have posted only a show header with the cells. In fact that iOS 15 has changed the new design interfaces of the UITableView as known .insetGrouped.

Basically Header in .insetGrouped really terrible design interfaces for Expandable. I am trying to get my idea to use only cell to do Expandable without section needed.

My Table View codes Here:

class HelpViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    struct Object {
        var seactionName: String!
        var seactionObjection: [String]!
        var footerName: String!
    }
   
    var objectArray = [Object]()
    
    
    var TableView = UITableView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        
        objectArray = [
            Object(seactionName: "Header", seactionObjection: ["Expandable Cell", "One Row", "Two Row"],
                   
                footerName: "Footer"),
        
            
            // copy and paste new cells
        ]
   
        title = "Help Center"
        
        view.backgroundColor = UIColor.quaternarySystemFill
    
        TableView.frame = view.bounds
       
        TableView = UITableView(frame: self.view.bounds, style: UITableView.Style.insetGrouped)
        TableView.showsVerticalScrollIndicator = true
        TableView.indicatorStyle = .default
        TableView.register(SliceCell.self, forCellReuseIdentifier: "Slice List")
        
        TableView.delegate = self
        TableView.dataSource = self
        
        view.addSubview(TableView)
    
    }


    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        return objectArray[section].seactionObjection.count
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
       
        return objectArray.count
        
    }
    
        func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {

            return objectArray[section].seactionName

        }



func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
    return objectArray[section].footerName
}
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
  
        
        let cell = tableView.dequeueReusableCell(withIdentifier: "Slice List") as! SliceCell
        
        cell.backgroundColor = .secondarySystemGroupedBackground
            cell.textLabel?.text = objectArray[indexPath.section].seactionObjection[indexPath.row]
            cell.textLabel?.numberOfLines = 0
        
        return cell
    }

func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
    view.tintColor = .clear
    let header = view as! UITableViewHeaderFooterView
    header.textLabel?.textColor = UIColor.label
}


}

Well, I could change this code

cell.accessoryType = .disclosureIndicator

to this

 let disclosureIndicatorTapped = UIImageView()
        disclosureIndicatorTapped.image = UIImage(systemName: "chevron.forward") // When tapped automatic to "Chevron.down"
        cell.accessoryView = disclosureIndicatorTapped

Any idea how to get Expandable Cells in UITableView with Swift, without Header or Footer needed?

Thanks!

Antonio Adrian Chavez
  • 1,016
  • 1
  • 7
  • 12
  • It's not clear what you're going for... Do you **want** the `.insetGrouped` look? Or not? Do you **want** a header and footer for each section? Or, do you want no section headers/footers but you want to tap the first row in a section to expand/collapse that section? It might help if you manually layout how you want your table to look and post a screen-shot of it. – DonMag Dec 04 '21 at 16:25
  • I want my TableView .insetgrouped. I don’t want headed of footer do expand/collapse. Only cell to do expand/collapse like that. – Antonio Adrian Chavez Dec 04 '21 at 17:26

1 Answers1

1

You can add a Bool "expanded" property to your Object.

In numberOfRowsInSection, if expanded is True, return the count of items in seactionObjection, else return 1.

Then, in didSelectRowAt, if it's the first row in a section, toggle the expanded property of that section's Object, and reload the section.

Here's a modified version of your controller class:

class HelpViewController: UIViewController, UITableViewDelegate, UITableViewDataSource {
    
    struct Object {
        var seactionName: String!
        var expanded: Bool!
        var seactionObjection: [String]!
        var footerName: String!
    }
    
    var objectArray = [Object]()
    
    var TableView = UITableView()
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view.
        
        
        objectArray = [
            Object(seactionName: "Header 1",
                   expanded: false,
                   seactionObjection: ["Expandable Cell 1", "One Row 1", "Two Row 1"],
                   footerName: "Footer 1"),
            
            Object(seactionName: "Header 2",
                   expanded: false,
                   seactionObjection: ["Expandable Cell 2", "One Row 2", "Two Row 2"],
                   footerName: "Footer 2"),
            
            Object(seactionName: "Header 3",
                   expanded: false,
                   seactionObjection: ["Expandable Cell 3", "One Row 3", "Two Row 3"],
                   footerName: "Footer 3"),
            

            // copy and paste new cells
        ]
        
        title = "Help Center"
        
        view.backgroundColor = UIColor.quaternarySystemFill
        
        TableView.frame = view.bounds
        
        TableView = UITableView(frame: self.view.bounds, style: UITableView.Style.insetGrouped)
        TableView.showsVerticalScrollIndicator = true
        TableView.indicatorStyle = .default
        TableView.register(SliceCell.self, forCellReuseIdentifier: "Slice List")
        
        TableView.delegate = self
        TableView.dataSource = self
        
        view.addSubview(TableView)
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
        // if section is expanded
        //  return count of seactionObjection
        // else
        //  return 1
        return objectArray[section].expanded ? objectArray[section].seactionObjection.count : 1
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return objectArray.count
    }
    
    func tableView(_ tableView: UITableView, titleForHeaderInSection section: Int) -> String? {
        return objectArray[section].seactionName
    }
    
    func tableView(_ tableView: UITableView, titleForFooterInSection section: Int) -> String? {
        return objectArray[section].footerName
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
        let cell = tableView.dequeueReusableCell(withIdentifier: "Slice List") as! SliceCell
        
        cell.backgroundColor = .secondarySystemGroupedBackground
        cell.textLabel?.text = objectArray[indexPath.section].seactionObjection[indexPath.row]
        cell.textLabel?.numberOfLines = 0
        
        // if it's the first row in a section,
        //  show accessoryView with
        //      chevron.up or chevron.down
        //  based on section Object expanded property
        if indexPath.row == 0 {
            let chevronName = objectArray[indexPath.section].expanded ? "chevron.up" : "chevron.down"
            let img = UIImage(systemName: chevronName)
            let disclosureView = UIImageView(image: img)
            cell.accessoryView = disclosureView
        } else {
            // not the first row in a section, so
            //  clear the accessoryView
            cell.accessoryView = nil
        }
    
        return cell
    }
    
    func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int){
        view.tintColor = .clear
        let header = view as! UITableViewHeaderFooterView
        header.textLabel?.textColor = UIColor.label
    }
    
    func tableView(_ tableView: UITableView, didSelectRowAt indexPath: IndexPath) {
        if indexPath.row == 0 {
            objectArray[indexPath.section].expanded.toggle()
            tableView.reloadSections([indexPath.section], with: .automatic)
        } else {
            // do something else on row selection
        }
    }
    
}
DonMag
  • 69,424
  • 5
  • 50
  • 86
  • I write from your code and get understood how to work! That is eaiser and simple understood! Thank you so much, But one things you forgot about this, how can you do `.disclosureIndicator` to `.disclosureIndicatorTapped ` to display when tap cell and you will see right turn down like that on `cell.accessoryView`. Thanks you! – Antonio Adrian Chavez Dec 05 '21 at 00:05
  • @AntonioAdrianChavez - In `cellForRowAt`, decide whether to set or clear the `.accessoryView` based on the `.row`, and which image to use based on the section Object's `.expanded` property. I've edited my answer with one way to do it, but I encourage you to try it yourself first... could be a good learning experience. – DonMag Dec 05 '21 at 13:56
  • Btw: I knew those UITableViewController basics Codes for many years that I used UITableViewController. I was learning more carefully with your code simple Since 25 min. I starting to understand it. :) Hey @DonMag, Do you think it was recommended to use the up arrow and down arrow with the SF Symbol, not the right arrow then the down arrow? – Antonio Adrian Chavez Dec 06 '21 at 00:15
  • @AntonioAdrianChavez - that's a design question, so it's up to you as the app designer. Personally, when I see a right-chevron, I expect it to "go somewhere." When I see a left-chevron, I expect it to "go back." For expand/collapse type of functionality, I'd expect up/down chevrons... or, a button labeled "Expand/Collapse"... or a "More/Less" button... or something else. – DonMag Dec 06 '21 at 13:22
  • Alright, Understood. Thank you so much for some tips and helpful answers! :) – Antonio Adrian Chavez Dec 06 '21 at 21:03