├── .gitignore ├── AccordionTableViewController.podspec ├── Classes ├── AccordionTableViewController.swift └── SectionHeaderView.xib ├── Demo ├── AccordionExample.xcodeproj │ ├── project.pbxproj │ └── project.xcworkspace │ │ └── contents.xcworkspacedata └── AccordionExample │ ├── AppDelegate.swift │ ├── Assets.xcassets │ ├── AppIcon.appiconset │ │ └── Contents.json │ ├── Contents.json │ ├── carat-open.imageset │ │ ├── Contents.json │ │ └── Sort Down Filled-30-2.png │ ├── carat.imageset │ │ ├── Contents.json │ │ └── Sort Right Filled-30-2.png │ ├── facebook.imageset │ │ ├── Contents.json │ │ └── facebook.png │ ├── linkedin.imageset │ │ ├── Contents.json │ │ └── linkedin.png │ └── twitter.imageset │ │ ├── Contents.json │ │ └── twitter.png │ ├── Base.lproj │ ├── LaunchScreen.storyboard │ └── Main.storyboard │ ├── Info.plist │ ├── SectionFactory.swift │ ├── SectionViewController.swift │ └── ViewController.swift ├── LICENSE ├── README.md └── demo.gif /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | build/ 4 | *.pbxuser 5 | !default.pbxuser 6 | *.mode1v3 7 | !default.mode1v3 8 | *.mode2v3 9 | !default.mode2v3 10 | *.perspectivev3 11 | !default.perspectivev3 12 | xcuserdata 13 | *.xccheckout 14 | *.moved-aside 15 | DerivedData 16 | *.hmap 17 | *.ipa 18 | *.xcuserstate 19 | 20 | # CocoaPods 21 | # 22 | # We recommend against adding the Pods directory to your .gitignore. However 23 | # you should judge for yourself, the pros and cons are mentioned at: 24 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control 25 | # 26 | # Pods/ 27 | 28 | # Carthage 29 | # 30 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 31 | # Carthage/Checkouts 32 | 33 | Carthage/Build 34 | 35 | Example/.idea/.name 36 | 37 | Example/.idea/encodings.xml 38 | 39 | Example/.idea/Example.iml 40 | 41 | Example/.idea/modules.xml 42 | 43 | Example/.idea/scopes/scope_settings.xml 44 | 45 | Example/.idea/vcs.xml 46 | 47 | Example/.idea/workspace.xml 48 | 49 | Example/.idea/xcode.xml 50 | -------------------------------------------------------------------------------- /AccordionTableViewController.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "AccordionTableViewController" 4 | s.version = "0.0.3" 5 | s.summary = "Accordion UITableViewController" 6 | s.description = <<-DESC 7 | Swift version of https://github.com/klevison/KMAccordionTableViewController 8 | DESC 9 | s.homepage = "https://github.com/klevison/AccordionTableViewController" 10 | s.screenshots = "http://dl.dropbox.com/u/378729/MBProgressHUD/1.png" 11 | s.license = { :type => 'MIT', :file => 'LICENSE' } 12 | s.author = { "Klevison Matias" => "klevison@gmail.com" } 13 | s.source = { :git => "https://github.com/klevison/AccordionTableViewController.git", :tag => s.version.to_s } 14 | s.social_media_url = 'https://twitter.com/klevison' 15 | 16 | s.platform = :ios, '8.0' 17 | s.requires_arc = true 18 | 19 | s.source_files = "Classes", "Classes/**/*.{swift}" 20 | s.resource_bundles = { 21 | 'AccordionTableViewController' => ['Classes/**/*.{xib,png,nib}'] 22 | } 23 | 24 | end 25 | -------------------------------------------------------------------------------- /Classes/AccordionTableViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Accordion.swift 3 | // AccordionTableViewController 4 | // 5 | // Created by Klevison Matias on 1/6/17. 6 | // Copyright © 2017 Klevison. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | //MARK: AccordionTableViewController 12 | 13 | protocol AccordionTableViewControllerDelegate: class { 14 | func accordionTableViewControllerSectionDidOpen(section: Section) 15 | func accordionTableViewControllerSectionDidClose(section: Section) 16 | } 17 | 18 | class AccordionTableViewController: UITableViewController { 19 | 20 | var openAnimation: UITableViewRowAnimation = .fade 21 | var closeAnimation: UITableViewRowAnimation = .fade 22 | var sections = [Section]() 23 | var oneSectionAlwaysOpen = false 24 | weak var delegate: AccordionTableViewControllerDelegate? 25 | fileprivate let sectionHeaderViewIdentifier = "SectionHeaderViewIdentifier" 26 | fileprivate let sectionCellID = "CellIdentifier" 27 | var openedSection: Section? { 28 | return sections 29 | .filter { $0.open == true } 30 | .first 31 | } 32 | 33 | override func viewDidLoad() { 34 | super.viewDidLoad() 35 | 36 | setupTableView() 37 | } 38 | 39 | private func setupTableView() { 40 | let sectionHeaderNib = UINib(nibName: "SectionHeaderView", bundle: nil) 41 | tableView.register(sectionHeaderNib, forHeaderFooterViewReuseIdentifier: sectionHeaderViewIdentifier) 42 | tableView.bounces = false 43 | tableView.separatorStyle = .none 44 | } 45 | 46 | func reloadOpenedSection() { 47 | openedSection 48 | .flatMap { [IndexPath(row: 0, section: $0.sectionIndex!)] } 49 | .map { tableView.reloadRows(at: $0, with: openAnimation) } 50 | } 51 | 52 | private func indexPathsToDelete() -> [IndexPath] { 53 | if let previousOpenSection = openedSection, let previousOpenSectionIndex = previousOpenSection.sectionIndex { 54 | return [IndexPath(row: 0, section: previousOpenSectionIndex)] 55 | } 56 | 57 | return [IndexPath]() 58 | } 59 | 60 | private func updateTable(insert indexPathsToInsert: [IndexPath], delete indexPathsToDelete: [IndexPath]) { 61 | tableView.beginUpdates() 62 | tableView.insertRows(at: indexPathsToInsert, with: openAnimation) 63 | tableView.deleteRows(at: indexPathsToDelete, with: closeAnimation) 64 | tableView.endUpdates() 65 | 66 | let sectionRect = tableView.rect(forSection: indexPathsToInsert[0].section) 67 | tableView.scrollRectToVisible(sectionRect, animated: true) 68 | 69 | if let index = indexPathsToInsert.first?.section { 70 | delegate?.accordionTableViewControllerSectionDidOpen(section: sections[index]) 71 | } 72 | if let index = indexPathsToDelete.first?.section { 73 | delegate?.accordionTableViewControllerSectionDidClose(section: sections[index]) 74 | } 75 | 76 | } 77 | 78 | func openSection(at index: Int) { 79 | let indexPathsToInsert = [IndexPath(row: 0, section: index)] 80 | let indexPathsToDelete = self.indexPathsToDelete() 81 | 82 | if let previousOpenSection = openedSection, let previousOpenSectionIndex = previousOpenSection.sectionIndex { 83 | previousOpenSection.open = false 84 | guard let praviousSectionHeaderView = tableView.headerView(forSection: previousOpenSectionIndex) as? SectionHeaderView else { 85 | return 86 | } 87 | praviousSectionHeaderView.disclosureButton.isSelected = false 88 | delegate?.accordionTableViewControllerSectionDidClose(section: previousOpenSection) 89 | } 90 | sections[index].open = true 91 | updateTable(insert: indexPathsToInsert, delete: indexPathsToDelete) 92 | } 93 | 94 | func closeSection(at index: Int) { 95 | let currentSection = sections[index] 96 | currentSection.open = false 97 | if tableView.numberOfRows(inSection: index) > 0 { 98 | var indexPathsToDelete = [IndexPath]() 99 | indexPathsToDelete.append(IndexPath(row: 0, section: index)) 100 | tableView.deleteRows(at: indexPathsToDelete, with: closeAnimation) 101 | } 102 | delegate?.accordionTableViewControllerSectionDidClose(section: currentSection) 103 | } 104 | 105 | } 106 | 107 | extension AccordionTableViewController { 108 | 109 | override func numberOfSections(in tableView: UITableView) -> Int { 110 | return sections.count 111 | } 112 | 113 | override func tableView(_ tableView: UITableView, numberOfRowsInSection section: Int) -> Int { 114 | if sections[section].open { 115 | return 1 116 | } 117 | 118 | return 0 119 | } 120 | 121 | override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 122 | let section = sections[indexPath.section] 123 | let cellIdentifier = "\(sectionCellID)\(section.sectionIndex!)" 124 | tableView.register(UITableViewCell.self, forCellReuseIdentifier: cellIdentifier) 125 | let cell = tableView.dequeueReusableCell(withIdentifier: cellIdentifier, for: indexPath) as UITableViewCell 126 | cell.contentView.addSubview(section.view!) 127 | cell.contentView.autoresizesSubviews = false 128 | cell.contentView.frame = section.view!.frame 129 | 130 | return cell 131 | } 132 | 133 | override func tableView(_ tableView: UITableView, heightForRowAt indexPath: IndexPath) -> CGFloat { 134 | return sections[indexPath.section].view?.frame.size.height ?? 0 135 | } 136 | 137 | override func tableView(_ tableView: UITableView, heightForHeaderInSection section: Int) -> CGFloat { 138 | return sections[section].appearance.headerHeight 139 | } 140 | 141 | override func tableView(_ tableView: UITableView, shouldHighlightRowAt indexPath: IndexPath) -> Bool { 142 | return false 143 | } 144 | 145 | override func tableView(_ tableView: UITableView, viewForHeaderInSection section: Int) -> UIView? { 146 | guard let sectionHeaderView = tableView.dequeueReusableHeaderFooterView(withIdentifier: sectionHeaderViewIdentifier) as? SectionHeaderView else { 147 | return nil 148 | } 149 | let currentSection = sections[section] 150 | if currentSection.backgroundColor != nil { 151 | currentSection.appearance.headerColor = currentSection.backgroundColor! 152 | } 153 | 154 | currentSection.sectionIndex = section 155 | currentSection.headerView = sectionHeaderView 156 | sectionHeaderView.headerSectionAppearence = currentSection.appearance 157 | sectionHeaderView.titleLabel.text = currentSection.title 158 | sectionHeaderView.section = section 159 | sectionHeaderView.delegate = self 160 | sectionHeaderView.disclosureButton.isSelected = currentSection.open 161 | 162 | //TODO: refact it 163 | if let overlayView = currentSection.overlayView { 164 | sectionHeaderView.addOverHeaderSubView(view: overlayView) 165 | } 166 | 167 | if oneSectionAlwaysOpen && section == 0 && openedSection == nil{ 168 | openSection(at: section) 169 | sectionHeaderView.disclosureButton.isSelected = true 170 | } 171 | 172 | return sectionHeaderView 173 | } 174 | 175 | } 176 | 177 | extension AccordionTableViewController: SectionHeaderViewDelegate { 178 | 179 | func sectionHeaderView(sectionHeaderView: SectionHeaderView, selectedAtIndex index: Int) { 180 | let section = sections[index] 181 | if !section.open { 182 | openSection(at: index) 183 | sectionHeaderView.disclosureButton.isSelected = true 184 | } else if !oneSectionAlwaysOpen { 185 | closeSection(at: index) 186 | sectionHeaderView.disclosureButton.isSelected = oneSectionAlwaysOpen && openedSection?.sectionIndex == index 187 | } 188 | } 189 | 190 | } 191 | 192 | //MARK: Section 193 | 194 | final class Section { 195 | 196 | var open = false 197 | var view: UIView? 198 | var overlayView: UIView? 199 | var headerView: SectionHeaderView? 200 | var title: String? 201 | var backgroundColor: UIColor? 202 | var sectionIndex: Int? 203 | var appearance = Appearance() 204 | 205 | } 206 | 207 | //MARK: Appearance 208 | 209 | final class Appearance { 210 | 211 | var headerHeight = CGFloat(50) 212 | var headerFont = UIFont.systemFont(ofSize: 15) 213 | var headerTitleColor = UIColor.black 214 | var headerColor = UIColor.white 215 | var headerSeparatorColor = UIColor.black 216 | var headerArrowImageOpened = #imageLiteral(resourceName: "carat") 217 | var headerArrowImageClosed = #imageLiteral(resourceName: "carat-open") 218 | 219 | } 220 | 221 | //MARK: SectionHeaderView 222 | 223 | protocol SectionHeaderViewDelegate: class { 224 | func sectionHeaderView(sectionHeaderView: SectionHeaderView, selectedAtIndex index: NSInteger) 225 | } 226 | 227 | final class SectionHeaderView: UITableViewHeaderFooterView { 228 | 229 | @IBOutlet weak var titleLabel: UILabel! 230 | @IBOutlet weak var disclosureButton: UIButton! 231 | @IBOutlet weak var headerSeparatorView: UIView! 232 | @IBOutlet weak var backgroundHeaderView: UIView! 233 | @IBOutlet weak var overHeaderView: UIView! 234 | 235 | weak var delegate: SectionHeaderViewDelegate? 236 | var section: NSInteger? 237 | var headerSectionAppearence: Appearance? { 238 | didSet { 239 | headerSeparatorView.backgroundColor = headerSectionAppearence!.headerSeparatorColor 240 | backgroundHeaderView.backgroundColor = headerSectionAppearence!.headerColor 241 | titleLabel.font = headerSectionAppearence!.headerFont 242 | titleLabel.textColor = headerSectionAppearence!.headerTitleColor 243 | disclosureButton.setImage(headerSectionAppearence!.headerArrowImageOpened, for: .normal) 244 | disclosureButton.setImage(headerSectionAppearence!.headerArrowImageClosed, for: .selected) 245 | } 246 | } 247 | 248 | override func awakeFromNib() { 249 | super.awakeFromNib() 250 | 251 | let tapGesture = UITapGestureRecognizer(target: self, action: #selector(SectionHeaderView.toggleOpen(_:))) 252 | self.addGestureRecognizer(tapGesture) 253 | } 254 | 255 | override func prepareForReuse() { 256 | super.prepareForReuse() 257 | 258 | overHeaderView.subviews.forEach { $0.removeFromSuperview() } 259 | } 260 | 261 | func addOverHeaderSubView(view: UIView) { 262 | self.overHeaderView.addSubview(view) 263 | } 264 | 265 | @IBAction func toggleOpen(_ sender: AnyObject) { 266 | delegate?.sectionHeaderView(sectionHeaderView: self, selectedAtIndex: section!) 267 | } 268 | 269 | } 270 | -------------------------------------------------------------------------------- /Classes/SectionHeaderView.xib: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 36 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | -------------------------------------------------------------------------------- /Demo/AccordionExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | BE6AFF3E1E269FFD004C7B80 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6AFF3D1E269FFD004C7B80 /* AppDelegate.swift */; }; 11 | BE6AFF401E269FFD004C7B80 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6AFF3F1E269FFD004C7B80 /* ViewController.swift */; }; 12 | BE6AFF431E269FFD004C7B80 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE6AFF411E269FFD004C7B80 /* Main.storyboard */; }; 13 | BE6AFF451E269FFD004C7B80 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = BE6AFF441E269FFD004C7B80 /* Assets.xcassets */; }; 14 | BE6AFF481E269FFD004C7B80 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = BE6AFF461E269FFD004C7B80 /* LaunchScreen.storyboard */; }; 15 | BE6AFF521E26A04B004C7B80 /* AccordionTableViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6AFF501E26A04B004C7B80 /* AccordionTableViewController.swift */; }; 16 | BE6AFF531E26A04B004C7B80 /* SectionHeaderView.xib in Resources */ = {isa = PBXBuildFile; fileRef = BE6AFF511E26A04B004C7B80 /* SectionHeaderView.xib */; }; 17 | BE6AFF551E26A911004C7B80 /* SectionViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6AFF541E26A911004C7B80 /* SectionViewController.swift */; }; 18 | BE6AFF571E26A943004C7B80 /* SectionFactory.swift in Sources */ = {isa = PBXBuildFile; fileRef = BE6AFF561E26A943004C7B80 /* SectionFactory.swift */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXFileReference section */ 22 | BE6AFF3A1E269FFD004C7B80 /* AccordionExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = AccordionExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 23 | BE6AFF3D1E269FFD004C7B80 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 24 | BE6AFF3F1E269FFD004C7B80 /* ViewController.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 25 | BE6AFF421E269FFD004C7B80 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 26 | BE6AFF441E269FFD004C7B80 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 27 | BE6AFF471E269FFD004C7B80 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 28 | BE6AFF491E269FFD004C7B80 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 29 | BE6AFF501E26A04B004C7B80 /* AccordionTableViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = AccordionTableViewController.swift; sourceTree = ""; }; 30 | BE6AFF511E26A04B004C7B80 /* SectionHeaderView.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = SectionHeaderView.xib; sourceTree = ""; }; 31 | BE6AFF541E26A911004C7B80 /* SectionViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionViewController.swift; sourceTree = ""; }; 32 | BE6AFF561E26A943004C7B80 /* SectionFactory.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = SectionFactory.swift; sourceTree = ""; }; 33 | /* End PBXFileReference section */ 34 | 35 | /* Begin PBXFrameworksBuildPhase section */ 36 | BE6AFF371E269FFD004C7B80 /* Frameworks */ = { 37 | isa = PBXFrameworksBuildPhase; 38 | buildActionMask = 2147483647; 39 | files = ( 40 | ); 41 | runOnlyForDeploymentPostprocessing = 0; 42 | }; 43 | /* End PBXFrameworksBuildPhase section */ 44 | 45 | /* Begin PBXGroup section */ 46 | BE6AFF311E269FFD004C7B80 = { 47 | isa = PBXGroup; 48 | children = ( 49 | BE6AFF3C1E269FFD004C7B80 /* AccordionExample */, 50 | BE6AFF3B1E269FFD004C7B80 /* Products */, 51 | ); 52 | sourceTree = ""; 53 | }; 54 | BE6AFF3B1E269FFD004C7B80 /* Products */ = { 55 | isa = PBXGroup; 56 | children = ( 57 | BE6AFF3A1E269FFD004C7B80 /* AccordionExample.app */, 58 | ); 59 | name = Products; 60 | sourceTree = ""; 61 | }; 62 | BE6AFF3C1E269FFD004C7B80 /* AccordionExample */ = { 63 | isa = PBXGroup; 64 | children = ( 65 | BE6AFF4F1E26A04B004C7B80 /* Classes */, 66 | BE6AFF3D1E269FFD004C7B80 /* AppDelegate.swift */, 67 | BE6AFF3F1E269FFD004C7B80 /* ViewController.swift */, 68 | BE6AFF561E26A943004C7B80 /* SectionFactory.swift */, 69 | BE6AFF541E26A911004C7B80 /* SectionViewController.swift */, 70 | BE6AFF411E269FFD004C7B80 /* Main.storyboard */, 71 | BE6AFF441E269FFD004C7B80 /* Assets.xcassets */, 72 | BE6AFF461E269FFD004C7B80 /* LaunchScreen.storyboard */, 73 | BE6AFF491E269FFD004C7B80 /* Info.plist */, 74 | ); 75 | path = AccordionExample; 76 | sourceTree = ""; 77 | }; 78 | BE6AFF4F1E26A04B004C7B80 /* Classes */ = { 79 | isa = PBXGroup; 80 | children = ( 81 | BE6AFF501E26A04B004C7B80 /* AccordionTableViewController.swift */, 82 | BE6AFF511E26A04B004C7B80 /* SectionHeaderView.xib */, 83 | ); 84 | name = Classes; 85 | path = ../../Classes; 86 | sourceTree = ""; 87 | }; 88 | /* End PBXGroup section */ 89 | 90 | /* Begin PBXNativeTarget section */ 91 | BE6AFF391E269FFD004C7B80 /* AccordionExample */ = { 92 | isa = PBXNativeTarget; 93 | buildConfigurationList = BE6AFF4C1E269FFD004C7B80 /* Build configuration list for PBXNativeTarget "AccordionExample" */; 94 | buildPhases = ( 95 | BE6AFF361E269FFD004C7B80 /* Sources */, 96 | BE6AFF371E269FFD004C7B80 /* Frameworks */, 97 | BE6AFF381E269FFD004C7B80 /* Resources */, 98 | ); 99 | buildRules = ( 100 | ); 101 | dependencies = ( 102 | ); 103 | name = AccordionExample; 104 | productName = AccordionExample; 105 | productReference = BE6AFF3A1E269FFD004C7B80 /* AccordionExample.app */; 106 | productType = "com.apple.product-type.application"; 107 | }; 108 | /* End PBXNativeTarget section */ 109 | 110 | /* Begin PBXProject section */ 111 | BE6AFF321E269FFD004C7B80 /* Project object */ = { 112 | isa = PBXProject; 113 | attributes = { 114 | LastSwiftUpdateCheck = 0820; 115 | LastUpgradeCheck = 0820; 116 | ORGANIZATIONNAME = worQ; 117 | TargetAttributes = { 118 | BE6AFF391E269FFD004C7B80 = { 119 | CreatedOnToolsVersion = 8.2.1; 120 | DevelopmentTeam = N88S4A5QL4; 121 | ProvisioningStyle = Automatic; 122 | }; 123 | }; 124 | }; 125 | buildConfigurationList = BE6AFF351E269FFD004C7B80 /* Build configuration list for PBXProject "AccordionExample" */; 126 | compatibilityVersion = "Xcode 3.2"; 127 | developmentRegion = English; 128 | hasScannedForEncodings = 0; 129 | knownRegions = ( 130 | en, 131 | Base, 132 | ); 133 | mainGroup = BE6AFF311E269FFD004C7B80; 134 | productRefGroup = BE6AFF3B1E269FFD004C7B80 /* Products */; 135 | projectDirPath = ""; 136 | projectRoot = ""; 137 | targets = ( 138 | BE6AFF391E269FFD004C7B80 /* AccordionExample */, 139 | ); 140 | }; 141 | /* End PBXProject section */ 142 | 143 | /* Begin PBXResourcesBuildPhase section */ 144 | BE6AFF381E269FFD004C7B80 /* Resources */ = { 145 | isa = PBXResourcesBuildPhase; 146 | buildActionMask = 2147483647; 147 | files = ( 148 | BE6AFF481E269FFD004C7B80 /* LaunchScreen.storyboard in Resources */, 149 | BE6AFF451E269FFD004C7B80 /* Assets.xcassets in Resources */, 150 | BE6AFF431E269FFD004C7B80 /* Main.storyboard in Resources */, 151 | BE6AFF531E26A04B004C7B80 /* SectionHeaderView.xib in Resources */, 152 | ); 153 | runOnlyForDeploymentPostprocessing = 0; 154 | }; 155 | /* End PBXResourcesBuildPhase section */ 156 | 157 | /* Begin PBXSourcesBuildPhase section */ 158 | BE6AFF361E269FFD004C7B80 /* Sources */ = { 159 | isa = PBXSourcesBuildPhase; 160 | buildActionMask = 2147483647; 161 | files = ( 162 | BE6AFF401E269FFD004C7B80 /* ViewController.swift in Sources */, 163 | BE6AFF521E26A04B004C7B80 /* AccordionTableViewController.swift in Sources */, 164 | BE6AFF551E26A911004C7B80 /* SectionViewController.swift in Sources */, 165 | BE6AFF3E1E269FFD004C7B80 /* AppDelegate.swift in Sources */, 166 | BE6AFF571E26A943004C7B80 /* SectionFactory.swift in Sources */, 167 | ); 168 | runOnlyForDeploymentPostprocessing = 0; 169 | }; 170 | /* End PBXSourcesBuildPhase section */ 171 | 172 | /* Begin PBXVariantGroup section */ 173 | BE6AFF411E269FFD004C7B80 /* Main.storyboard */ = { 174 | isa = PBXVariantGroup; 175 | children = ( 176 | BE6AFF421E269FFD004C7B80 /* Base */, 177 | ); 178 | name = Main.storyboard; 179 | sourceTree = ""; 180 | }; 181 | BE6AFF461E269FFD004C7B80 /* LaunchScreen.storyboard */ = { 182 | isa = PBXVariantGroup; 183 | children = ( 184 | BE6AFF471E269FFD004C7B80 /* Base */, 185 | ); 186 | name = LaunchScreen.storyboard; 187 | sourceTree = ""; 188 | }; 189 | /* End PBXVariantGroup section */ 190 | 191 | /* Begin XCBuildConfiguration section */ 192 | BE6AFF4A1E269FFD004C7B80 /* Debug */ = { 193 | isa = XCBuildConfiguration; 194 | buildSettings = { 195 | ALWAYS_SEARCH_USER_PATHS = NO; 196 | CLANG_ANALYZER_NONNULL = YES; 197 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 198 | CLANG_CXX_LIBRARY = "libc++"; 199 | CLANG_ENABLE_MODULES = YES; 200 | CLANG_ENABLE_OBJC_ARC = YES; 201 | CLANG_WARN_BOOL_CONVERSION = YES; 202 | CLANG_WARN_CONSTANT_CONVERSION = YES; 203 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 204 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 205 | CLANG_WARN_EMPTY_BODY = YES; 206 | CLANG_WARN_ENUM_CONVERSION = YES; 207 | CLANG_WARN_INFINITE_RECURSION = YES; 208 | CLANG_WARN_INT_CONVERSION = YES; 209 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 210 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 211 | CLANG_WARN_UNREACHABLE_CODE = YES; 212 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 213 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 214 | COPY_PHASE_STRIP = NO; 215 | DEBUG_INFORMATION_FORMAT = dwarf; 216 | ENABLE_STRICT_OBJC_MSGSEND = YES; 217 | ENABLE_TESTABILITY = YES; 218 | GCC_C_LANGUAGE_STANDARD = gnu99; 219 | GCC_DYNAMIC_NO_PIC = NO; 220 | GCC_NO_COMMON_BLOCKS = YES; 221 | GCC_OPTIMIZATION_LEVEL = 0; 222 | GCC_PREPROCESSOR_DEFINITIONS = ( 223 | "DEBUG=1", 224 | "$(inherited)", 225 | ); 226 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 227 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 228 | GCC_WARN_UNDECLARED_SELECTOR = YES; 229 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 230 | GCC_WARN_UNUSED_FUNCTION = YES; 231 | GCC_WARN_UNUSED_VARIABLE = YES; 232 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 233 | MTL_ENABLE_DEBUG_INFO = YES; 234 | ONLY_ACTIVE_ARCH = YES; 235 | SDKROOT = iphoneos; 236 | SWIFT_ACTIVE_COMPILATION_CONDITIONS = DEBUG; 237 | SWIFT_OPTIMIZATION_LEVEL = "-Onone"; 238 | }; 239 | name = Debug; 240 | }; 241 | BE6AFF4B1E269FFD004C7B80 /* Release */ = { 242 | isa = XCBuildConfiguration; 243 | buildSettings = { 244 | ALWAYS_SEARCH_USER_PATHS = NO; 245 | CLANG_ANALYZER_NONNULL = YES; 246 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 247 | CLANG_CXX_LIBRARY = "libc++"; 248 | CLANG_ENABLE_MODULES = YES; 249 | CLANG_ENABLE_OBJC_ARC = YES; 250 | CLANG_WARN_BOOL_CONVERSION = YES; 251 | CLANG_WARN_CONSTANT_CONVERSION = YES; 252 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 253 | CLANG_WARN_DOCUMENTATION_COMMENTS = YES; 254 | CLANG_WARN_EMPTY_BODY = YES; 255 | CLANG_WARN_ENUM_CONVERSION = YES; 256 | CLANG_WARN_INFINITE_RECURSION = YES; 257 | CLANG_WARN_INT_CONVERSION = YES; 258 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 259 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 260 | CLANG_WARN_UNREACHABLE_CODE = YES; 261 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 262 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 263 | COPY_PHASE_STRIP = NO; 264 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 265 | ENABLE_NS_ASSERTIONS = NO; 266 | ENABLE_STRICT_OBJC_MSGSEND = YES; 267 | GCC_C_LANGUAGE_STANDARD = gnu99; 268 | GCC_NO_COMMON_BLOCKS = YES; 269 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 270 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 271 | GCC_WARN_UNDECLARED_SELECTOR = YES; 272 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 273 | GCC_WARN_UNUSED_FUNCTION = YES; 274 | GCC_WARN_UNUSED_VARIABLE = YES; 275 | IPHONEOS_DEPLOYMENT_TARGET = 10.2; 276 | MTL_ENABLE_DEBUG_INFO = NO; 277 | SDKROOT = iphoneos; 278 | SWIFT_OPTIMIZATION_LEVEL = "-Owholemodule"; 279 | VALIDATE_PRODUCT = YES; 280 | }; 281 | name = Release; 282 | }; 283 | BE6AFF4D1E269FFD004C7B80 /* Debug */ = { 284 | isa = XCBuildConfiguration; 285 | buildSettings = { 286 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 287 | DEVELOPMENT_TEAM = N88S4A5QL4; 288 | INFOPLIST_FILE = AccordionExample/Info.plist; 289 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 290 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 291 | PRODUCT_BUNDLE_IDENTIFIER = com.worq.AccordionExample; 292 | PRODUCT_NAME = "$(TARGET_NAME)"; 293 | SWIFT_VERSION = 3.0; 294 | }; 295 | name = Debug; 296 | }; 297 | BE6AFF4E1E269FFD004C7B80 /* Release */ = { 298 | isa = XCBuildConfiguration; 299 | buildSettings = { 300 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 301 | DEVELOPMENT_TEAM = N88S4A5QL4; 302 | INFOPLIST_FILE = AccordionExample/Info.plist; 303 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 304 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 305 | PRODUCT_BUNDLE_IDENTIFIER = com.worq.AccordionExample; 306 | PRODUCT_NAME = "$(TARGET_NAME)"; 307 | SWIFT_VERSION = 3.0; 308 | }; 309 | name = Release; 310 | }; 311 | /* End XCBuildConfiguration section */ 312 | 313 | /* Begin XCConfigurationList section */ 314 | BE6AFF351E269FFD004C7B80 /* Build configuration list for PBXProject "AccordionExample" */ = { 315 | isa = XCConfigurationList; 316 | buildConfigurations = ( 317 | BE6AFF4A1E269FFD004C7B80 /* Debug */, 318 | BE6AFF4B1E269FFD004C7B80 /* Release */, 319 | ); 320 | defaultConfigurationIsVisible = 0; 321 | defaultConfigurationName = Release; 322 | }; 323 | BE6AFF4C1E269FFD004C7B80 /* Build configuration list for PBXNativeTarget "AccordionExample" */ = { 324 | isa = XCConfigurationList; 325 | buildConfigurations = ( 326 | BE6AFF4D1E269FFD004C7B80 /* Debug */, 327 | BE6AFF4E1E269FFD004C7B80 /* Release */, 328 | ); 329 | defaultConfigurationIsVisible = 0; 330 | defaultConfigurationName = Release; 331 | }; 332 | /* End XCConfigurationList section */ 333 | }; 334 | rootObject = BE6AFF321E269FFD004C7B80 /* Project object */; 335 | } 336 | -------------------------------------------------------------------------------- /Demo/AccordionExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/AccordionExample/AppDelegate.swift: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.swift 3 | // AccordionExample 4 | // 5 | // Created by Klevison Matias on 1/11/17. 6 | // Copyright © 2017 worQ. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | @UIApplicationMain 12 | class AppDelegate: UIResponder, UIApplicationDelegate { 13 | 14 | var window: UIWindow? 15 | 16 | 17 | func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplicationLaunchOptionsKey: Any]?) -> Bool { 18 | // Override point for customization after application launch. 19 | return true 20 | } 21 | 22 | func applicationWillResignActive(_ application: UIApplication) { 23 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 24 | // Use this method to pause ongoing tasks, disable timers, and invalidate graphics rendering callbacks. Games should use this method to pause the game. 25 | } 26 | 27 | func applicationDidEnterBackground(_ application: UIApplication) { 28 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 29 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 30 | } 31 | 32 | func applicationWillEnterForeground(_ application: UIApplication) { 33 | // Called as part of the transition from the background to the active state; here you can undo many of the changes made on entering the background. 34 | } 35 | 36 | func applicationDidBecomeActive(_ application: UIApplication) { 37 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 38 | } 39 | 40 | func applicationWillTerminate(_ application: UIApplication) { 41 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 42 | } 43 | 44 | 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "20x20", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "20x20", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "29x29", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "29x29", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "40x40", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "40x40", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "iphone", 35 | "size" : "60x60", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "iphone", 40 | "size" : "60x60", 41 | "scale" : "3x" 42 | } 43 | ], 44 | "info" : { 45 | "version" : 1, 46 | "author" : "xcode" 47 | } 48 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "info" : { 3 | "version" : 1, 4 | "author" : "xcode" 5 | } 6 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/carat-open.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Sort Down Filled-30-2.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/carat-open.imageset/Sort Down Filled-30-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klevison/AccordionTableViewController/78de224b3105fdab5203f74c43e73b329025c8a0/Demo/AccordionExample/Assets.xcassets/carat-open.imageset/Sort Down Filled-30-2.png -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/carat.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "scale" : "1x" 6 | }, 7 | { 8 | "idiom" : "universal", 9 | "filename" : "Sort Right Filled-30-2.png", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/carat.imageset/Sort Right Filled-30-2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klevison/AccordionTableViewController/78de224b3105fdab5203f74c43e73b329025c8a0/Demo/AccordionExample/Assets.xcassets/carat.imageset/Sort Right Filled-30-2.png -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/facebook.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "facebook.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/facebook.imageset/facebook.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klevison/AccordionTableViewController/78de224b3105fdab5203f74c43e73b329025c8a0/Demo/AccordionExample/Assets.xcassets/facebook.imageset/facebook.png -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/linkedin.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "linkedin.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/linkedin.imageset/linkedin.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klevison/AccordionTableViewController/78de224b3105fdab5203f74c43e73b329025c8a0/Demo/AccordionExample/Assets.xcassets/linkedin.imageset/linkedin.png -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/twitter.imageset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "universal", 5 | "filename" : "twitter.png", 6 | "scale" : "1x" 7 | }, 8 | { 9 | "idiom" : "universal", 10 | "scale" : "2x" 11 | }, 12 | { 13 | "idiom" : "universal", 14 | "scale" : "3x" 15 | } 16 | ], 17 | "info" : { 18 | "version" : 1, 19 | "author" : "xcode" 20 | } 21 | } -------------------------------------------------------------------------------- /Demo/AccordionExample/Assets.xcassets/twitter.imageset/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klevison/AccordionTableViewController/78de224b3105fdab5203f74c43e73b329025c8a0/Demo/AccordionExample/Assets.xcassets/twitter.imageset/twitter.png -------------------------------------------------------------------------------- /Demo/AccordionExample/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /Demo/AccordionExample/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Demo/AccordionExample/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleVersion 20 | 1 21 | LSRequiresIPhoneOS 22 | 23 | UILaunchStoryboardName 24 | LaunchScreen 25 | UIMainStoryboardFile 26 | Main 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | 38 | 39 | -------------------------------------------------------------------------------- /Demo/AccordionExample/SectionFactory.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionFactory.swift 3 | // AccordionExample 4 | // 5 | // Created by Klevison Matias on 1/11/17. 6 | // Copyright © 2017 worQ. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | extension Section { 12 | 13 | static func sectionOne(view: UIView) -> Section { 14 | let viewOfSection = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 300)) 15 | viewOfSection.backgroundColor = UIColor.blue 16 | let section = Section() 17 | section.view = viewOfSection 18 | section.title = "Facebook" 19 | // individual background color for a specific section, overrides the general color if set 20 | section.backgroundColor = UIColor.red 21 | section.appearance.headerHeight = 100 22 | 23 | let overlayViewSection = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 49)) 24 | overlayViewSection.backgroundColor = UIColor.white 25 | //overlayViewSection.image = UIImage(named: "facebook") 26 | overlayViewSection.contentMode = .center 27 | overlayViewSection.backgroundColor = UIColor.clear 28 | section.overlayView = overlayViewSection 29 | 30 | let button = UIButton(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 50)) 31 | button.setTitle("I can be any kind of UIView", for: .normal) 32 | viewOfSection.addSubview(button) 33 | 34 | return section 35 | } 36 | 37 | static func sectionTwo(view: UIView) -> Section { 38 | let viewOfSection = UIView(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 300)) 39 | viewOfSection.backgroundColor = UIColor.red 40 | let section = Section() 41 | section.view = viewOfSection 42 | section.title = "Twitter" 43 | // individual background color for a specific section, overrides the general color if set 44 | section.backgroundColor = UIColor.blue 45 | 46 | let overlayViewSection = UIImageView(frame: CGRect(x: 0, y: 0, width: 50, height: 49)) 47 | overlayViewSection.backgroundColor = UIColor.white 48 | overlayViewSection.image = UIImage(named: "twitter") 49 | overlayViewSection.contentMode = .center 50 | overlayViewSection.backgroundColor = UIColor.clear 51 | section.overlayView = overlayViewSection 52 | 53 | let button = UIButton(frame: CGRect(x: 0, y: 0, width: view.frame.size.width, height: 50)) 54 | button.setTitle("I'm another UIView", for: .normal) 55 | viewOfSection.addSubview(button) 56 | 57 | return section 58 | } 59 | 60 | static func sectionThree(vc viewController: UIViewController) -> Section { 61 | let storyboard = UIStoryboard(name: "Main", bundle: nil) 62 | let sectionViewController = storyboard.instantiateViewController(withIdentifier: "SectionViewController") as UIViewController 63 | viewController.addChildViewController(sectionViewController) 64 | 65 | let section = Section() 66 | section.view = sectionViewController.view 67 | section.title = "ViewController" 68 | // individual background color for a specific section, overrides the general color if set 69 | section.backgroundColor = UIColor.orange 70 | 71 | return section 72 | } 73 | 74 | } 75 | -------------------------------------------------------------------------------- /Demo/AccordionExample/SectionViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // SectionViewController.swift 3 | // AccordionExample 4 | // 5 | // Created by Klevison Matias on 1/11/17. 6 | // Copyright © 2017 worQ. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | protocol SectionViewControllerDelegate: class { 12 | func sectionViewControllerDidLayoutSubViews(size: CGSize) 13 | } 14 | 15 | final class SectionViewController: UIViewController { 16 | 17 | weak var delegate: SectionViewControllerDelegate? 18 | 19 | override func viewDidLayoutSubviews() { 20 | super.viewDidLayoutSubviews() 21 | delegate?.sectionViewControllerDidLayoutSubViews(size: view.bounds.size) 22 | } 23 | } 24 | 25 | -------------------------------------------------------------------------------- /Demo/AccordionExample/ViewController.swift: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.swift 3 | // AccordionTableViewController 4 | // 5 | // Created by Klevison Matias on 1/11/17. 6 | // Copyright © 2017 worQ. All rights reserved. 7 | // 8 | 9 | import UIKit 10 | 11 | class ViewController: AccordionTableViewController, SectionViewControllerDelegate, AccordionTableViewControllerDelegate { 12 | 13 | override func viewDidLoad() { 14 | super.viewDidLoad() 15 | 16 | oneSectionAlwaysOpen = false 17 | sections = allSetions() 18 | delegate = self 19 | openAnimation = .fade 20 | closeAnimation = .fade 21 | } 22 | 23 | private func allSetions() -> [Section] { 24 | return [Section.sectionOne(view: view), Section.sectionTwo(view: view), Section.sectionThree(vc: self)] 25 | } 26 | 27 | func sectionViewControllerDidLayoutSubViews(size: CGSize) { 28 | let section = self.sections[2] 29 | section.view!.frame = CGRect(x: 0, y: 0, width: size.width, height: size.height) 30 | 31 | if openedSection?.sectionIndex == 2 { 32 | self.reloadOpenedSection() 33 | } 34 | } 35 | 36 | func accordionTableViewControllerSectionDidClose(section: Section) { 37 | print(#function) 38 | } 39 | 40 | func accordionTableViewControllerSectionDidOpen(section: Section) { 41 | print(#function) 42 | } 43 | 44 | } 45 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Klevison Matias 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # AccordionTableViewController 2 | 3 | Swift version of https://github.com/klevison/KMAccordionTableViewController 4 | 5 |

