// Arrow label
contentView.addSubview(arrowLabel)
arrowLabel.textColor = UIColor.white
arrowLabel.translatesAutoresizingMaskIntoConstraints = false
arrowLabel.widthAnchor.constraint(equalToConstant: 12).isActive = true
arrowLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
arrowLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
arrowLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
//
// Call tapHeader when tapping on this header
//
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(CollapsibleTableViewHeader.tapHeader(_:))))
完整代码:
import UIKit
protocol CollapsibleTableViewHeaderDelegate {
func toggleSection(_ header: CollapsibleTableViewHeader, section: Int)
}
class CollapsibleTableViewHeader: UITableViewHeaderFooterView {
var delegate: CollapsibleTableViewHeaderDelegate?
var section: Int = 0
let titleLabel = UILabel()
let arrowLabel = UILabel()
override init(reuseIdentifier: String?) {
super.init(reuseIdentifier: reuseIdentifier)
// Content View
contentView.backgroundColor = UIColor(hex: 0x2E3944)
let marginGuide = contentView.layoutMarginsGuide
// Arrow label
contentView.addSubview(arrowLabel)
arrowLabel.textColor = UIColor.white
arrowLabel.translatesAutoresizingMaskIntoConstraints = false
arrowLabel.widthAnchor.constraint(equalToConstant: 12).isActive = true
arrowLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
arrowLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
arrowLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
// Title label
contentView.addSubview(titleLabel)
titleLabel.textColor = UIColor.white
titleLabel.translatesAutoresizingMaskIntoConstraints = false
titleLabel.topAnchor.constraint(equalTo: marginGuide.topAnchor).isActive = true
titleLabel.trailingAnchor.constraint(equalTo: marginGuide.trailingAnchor).isActive = true
titleLabel.bottomAnchor.constraint(equalTo: marginGuide.bottomAnchor).isActive = true
titleLabel.leadingAnchor.constraint(equalTo: marginGuide.leadingAnchor).isActive = true
//
// Call tapHeader when tapping on this header
//
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(CollapsibleTableViewHeader.tapHeader(_:))))
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
//
// Trigger toggle section when tapping on the header
//
func tapHeader(_ gestureRecognizer: UITapGestureRecognizer) {
guard let cell = gestureRecognizer.view as? CollapsibleTableViewHeader else {
return
}
delegate?.toggleSection(self, section: cell.section)
}
func setCollapsed(_ collapsed: Bool) {
//
// Animate the arrow rotation (see Extensions.swf)
//
arrowLabel.rotate(collapsed ? 0.0 : .pi / 2)
}
}
extension UIView {
func rotate(_ toValue: CGFloat, duration: CFTimeInterval = 0.2) {
let animation = CABasicAnimation(keyPath: "transform.rotation")
animation.toValue = toValue
animation.duration = duration
animation.isRemovedOnCompletion = false
animation.fillMode = kCAFillModeForwards
self.layer.add(animation, forKey: nil)
}
}
import UIKit
//
// MARK: - View Controller
//
class CollapsibleTableViewController: UITableViewController {
var sections = sectionsData
override func viewDidLoad() {
super.viewDidLoad()
// Auto resizing the height of the cell
tableView.estimatedRowHeight = 44.0
tableView.rowHeight = UITableViewAutomaticDimension
self.title = "Apple Products"
}
}
//
// MARK: - View Controller DataSource and Delegate
//
extension CollapsibleTableViewController {
override func numberOfSections(in tableView: UITableView) -> Int {
return sections.count
}
override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int {
return sections[section].collapsed ? 0 : sections[section].items.count
}
// Cell
override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell {
let cell: CollapsibleTableViewCell = tableView.dequeueReusableCell(withIdentifier: "cell") as? CollapsibleTableViewCell ??
CollapsibleTableViewCell(style: .default, reuseIdentifier: "cell")
let item: Item = sections[indexPath.section].items[indexPath.row]
cell.nameLabel.text = item.name
cell.detailLabel.text = item.detail
return cell
}
override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat {
return UITableViewAutomaticDimension
}
// Header
override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
let header = tableView.dequeueReusableHeaderFooterView(withIdentifier: "header") as? CollapsibleTableViewHeader ?? CollapsibleTableViewHeader(reuseIdentifier: "header")
header.titleLabel.text = sections[section].name
header.arrowLabel.text = ">"
header.setCollapsed(sections[section].collapsed)
header.section = section
header.delegate = self
return header
}
override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
return 44.0
}
override func tableView(_ tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
return 1.0
}
}
//
// MARK: - Section Header Delegate
//
extension CollapsibleTableViewController: CollapsibleTableViewHeaderDelegate {
func toggleSection(_ header: CollapsibleTableViewHeader, section: Int) {
let collapsed = !sections[section].collapsed
// Toggle collapse
sections[section].collapsed = collapsed
header.setCollapsed(collapsed)
tableView.reloadSections(NSIndexSet(index: section) as IndexSet, with: .automatic)
}
}