2

I'm setting up a collapsable tableView, but something strange happens on the collapsable item. When you look at the video keep an eye on the "Where are you located" line.. (I'm using a .plist for the question and answer items)

Where do I go wrong, is it somewhere in my code? I don't want to let that line stick on the top :(

enter image description here

Here is the code I'm using but I can't find anything strange...

class FAQViewController: UIViewController, UITableViewDataSource, UITableViewDelegate {
    
    var questionsArray = [String]()
    var answersDict = Dictionary<String, [String]>() // multiple answers for a question
    var collapsedArray = [Bool]()
    
    @IBOutlet weak var tableView: UITableView!
    
    override func viewWillAppear(_ animated: Bool) {
        // Hide the navigation bar on the this view controller
        self.navigationController?.setNavigationBarHidden(true, animated: true)
    }
    
    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        
        addTableStyles()
        readQAFile()
        
        tableView.delegate = self
        tableView.dataSource = self
        self.tableView.register(UITableViewCell.self, forCellReuseIdentifier: "Cell")
    }
    
    func addTableStyles(){
        navigationController?.isNavigationBarHidden = false
        
        self.tableView?.backgroundView = {
            let view = UIView(frame: self.tableView.bounds)
            return view
        }()
        
        tableView.estimatedRowHeight = 43.0;
        tableView.rowHeight = UITableView.automaticDimension
        tableView.separatorStyle = UITableViewCell.SeparatorStyle.singleLine
    }
    
    func readQAFile(){
        guard let url = Bundle.main.url(forResource: "QA", withExtension: "plist")
            else { print("no QAFile found")
                return
        }
        
        let QAFileData = try! Data(contentsOf: url)
        let dict = try! PropertyListSerialization.propertyList(from: QAFileData, format: nil) as! Dictionary<String, Any>
        
        // Read the questions and answers from the plist
        questionsArray = dict["Questions"] as! [String]
        answersDict = dict["Answers"] as! Dictionary<String, [String]>
        
        // Initially collapse every question
        for _ in 0..<questionsArray.count {
            collapsedArray.append(false)
        }
    }
    
    func numberOfSections(in tableView: UITableView) -> Int {
        return questionsArray.count
    }
    
    func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int
    {
        if collapsedArray[section] {
            let ansCount = answersDict[String(section)]!
            return ansCount.count
        }
        return 0
    }
    
    func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
        // Set it to any number
        return 70
    }
    
    func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
        return 1
    }
    
    func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
        
        if collapsedArray[indexPath.section] {
            return UITableView.automaticDimension
        }
        return 2
    }
    
    func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
        
        let headerView = UIView(frame: CGRect(x:0, y:0, width:tableView.frame.size.width, height:40))
        headerView.tag = section
        
        let headerString = UILabel(frame: CGRect(x: 10, y: 10, width: tableView.frame.size.width, height: 50)) as UILabel
         headerString.text = "\(questionsArray[section])"
        headerView .addSubview(headerString)
        
        let headerTapped = UITapGestureRecognizer (target: self, action:#selector(sectionHeaderTapped(_:)))
        headerView.addGestureRecognizer(headerTapped)
        
        return headerView
    }
    
    @objc func sectionHeaderTapped(_ recognizer: UITapGestureRecognizer) {
        
        let indexPath : IndexPath = IndexPath(row: 0, section:recognizer.view!.tag)
        if (indexPath.row == 0) {
            
            let collapsed = collapsedArray[indexPath.section]
            
            collapsedArray[indexPath.section] = !collapsed
            
            //reload specific section animated
            let range = Range(NSRange(location: indexPath.section, length: 1))!
            let sectionToReload = IndexSet(integersIn: range)
            self.tableView.reloadSections(sectionToReload as IndexSet, with:UITableView.RowAnimation.fade)
        }
    }
    
    func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell{
        
        let cellIdentifier = "Cell"
        let cell: UITableViewCell! = self.tableView.dequeueReusableCell(withIdentifier: cellIdentifier)
        
        cell.textLabel?.adjustsFontSizeToFitWidth = true
        cell.textLabel?.numberOfLines = 0
        
        let manyCells : Bool = collapsedArray[indexPath.section]
        
        if (manyCells) {
            let content = answersDict[String(indexPath.section)]
            cell.textLabel?.text = content![indexPath.row]
        }
        
        return cell
    }
    
    override var prefersStatusBarHidden: Bool {
        return true
    }
    
}
gcharita
  • 7,729
  • 3
  • 20
  • 37
DeDe Schurk
  • 113
  • 11

2 Answers2

2

You need to change the style of the tableView to grouped, when you initialize it:

let tableView = UITableView(frame: someFrame, style: .grouped)

or from Storyboard:

enter image description here

After that you will have this issue, which I solved by setting a tableHeaderView to the tableView that has CGFloat.leastNormalMagnitude as its height:

override func viewDidLoad() {
    super.viewDidLoad()
    
    var frame = CGRect.zero
    frame.size.height = .leastNormalMagnitude
    tableView.tableHeaderView = UIView(frame: frame)
}
gcharita
  • 7,729
  • 3
  • 20
  • 37
1

Just remove your headerView from view hierarchy here

 @objc func sectionHeaderTapped(_ recognizer: UITapGestureRecognizer) {
    headerView.removeFromSuperview() 
    ...
    }

By the way, yes creating a openable tableview menu with using plist is one of the methods but it could be more simple. In my opinion you should refactor your code.

zeytin
  • 5,545
  • 4
  • 14
  • 38