6 | ... 7 |

8 | 9 | ## Current Version 10 | 11 | Version: 0.0.3 12 | 13 | ## Under the Hood 14 | 15 | * Supports UIViews as sections (UIViews, UIViewController's view, UITableViews, UIWebView, MKMapView, etc...) 16 | * Update content and size of a section 17 | * Custom animation, headers, sizes, etc... 18 | * Xcode 8 19 | * Swift 3 20 | 21 | ## How to install it? 22 | 23 | [CocoaPods](http://cocoapods.org) is the easiest way to install AccordionTableViewController. Run ```pod search AccordionTableViewController``` to search for the latest version. Then, copy and paste the ```pod``` line to your ```Podfile```. Your podfile should look like: 24 | 25 | ``` 26 | platform :ios, '8.0' 27 | pod 'AccordionTableViewController' 28 | ``` 29 | 30 | Finally, install it by running ```pod install```. 31 | 32 | If you don't use CocoaPods, import the all files from "Classes" directory to your project. 33 | 34 | ## How to use it? 35 | 36 | ### Extends from AccordionTableViewController 37 | 38 | ```swift 39 | import UIKit 40 | 41 | class ViewController: AccordionTableViewController { 42 | 43 | } 44 | ``` 45 | 46 | ### Set `sections` and `delegate` variables 47 | 48 | ```swift 49 | override func viewDidLoad() { 50 | super.viewDidLoad() 51 | 52 | let viewOfSection = UIView(frame: CGRectMake(0, 0, view.frame.size.width, 300)) 53 | viewOfSection.backgroundColor = UIColor.blueColor() 54 | let section = Section() 55 | section.view = viewOfSection 56 | section.title = "Section" 57 | 58 | oneSectionAlwaysOpen = true 59 | sections = [section] //how many sections you want 60 | delegate = self 61 | } 62 | ``` 63 | 64 | ### Customization 65 | 66 | Each section has an `appearence` var and it can be customized 67 | 68 | ```swift 69 | var open = false 70 | var view: UIView? 71 | var overlayView: UIView? 72 | var headerView: SectionHeaderView? 73 | var title: String? 74 | var backgroundColor: UIColor? 75 | var sectionIndex: Int? 76 | var appearence = Appearence() 77 | ``` 78 | 79 | ## Contact 80 | 81 | If you have any questions comments or suggestions, send me a message. If you find a bug, or want to submit a pull request, let me know. 82 | 83 | * klevison@gmail.com 84 | * http://twitter.com/klevison 85 | 86 | ## Copyright and license 87 | 88 | Copyright (c) 2015 Klevison Matias (http://twitter.com/klevison). Code released under [the MIT license](LICENSE). 89 | -------------------------------------------------------------------------------- /demo.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/klevison/AccordionTableViewController/78de224b3105fdab5203f74c43e73b329025c8a0/demo.gif --------------------------------------------------------------------------------