Skip to content

Commit 4afd583

Browse files
committed
Animate the arrow when collapse the section.
1 parent 9fc90de commit 4afd583

File tree

4 files changed

+123
-7
lines changed

4 files changed

+123
-7
lines changed

ios-swift-collapsible-table-section.xcodeproj/project.pbxproj

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
objects = {
88

99
/* Begin PBXBuildFile section */
10+
0A12C8C21D9C3AAF00D0BEE3 /* Extensions.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A12C8C11D9C3AAF00D0BEE3 /* Extensions.swift */; };
1011
0A908DEF1CFCAA9200470F33 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 0A908DEE1CFCAA9200470F33 /* AppDelegate.swift */; };
1112
0A908DF61CFCAA9200470F33 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 0A908DF51CFCAA9200470F33 /* Assets.xcassets */; };
1213
0A908DF91CFCAA9200470F33 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 0A908DF71CFCAA9200470F33 /* LaunchScreen.storyboard */; };
@@ -15,6 +16,7 @@
1516
/* End PBXBuildFile section */
1617

1718
/* Begin PBXFileReference section */
19+
0A12C8C11D9C3AAF00D0BEE3 /* Extensions.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Extensions.swift; sourceTree = "<group>"; };
1820
0A908DEB1CFCAA9200470F33 /* ios-swift-collapsible-table-section.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = "ios-swift-collapsible-table-section.app"; sourceTree = BUILT_PRODUCTS_DIR; };
1921
0A908DEE1CFCAA9200470F33 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = "<group>"; };
2022
0A908DF51CFCAA9200470F33 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = "<group>"; };
@@ -60,6 +62,7 @@
6062
0A908DFA1CFCAA9200470F33 /* Info.plist */,
6163
0A908E001CFCAC7500470F33 /* CollapsibleTableViewController.swift */,
6264
0A908E021CFCB8D600470F33 /* CollapsibleTableViewHeader.swift */,
65+
0A12C8C11D9C3AAF00D0BEE3 /* Extensions.swift */,
6366
);
6467
path = "ios-swift-collapsible-table-section";
6568
sourceTree = "<group>";
@@ -138,6 +141,7 @@
138141
0A908E011CFCAC7500470F33 /* CollapsibleTableViewController.swift in Sources */,
139142
0A908E031CFCB8D600470F33 /* CollapsibleTableViewHeader.swift in Sources */,
140143
0A908DEF1CFCAA9200470F33 /* AppDelegate.swift in Sources */,
144+
0A12C8C21D9C3AAF00D0BEE3 /* Extensions.swift in Sources */,
141145
);
142146
runOnlyForDeploymentPostprocessing = 0;
143147
};

ios-swift-collapsible-table-section/CollapsibleTableViewController.swift

Lines changed: 14 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ class CollapsibleTableViewController: UITableViewController {
4040
sections = [
4141
Section(name: "Mac", items: ["MacBook", "MacBook Air", "MacBook Pro", "iMac", "Mac Pro", "Mac mini", "Accessories", "OS X El Capitan"]),
4242
Section(name: "iPad", items: ["iPad Pro", "iPad Air 2", "iPad mini 4", "Accessories"]),
43-
Section(name: "iPhone", items: ["iPhone 6s", "iPhone 6", "iPhone SE", "Accessories"])
43+
Section(name: "iPhone", items: ["iPhone 6s", "iPhone 6", "iPhone SE", "Accessories"]),
4444
]
4545
}
4646

@@ -76,7 +76,10 @@ extension CollapsibleTableViewController {
7676
override func tableView(tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? {
7777
let header = tableView.dequeueReusableHeaderFooterViewWithIdentifier("header") as? CollapsibleTableViewHeader ?? CollapsibleTableViewHeader(reuseIdentifier: "header")
7878

79-
header.textLabel?.text = sections[section].name
79+
header.titleLabel.text = sections[section].name
80+
header.arrowLabel.text = ">"
81+
header.setCollapsed(sections[section].collapsed)
82+
8083
header.section = section
8184
header.delegate = self
8285

@@ -86,6 +89,10 @@ extension CollapsibleTableViewController {
8689
override func tableView(tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat {
8790
return 44.0
8891
}
92+
93+
override func tableView(tableView: UITableView, heightForFooterInSection section: Int) -> CGFloat {
94+
return 1.0
95+
}
8996

9097
}
9198

@@ -94,12 +101,14 @@ extension CollapsibleTableViewController {
94101
//
95102
extension CollapsibleTableViewController: CollapsibleTableViewHeaderDelegate {
96103

97-
func toggleSection(section: Int) {
98-
let collapsed = sections[section].collapsed
104+
func toggleSection(header: CollapsibleTableViewHeader, section: Int) {
105+
let collapsed = !sections[section].collapsed
99106

100107
// Toggle collapse
101-
sections[section].collapsed = !collapsed
108+
sections[section].collapsed = collapsed
109+
header.setCollapsed(collapsed)
102110

111+
// Adjust the height of the rows inside the section
103112
tableView.beginUpdates()
104113
for i in 0 ..< sections[section].items.count {
105114
tableView.reloadRowsAtIndexPaths([NSIndexPath(forRow: i, inSection: section)], withRowAnimation: .Automatic)

ios-swift-collapsible-table-section/CollapsibleTableViewHeader.swift

Lines changed: 68 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,30 +9,96 @@
99
import UIKit
1010

1111
protocol CollapsibleTableViewHeaderDelegate {
12-
func toggleSection(section: Int)
12+
func toggleSection(header: CollapsibleTableViewHeader, section: Int)
1313
}
1414

1515
class CollapsibleTableViewHeader: UITableViewHeaderFooterView {
1616

1717
var delegate: CollapsibleTableViewHeaderDelegate?
1818
var section: Int = 0
1919

20+
let titleLabel = UILabel()
21+
let arrowLabel = UILabel()
22+
2023
override init(reuseIdentifier: String?) {
2124
super.init(reuseIdentifier: reuseIdentifier)
2225

26+
//
27+
// Constraint the size of arrow label for auto layout
28+
//
29+
arrowLabel.widthAnchor.constraintEqualToConstant(12).active = true
30+
arrowLabel.heightAnchor.constraintEqualToConstant(12).active = true
31+
32+
titleLabel.translatesAutoresizingMaskIntoConstraints = false
33+
arrowLabel.translatesAutoresizingMaskIntoConstraints = false
34+
35+
contentView.addSubview(titleLabel)
36+
contentView.addSubview(arrowLabel)
37+
38+
//
39+
// Call tapHeader when tapping on this header
40+
//
2341
addGestureRecognizer(UITapGestureRecognizer(target: self, action: #selector(CollapsibleTableViewHeader.tapHeader(_:))))
2442
}
2543

2644
required init?(coder aDecoder: NSCoder) {
2745
fatalError("init(coder:) has not been implemented")
2846
}
2947

48+
override func layoutSubviews() {
49+
super.layoutSubviews()
50+
51+
contentView.backgroundColor = UIColor(hex: 0x2E3944)
52+
53+
titleLabel.textColor = UIColor.whiteColor()
54+
arrowLabel.textColor = UIColor.whiteColor()
55+
56+
//
57+
// Autolayout the lables
58+
//
59+
let views = [
60+
"titleLabel" : titleLabel,
61+
"arrowLabel" : arrowLabel,
62+
]
63+
64+
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
65+
"H:|-20-[titleLabel]-[arrowLabel]-20-|",
66+
options: [],
67+
metrics: nil,
68+
views: views
69+
))
70+
71+
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
72+
"V:|-[titleLabel]-|",
73+
options: [],
74+
metrics: nil,
75+
views: views
76+
))
77+
78+
contentView.addConstraints(NSLayoutConstraint.constraintsWithVisualFormat(
79+
"V:|-[arrowLabel]-|",
80+
options: [],
81+
metrics: nil,
82+
views: views
83+
))
84+
}
85+
86+
//
87+
// Trigger toggle section when tapping on the header
88+
//
3089
func tapHeader(gestureRecognizer: UITapGestureRecognizer) {
3190
guard let cell = gestureRecognizer.view as? CollapsibleTableViewHeader else {
3291
return
3392
}
3493

35-
self.delegate?.toggleSection(cell.section)
94+
delegate?.toggleSection(self, section: cell.section)
95+
}
96+
97+
func setCollapsed(collapsed: Bool) {
98+
//
99+
// Animate the arrow rotation (see Extensions.swf)
100+
//
101+
arrowLabel.rotate(collapsed ? 0.0 : CGFloat(M_PI_2))
36102
}
37103

38104
}
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
//
2+
// Extensions.swift
3+
// ios-swift-collapsible-table-section
4+
//
5+
// Created by Yong Su on 9/28/16.
6+
// Copyright © 2016 Yong Su. All rights reserved.
7+
//
8+
9+
import UIKit
10+
11+
extension UIColor {
12+
13+
convenience init(hex:Int, alpha:CGFloat = 1.0) {
14+
self.init(
15+
red: CGFloat((hex & 0xFF0000) >> 16) / 255.0,
16+
green: CGFloat((hex & 0x00FF00) >> 8) / 255.0,
17+
blue: CGFloat((hex & 0x0000FF) >> 0) / 255.0,
18+
alpha: alpha
19+
)
20+
}
21+
22+
}
23+
24+
extension UIView {
25+
26+
func rotate(toValue: CGFloat, duration: CFTimeInterval = 0.2) {
27+
let animation = CABasicAnimation(keyPath: "transform.rotation")
28+
29+
animation.toValue = toValue
30+
animation.duration = duration
31+
animation.removedOnCompletion = false
32+
animation.fillMode = kCAFillModeForwards
33+
34+
self.layer.addAnimation(animation, forKey: nil)
35+
}
36+
37+
}

0 commit comments

Comments
 (0)