简体   繁体   中英

Adding Buttons to Static TableView Headers with Swift

I am trying to add UIControls to static TableViewHeaders in iOS using swift. The goal is build on top of the default appearance so the UI will match default UI elements going forward.

I found a great example of modifying the appearance of existing elements , but nothing on adding new ones.

My specific goals are:

  1. "Select All" functionality to quickly mark all rows in a section as "checked" (could be a checkmark accessory, UISwitch, etc)
  2. "Show/Hide" functionality to allow a single View to provide a simple "overview" by sections while still presenting access to details inside sections.

As both of these related to the section groupings, the headers are a logical choice for adding this functionality.

There are two main options for customizing static headers for TableViews:

willDisplayHeaderView provides the default view and allows for modification of it. Simple appearance modifications are fairly straight forward. Adding interactive features such as buttons is a bit more complicated

viewForHeaderInSection returns the view for the header, which can be loaded from a nib or created entirely in code. One disadvantage of this is that it gives no access to the default appearance of headers, and Apple only provides access to one default (UIColor.groupTableViewBackground).

To build on top of the default header, willDisplayHeaderView needs to be used.

override func tableView(_ tableView: UITableView, willDisplayHeaderView view: UIView, forSection section: Int)
{    
    let header = view as! UITableViewHeaderFooterView
    let headerLabelFont: UIFont = header.textLabel!.font

    // References for existing or new button
    var selectButton: UIButton? = nil

    // Check for existing button
    for i in 0..<view.subviews.count {
      if view.subviews[i] is UIButton {
          selectButton = view.subviews[i] as? UIButton
      }
    }

    // No button exist, create new one
    if selectButton == nil {
      selectButton = UIButton(type: .system)
      header.addSubview(selectButton!)
      toggleButton = UIButton(type: .system)
      header.addSubview(toggleButton!)
    }
    // Configure button
    selectButton?.frame = CGRect(x: view.frame.size.width - 85, y: view.frame.size.height - 28, width: 77, height: 26)
    selectButton?.tag = section
    selectButton?.setTitle("SELECT ALL", for: .normal)
    selectButton?.titleLabel?.font = UIFont(descriptor: headerLabelFont.fontDescriptor, size: 11)
    selectButton?.contentHorizontalAlignment = .right;
    selectButton?.setTitleColor(self.view.tintColor, for: .normal)
    selectButton?.addTarget(self, action: #selector(self.selectAllInSection), for: .touchUpInside)

}

func selectAllInSection() {
    ...

The biggest challenge is working around the fact that static header cells can be reused by the TableView. So if one is modified, for example by adding a button, then when it is reused a second button could be added. This is only a problem if the TableView is large enough to scrolll off screen, but should be guarded against as the results can be tough to track down.

If multiple buttons are added to a header, some mechanism to identify each button is needed. The UIButton.tag is one option, but in this example that field is used to identify which section to act on. Another option would be to use the tag string to include two pieces of information.

A full working demo can be found on Github

(yes answering my own question, wanted to give something back after leaching for years)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM