├── .travis.yml ├── .DS_Store ├── Screenshots ├── Screenshots1.png ├── Screenshots2.png ├── Screenshots3.png └── Screenshots4.png ├── FTFoldingTableView ├── Arrowhead.png ├── FTFoldingTableView.h └── FTFoldingTableView.m ├── Demo ├── FTFoldingTableView.xcodeproj │ ├── project.xcworkspace │ │ ├── contents.xcworkspacedata │ │ └── xcshareddata │ │ │ └── IDEWorkspaceChecks.plist │ └── project.pbxproj ├── FTFoldingTableView │ ├── ViewController.h │ ├── AppDelegate.h │ ├── main.m │ ├── Assets.xcassets │ │ └── AppIcon.appiconset │ │ │ └── Contents.json │ ├── Info.plist │ ├── Base.lproj │ │ └── LaunchScreen.storyboard │ ├── AppDelegate.m │ ├── ViewController.m │ └── Main.storyboard └── FTFoldingTableViewUITests │ ├── Info.plist │ └── FTFoldingTableViewUITests.m ├── ChangeLog.md ├── LICENSE ├── FTFoldingTableView.podspec ├── .gitignore └── README.md /.travis.yml: -------------------------------------------------------------------------------- 1 | language: objective-c 2 | -------------------------------------------------------------------------------- /.DS_Store: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liufengting/FTFoldingTableView/HEAD/.DS_Store -------------------------------------------------------------------------------- /Screenshots/Screenshots1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liufengting/FTFoldingTableView/HEAD/Screenshots/Screenshots1.png -------------------------------------------------------------------------------- /Screenshots/Screenshots2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liufengting/FTFoldingTableView/HEAD/Screenshots/Screenshots2.png -------------------------------------------------------------------------------- /Screenshots/Screenshots3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liufengting/FTFoldingTableView/HEAD/Screenshots/Screenshots3.png -------------------------------------------------------------------------------- /Screenshots/Screenshots4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liufengting/FTFoldingTableView/HEAD/Screenshots/Screenshots4.png -------------------------------------------------------------------------------- /FTFoldingTableView/Arrowhead.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/liufengting/FTFoldingTableView/HEAD/FTFoldingTableView/Arrowhead.png -------------------------------------------------------------------------------- /Demo/FTFoldingTableView.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | @end 14 | 15 | -------------------------------------------------------------------------------- /ChangeLog.md: -------------------------------------------------------------------------------- 1 | # FTFoldingTableView ChangeLog 2 | 3 | * 1.0.0 (2016.06.28) upload to Cocoapods 4 | * 1.0.5 (2016.08.01) supports portrait and landscrape 5 | * 1.0.6 (2017.02.03) add will fold/open delegate 6 | * 1.0.8 (2018.01.11) add didDeselectRowAtIndexPath delegate 7 | * 1.0.9 (2018.01.15) add delegate methods and public methods 8 | * 1.1.0 (2019.03.09) just made some small changes 9 | 10 | 11 | 12 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | } 33 | ], 34 | "info" : { 35 | "version" : 1, 36 | "author" : "xcode" 37 | } 38 | } -------------------------------------------------------------------------------- /Demo/FTFoldingTableViewUITests/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 | BNDL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | 24 | 25 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2016 刘锋婷 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. 22 | -------------------------------------------------------------------------------- /FTFoldingTableView.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |s| 2 | 3 | s.name = "FTFoldingTableView" 4 | s.version = "1.1.0" 5 | s.summary = "Folding cells with simple delegates, and change UI looks in a few lines of code." 6 | s.description = <<-DESC 7 | FTFoldingTableView.Folding cells with simple delegates, and change UI looks in a few lines of code. I recently developed this for future use. 8 | DESC 9 | s.homepage = "https://github.com/liufengting/FTFoldingTableView" 10 | s.screenshots = "https://raw.githubusercontent.com/liufengting/FTFoldingTableView/master/Screenshots/Screenshots1.png","https://raw.githubusercontent.com/liufengting/FTFoldingTableView/master/Screenshots/Screenshots2.png","https://raw.githubusercontent.com/liufengting/FTFoldingTableView/master/Screenshots/Screenshots3.png","https://raw.githubusercontent.com/liufengting/FTFoldingTableView/master/Screenshots/Screenshots4.png" 11 | s.license = { :type => "MIT", :file => "LICENSE" } 12 | s.author = { "liufengting" => "wo157121900@me.com" } 13 | s.social_media_url = "https://twitter.com/liufengting" 14 | s.platform = :ios 15 | s.source = { :git => "https://github.com/liufengting/FTFoldingTableView.git", :tag => "#{s.version}" } 16 | s.source_files = "FTFoldingTableView/*.{h,m}" 17 | s.resources = "FTFoldingTableView/*.{png}" 18 | 19 | end -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/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 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | 40 | 41 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableViewUITests/FTFoldingTableViewUITests.m: -------------------------------------------------------------------------------- 1 | // 2 | // FTFoldingTableViewUITests.m 3 | // FTFoldingTableViewUITests 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface FTFoldingTableViewUITests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation FTFoldingTableViewUITests 16 | 17 | - (void)setUp { 18 | [super setUp]; 19 | 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | 22 | // In UI tests it is usually best to stop immediately when a failure occurs. 23 | self.continueAfterFailure = NO; 24 | // UI tests must launch the application that they test. Doing this in setup will make sure it happens for each test method. 25 | [[[XCUIApplication alloc] init] launch]; 26 | 27 | // In UI tests it’s important to set the initial state - such as interface orientation - required for your tests before they run. The setUp method is a good place to do this. 28 | } 29 | 30 | - (void)tearDown { 31 | // Put teardown code here. This method is called after the invocation of each test method in the class. 32 | [super tearDown]; 33 | } 34 | 35 | - (void)testExample { 36 | // Use recording to get started writing UI tests. 37 | // Use XCTAssert and related functions to verify your tests produce the correct results. 38 | } 39 | 40 | @end 41 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | .DS_Store 5 | ## Build generated 6 | build/ 7 | DerivedData/ 8 | 9 | ## Various settings 10 | *.pbxuser 11 | !default.pbxuser 12 | *.mode1v3 13 | !default.mode1v3 14 | *.mode2v3 15 | !default.mode2v3 16 | *.perspectivev3 17 | !default.perspectivev3 18 | xcuserdata/ 19 | 20 | ## Other 21 | *.moved-aside 22 | *.xcuserstate 23 | 24 | ## Obj-C/Swift specific 25 | *.hmap 26 | *.ipa 27 | *.dSYM.zip 28 | *.dSYM 29 | 30 | # CocoaPods 31 | # 32 | # We recommend against adding the Pods directory to your .gitignore. However 33 | # you should judge for yourself, the pros and cons are mentioned at: 34 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 35 | # 36 | # Pods/ 37 | 38 | # Carthage 39 | # 40 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 41 | # Carthage/Checkouts 42 | 43 | Carthage/Build 44 | 45 | # fastlane 46 | # 47 | # It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the 48 | # screenshots whenever they are needed. 49 | # For more information about the recommended setup visit: 50 | # https://github.com/fastlane/fastlane/blob/master/fastlane/docs/Gitignore.md 51 | 52 | fastlane/report.xml 53 | fastlane/screenshots 54 | 55 | #Code Injection 56 | # 57 | # After new code Injection tools there's a generated folder /iOSInjectionProject 58 | # https://github.com/johnno1962/injectionforxcode 59 | 60 | iOSInjectionProject/ 61 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/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/FTFoldingTableView/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // 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. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // 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. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // 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. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "FTFoldingTableView.h" 11 | 12 | static NSString * const SectionHeaderViewIdentifier = @"SectionHeaderViewIdentifier"; 13 | static NSString * const DemoTableViewIdentifier = @"DemoTableViewIdentifier"; 14 | 15 | @interface ViewController () 16 | 17 | @property (weak, nonatomic) IBOutlet FTFoldingTableView *ft_tableView; 18 | @property (nonatomic, assign) FTFoldingSectionHeaderArrowPosition arrowPosition; 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | self.automaticallyAdjustsScrollViewInsets = NO; 28 | 29 | self.arrowPosition = FTFoldingSectionHeaderArrowPositionLeft; 30 | 31 | self.ft_tableView.foldingDelegate = self; 32 | } 33 | 34 | - (IBAction)changeStyle:(UIBarButtonItem *)sender 35 | { 36 | self.arrowPosition = [NSNumber numberWithBool:(![NSNumber numberWithInteger:self.arrowPosition].boolValue)].integerValue; 37 | [self.ft_tableView reloadData]; 38 | 39 | 40 | // foldAllSections 41 | // [self.ft_tableView foldAllSections]; 42 | 43 | // expandAllSections 44 | // [self.ft_tableView expandAllSections]; 45 | 46 | // test one section 47 | // NSInteger section = 0; 48 | // FTFoldingSectionState state = [self.ft_tableView foldingStateForSection:section]; 49 | // if (state == FTFoldingSectionStateFold) { 50 | // [self.ft_tableView expandSection:section]; 51 | // }else{ 52 | // [self.ft_tableView foldSection:section]; 53 | // } 54 | } 55 | 56 | #pragma mark - FTFoldingTableViewDelegate / required 57 | 58 | - (FTFoldingSectionHeaderArrowPosition)perferedArrowPositionForFTFoldingTableView:(FTFoldingTableView *)ftTableView 59 | { 60 | return self.arrowPosition; 61 | } 62 | - (NSInteger)numberOfSectionForFTFoldingTableView:(FTFoldingTableView *)ftTableView 63 | { 64 | return 5; 65 | } 66 | - (NSInteger)ftFoldingTableView:(FTFoldingTableView *)ftTableView numberOfRowsInSection:(NSInteger)section 67 | { 68 | return 3; 69 | } 70 | - (CGFloat)ftFoldingTableView:(FTFoldingTableView *)ftTableView heightForHeaderInSection:(NSInteger)section 71 | { 72 | return 60.f; 73 | } 74 | - (CGFloat)ftFoldingTableView:(FTFoldingTableView *)ftTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 75 | { 76 | return 50.f; 77 | } 78 | - (NSString *)ftFoldingTableView:(FTFoldingTableView *)ftTableView titleForHeaderInSection:(NSInteger)section 79 | { 80 | return [NSString stringWithFormat:@"Section %ld",section]; 81 | } 82 | - (UITableViewCell *)ftFoldingTableView:(FTFoldingTableView *)ftTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 83 | { 84 | UITableViewCell *cell = [self.ft_tableView dequeueReusableCellWithIdentifier:DemoTableViewIdentifier forIndexPath:indexPath]; 85 | 86 | 87 | return cell; 88 | } 89 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 90 | { 91 | [ftTableView deselectRowAtIndexPath:indexPath animated:YES]; 92 | } 93 | 94 | #pragma mark - FTFoldingTableViewDelegate / optional delegates, change almost everything using delegate 95 | 96 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView willChangeToSectionState:(FTFoldingSectionState)sectionState section:(NSInteger)section 97 | { 98 | NSLog(@"section: %ld is about to %@", section, sectionState == FTFoldingSectionStateFold ? @"close" : @"open"); 99 | } 100 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView didChangeToSectionState:(FTFoldingSectionState)sectionState section:(NSInteger)section 101 | { 102 | NSLog(@"section: %ld is now %@", section, sectionState == FTFoldingSectionStateFold ? @"closed" : @"opened"); 103 | } 104 | 105 | - (NSString *)ftFoldingTableView:(FTFoldingTableView *)ftTableView descriptionForHeaderInSection:(NSInteger)section 106 | { 107 | return @"description"; 108 | } 109 | 110 | //- (UIImage *)ftFoldingTableView:(FTFoldingTableView *)ftTableView arrowImageForSection:(NSInteger)section 111 | //{ 112 | // return [UIImage imageNamed:@"Arrowhead"]; 113 | //} 114 | //- (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView backgroundColorForHeaderInSection:(NSInteger)section 115 | //{ 116 | // return [UIColor grayColor]; 117 | //} 118 | //- (UIFont *)ftFoldingTableView:(FTFoldingTableView *)ftTableView fontForTitleInSection:(NSInteger)section 119 | //{ 120 | // return [UIFont boldSystemFontOfSize:16]; 121 | //} 122 | //- (UIFont *)ftFoldingTableView:(FTFoldingTableView *)ftTableView fontForDescriptionInSection:(NSInteger)section 123 | //{ 124 | // return [UIFont systemFontOfSize:13]; 125 | //} 126 | //- (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView textColorForTitleInSection:(NSInteger)section 127 | //{ 128 | // return [UIColor whiteColor]; 129 | //} 130 | //- (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView textColorForDescriptionInSection:(NSInteger)section 131 | //{ 132 | // return [UIColor whiteColor]; 133 | //} 134 | 135 | @end 136 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # FTFoldingTableView 2 | 3 | [![Twitter](https://img.shields.io/badge/twitter-@liufengting-blue.svg?style=flat)](http://twitter.com/liufengting) 4 | [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/liufengting/FTFoldingTableView/master/LICENSE) 5 | [![Version](https://img.shields.io/cocoapods/v/FTFoldingTableView.svg?style=flat)](http://cocoapods.org/pods/FTFoldingTableView) 6 | [![Platform](https://img.shields.io/cocoapods/p/FTFoldingTableView.svg?style=flat)](http://cocoapods.org/pods/FTFoldingTableView) 7 | [![CocoaPods](https://img.shields.io/cocoapods/dt/FTFoldingTableView.svg?maxAge=2592000)](http://cocoapods.org/pods/FTFoldingTableView) 8 | [![CI Status](http://img.shields.io/travis/liufengting/FTFoldingTableView.svg?style=flat)](https://travis-ci.org/liufengting/FTFoldingTableView) 9 | [![GitHub stars](https://img.shields.io/github/stars/liufengting/FTFoldingTableView.svg)](https://github.com/liufengting/FTFoldingTableView/stargazers) 10 | 11 | FTFoldingTableView. Folding cells with simple delegates, and change UI looks in a few lines of code. 12 | 13 | 14 | # ScreenShots 15 | 16 | | Style | Left | Right | 17 | |:-------------|:-------------:|:-------------:| 18 | | fold | | | 19 | | show | | | 20 | 21 | # Usage 22 | 23 | ## Required Methods 24 | 25 | * preferred ArrowPosition 26 | 27 | ```objective-c 28 | - (FTFoldingSectionHeaderArrowPosition)perferedArrowPositionForFTFoldingTableView:(FTFoldingTableView *)ftTableView 29 | { 30 | return self.arrowPosition; 31 | } 32 | ``` 33 | * numberOfSectionForFTFoldingTableView 34 | 35 | ```objective-c 36 | - (NSInteger )numberOfSectionForFTFoldingTableView:(FTFoldingTableView *)ftTableView 37 | { 38 | return 5; 39 | } 40 | 41 | ``` 42 | * numberOfRowsInSection 43 | 44 | ```objective-c 45 | - (NSInteger )ftFoldingTableView:(FTFoldingTableView *)ftTableView numberOfRowsInSection:(NSInteger )section 46 | { 47 | return 3; 48 | } 49 | ``` 50 | * heightForHeaderInSection 51 | 52 | ```objective-c 53 | - (CGFloat )ftFoldingTableView:(FTFoldingTableView *)ftTableView heightForHeaderInSection:(NSInteger )section 54 | { 55 | return 60; 56 | } 57 | ``` 58 | * heightForRowAtIndexPath 59 | 60 | ```objective-c 61 | - (CGFloat )ftFoldingTableView:(FTFoldingTableView *)ftTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 62 | { 63 | return 50; 64 | } 65 | ``` 66 | * titleForHeaderInSection 67 | 68 | ```objective-c 69 | - (NSString *)ftFoldingTableView:(FTFoldingTableView *)ftTableView titleForHeaderInSection:(NSInteger)section 70 | { 71 | return [NSString stringWithFormat:@"Section %ld",section]; 72 | } 73 | ``` 74 | * cellForRowAtIndexPath 75 | 76 | ```objective-c 77 | - (UITableViewCell *)ftFoldingTableView:(FTFoldingTableView *)ftTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 78 | { 79 | UITableViewCell *cell = [ft_tableView dequeueReusableCellWithIdentifier:DemoTableViewIdentifier forIndexPath:indexPath]; 80 | 81 | 82 | return cell; 83 | } 84 | ``` 85 | * didSelectRowAtIndexPath 86 | 87 | ```objective-c 88 | - (void )ftFoldingTableView:(FTFoldingTableView *)ftTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 89 | { 90 | [ftTableView deselectRowAtIndexPath:indexPath animated:YES]; 91 | 92 | 93 | } 94 | ``` 95 | ## Optional Methods 96 | 97 | * descriptionForHeaderInSection 98 | 99 | ```objective-c 100 | - (NSString *)ftFoldingTableView:(FTFoldingTableView *)ftTableView descriptionForHeaderInSection:(NSInteger )section 101 | { 102 | return @"description"; 103 | } 104 | ``` 105 | * arrowImageForSection 106 | 107 | ```objective-c 108 | - (UIImage *)ftFoldingTableView:(FTFoldingTableView *)ftTableView arrowImageForSection:(NSInteger )section 109 | { 110 | return [UIImage imageNamed:@"Arrowhead"]; 111 | } 112 | ``` 113 | * backgroundColorForHeaderInSection 114 | 115 | ```objective-c 116 | - (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView backgroundColorForHeaderInSection:(NSInteger )section 117 | { 118 | return [UIColor grayColor]; 119 | } 120 | ``` 121 | * fontForTitleInSection 122 | 123 | ```objective-c 124 | - (UIFont *)ftFoldingTableView:(FTFoldingTableView *)ftTableView fontForTitleInSection:(NSInteger )section 125 | { 126 | return [UIFont boldSystemFontOfSize:16]; 127 | } 128 | ``` 129 | * fontForDescriptionInSection 130 | 131 | ```objective-c 132 | - (UIFont *)ftFoldingTableView:(FTFoldingTableView *)ftTableView fontForDescriptionInSection:(NSInteger )section 133 | { 134 | return [UIFont systemFontOfSize:13]; 135 | } 136 | ``` 137 | * textColorForTitleInSection 138 | 139 | ```objective-c 140 | - (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView textColorForTitleInSection:(NSInteger )section 141 | { 142 | return [UIColor whiteColor]; 143 | } 144 | ``` 145 | * textColorForDescriptionInSection 146 | 147 | ```objective-c 148 | - (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView textColorForDescriptionInSection:(NSInteger )section 149 | { 150 | return [UIColor whiteColor]; 151 | } 152 | ``` 153 | 154 | # Installation 155 | 156 | ## Manually 157 | 158 | * clone this repo. 159 | * Simply drop the '/FTFoldingTableViewLib' folder into your project. 160 | * Enjoy! 161 | 162 | ## Cocoapods 163 | 164 | FTFoldingTableView is available through [CocoaPods](http://cocoapods.org). To install it, simply add the following line to your Podfile: 165 | 166 | ```ruby 167 | pod 'FTFoldingTableView' 168 | ``` 169 | 170 | 171 | 172 | # Need to know 173 | 174 | * I used two days to finish this project, and then uploaded it to Cocoapods, so I didn't have enough time to test it;if you have any questions, please let me know. I'll fill this README in the near future. 175 | 176 | 177 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView/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 | 42 | 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 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | -------------------------------------------------------------------------------- /FTFoldingTableView/FTFoldingTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // FTFoldingTableView.h 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #pragma mark - ENUM FTFoldingSectionState 12 | /** 13 | FTFoldingSectionState 14 | */ 15 | typedef NS_ENUM(NSUInteger, FTFoldingSectionState) { 16 | /** 17 | section state fold 18 | */ 19 | FTFoldingSectionStateFold, 20 | /** 21 | section state show 22 | */ 23 | FTFoldingSectionStateExpand, 24 | }; 25 | 26 | #pragma mark - ENUM FTFoldingSectionHeaderArrowPosition 27 | /** 28 | FTFoldingSectionHeaderArrowPosition 29 | */ 30 | typedef NS_ENUM(NSUInteger, FTFoldingSectionHeaderArrowPosition) { 31 | /** 32 | arrow position left 33 | */ 34 | FTFoldingSectionHeaderArrowPositionLeft, 35 | /** 36 | arrow position right 37 | */ 38 | FTFoldingSectionHeaderArrowPositionRight, 39 | }; 40 | 41 | 42 | #pragma mark - FTFoldingTableViewDelegate 43 | 44 | @class FTFoldingTableView; 45 | /** 46 | * FTFoldingTableViewDelegate 47 | */ 48 | @protocol FTFoldingTableViewDelegate 49 | 50 | @required 51 | /** 52 | perferedArrowPositionForFTFoldingTableView 53 | 54 | @param ftTableView FTFoldingTableView 55 | @return FTFoldingSectionHeaderArrowPosition 56 | */ 57 | - (FTFoldingSectionHeaderArrowPosition)perferedArrowPositionForFTFoldingTableView:(FTFoldingTableView *)ftTableView; 58 | /** 59 | numberOfSectionForFTFoldingTableView 60 | 61 | @param ftTableView FTFoldingTableView 62 | @return NSInteger 63 | */ 64 | - (NSInteger)numberOfSectionForFTFoldingTableView:(FTFoldingTableView *)ftTableView; 65 | /** 66 | numberOfRowsInSection 67 | 68 | @param ftTableView FTFoldingTableView 69 | @param section NSInteger 70 | @return NSInteger 71 | */ 72 | - (NSInteger)ftFoldingTableView:(FTFoldingTableView *)ftTableView numberOfRowsInSection:(NSInteger)section; 73 | /** 74 | heightForHeaderInSection 75 | 76 | @param ftTableView FTFoldingTableView 77 | @param section NSInteger 78 | @return CGFloat 79 | */ 80 | - (CGFloat)ftFoldingTableView:(FTFoldingTableView *)ftTableView heightForHeaderInSection:(NSInteger)section; 81 | /** 82 | heightForRowAtIndexPath 83 | 84 | @param ftTableView FTFoldingTableView 85 | @param indexPath NSIndexPath 86 | @return CGFloat 87 | */ 88 | - (CGFloat)ftFoldingTableView:(FTFoldingTableView *)ftTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; 89 | /** 90 | titleForHeaderInSection 91 | 92 | @param ftTableView FTFoldingTableView 93 | @param section NSInteger 94 | @return NSString 95 | */ 96 | - (NSString *)ftFoldingTableView:(FTFoldingTableView *)ftTableView titleForHeaderInSection:(NSInteger)section; 97 | /** 98 | cellForRowAtIndexPath 99 | 100 | @param ftTableView FTFoldingTableView 101 | @param indexPath NSIndexPath 102 | @return UITableViewCell 103 | */ 104 | - (UITableViewCell *)ftFoldingTableView:(FTFoldingTableView *)ftTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 105 | /** 106 | didSelectRowAtIndexPath 107 | 108 | @param ftTableView FTFoldingTableView 109 | @param indexPath NSIndexPath 110 | */ 111 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 112 | 113 | @optional 114 | 115 | /** 116 | didChangeSectionState 117 | 118 | @param ftTableView FTFoldingTableView 119 | @param sectionState FTFoldingSectionState 120 | @param section section 121 | */ 122 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView willChangeToSectionState:(FTFoldingSectionState)sectionState section:(NSInteger)section; 123 | /** 124 | didChangeToSectionState 125 | 126 | @param ftTableView FTFoldingTableView 127 | @param sectionState FTFoldingSectionState 128 | @param section section 129 | */ 130 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView didChangeToSectionState:(FTFoldingSectionState)sectionState section:(NSInteger)section; 131 | /** 132 | arrowImageForSection 133 | 134 | @param ftTableView FTFoldingTableView 135 | @param section NSInteger 136 | @return UIImage 137 | */ 138 | - (UIImage *)ftFoldingTableView:(FTFoldingTableView *)ftTableView arrowImageForSection:(NSInteger)section; 139 | /** 140 | descriptionForHeaderInSection 141 | 142 | @param ftTableView FTFoldingTableView 143 | @param section NSInteger 144 | @return NSString 145 | */ 146 | - (NSString *)ftFoldingTableView:(FTFoldingTableView *)ftTableView descriptionForHeaderInSection:(NSInteger)section; 147 | /** 148 | backgroundColorForHeaderInSection 149 | 150 | @param ftTableView FTFoldingTableView 151 | @param section NSInteger 152 | @return UIColor 153 | */ 154 | - (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView backgroundColorForHeaderInSection:(NSInteger)section; 155 | /** 156 | fontForTitleInSection 157 | 158 | @param ftTableView FTFoldingTableView 159 | @param section NSInteger 160 | @return UIFont 161 | */ 162 | - (UIFont *)ftFoldingTableView:(FTFoldingTableView *)ftTableView fontForTitleInSection:(NSInteger)section; 163 | /** 164 | fontForDescriptionInSection 165 | 166 | @param ftTableView FTFoldingTableView 167 | @param section NSInteger 168 | @return UIFont 169 | */ 170 | - (UIFont *)ftFoldingTableView:(FTFoldingTableView *)ftTableView fontForDescriptionInSection:(NSInteger)section; 171 | /** 172 | textColorForTitleInSection 173 | 174 | @param ftTableView FTFoldingTableView 175 | @param section NSInteger 176 | @return UIColor 177 | */ 178 | - (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView textColorForTitleInSection:(NSInteger)section; 179 | /** 180 | textColorForDescriptionInSection 181 | 182 | @param ftTableView FTFoldingTableView 183 | @param section NSInteger 184 | @return UIColor 185 | */ 186 | - (UIColor *)ftFoldingTableView:(FTFoldingTableView *)ftTableView textColorForDescriptionInSection:(NSInteger)section; 187 | /** 188 | didDeselectRowAtIndexPath 189 | 190 | @param ftTableView FTFoldingTableView 191 | @param indexPath NSIndexPath 192 | */ 193 | - (void)ftFoldingTableView:(FTFoldingTableView *)ftTableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath; 194 | 195 | @end 196 | 197 | #pragma mark - FTFoldingSectionHeaderDelegate 198 | /** 199 | FTFoldingSectionHeaderDelegate 200 | */ 201 | @protocol FTFoldingSectionHeaderDelegate 202 | /** 203 | ftFoldingSectionHeaderTappedAtIndex 204 | 205 | @param index NSInteger 206 | */ 207 | - (void)ftFoldingSectionHeaderTappedAtIndex:(NSInteger)index; 208 | 209 | @end 210 | 211 | #pragma mark - FTFoldingTableView 212 | /** 213 | FTFoldingTableView 214 | */ 215 | @interface FTFoldingTableView : UITableView 216 | /** 217 | FTFoldingTableViewDelegate foldingDelegate 218 | */ 219 | @property (nonatomic, weak) id foldingDelegate; 220 | 221 | /** 222 | foldingStateForSection 223 | 224 | @param section NSInteger 225 | @return FTFoldingSectionState 226 | */ 227 | - (FTFoldingSectionState)foldingStateForSection:(NSInteger)section; 228 | 229 | /** 230 | expandSection 231 | 232 | @param section NSInteger 233 | */ 234 | - (void)expandSection:(NSInteger)section; 235 | 236 | /** 237 | foldSection 238 | 239 | @param section NSInteger 240 | */ 241 | - (void)foldSection:(NSInteger)section; 242 | 243 | /** 244 | expandAllSections 245 | */ 246 | - (void)expandAllSections; 247 | 248 | /** 249 | foldAllSections 250 | */ 251 | - (void)foldAllSections; 252 | 253 | @end 254 | 255 | #pragma mark - FTFoldingSectionHeader 256 | 257 | /** 258 | FTFoldingSectionHeader 259 | */ 260 | @interface FTFoldingSectionHeader : UIView 261 | 262 | @property (nonatomic, weak) id tapDelegate; 263 | /** 264 | initWithFrame 265 | 266 | @param frame CGRect 267 | @param tag NSInteger 268 | @return instancetype 269 | */ 270 | - (instancetype)initWithFrame:(CGRect)frame withTag:(NSInteger)tag; 271 | /** 272 | setup 273 | 274 | @param backgroundColor UIColor 275 | @param titleString NSString 276 | @param titleColor UIColor 277 | @param titleFont UIFont 278 | @param descriptionString NSString 279 | @param descriptionColor UIColor 280 | @param descriptionFont UIFont 281 | @param arrowImage UIImage 282 | @param arrowPosition FTFoldingSectionHeaderArrowPosition 283 | @param sectionState FTFoldingSectionState 284 | */ 285 | - (void)setupWithBackgroundColor:(UIColor *)backgroundColor 286 | titleString:(NSString *)titleString 287 | titleColor:(UIColor *)titleColor 288 | titleFont:(UIFont *)titleFont 289 | descriptionString:(NSString *)descriptionString 290 | descriptionColor:(UIColor *)descriptionColor 291 | descriptionFont:(UIFont *)descriptionFont 292 | arrowImage:(UIImage *)arrowImage 293 | arrowPosition:(FTFoldingSectionHeaderArrowPosition)arrowPosition 294 | sectionState:(FTFoldingSectionState)sectionState; 295 | 296 | @end 297 | -------------------------------------------------------------------------------- /Demo/FTFoldingTableView.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | 2ABD2C521E44520F00EBB748 /* Arrowhead.png in Resources */ = {isa = PBXBuildFile; fileRef = 2ABD2C4F1E44520F00EBB748 /* Arrowhead.png */; }; 11 | 2ABD2C531E44520F00EBB748 /* FTFoldingTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = 2ABD2C511E44520F00EBB748 /* FTFoldingTableView.m */; }; 12 | 5A4B4FB41D4F3D3200134E33 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5A4B4FB31D4F3D3200134E33 /* Main.storyboard */; }; 13 | 5AB106C81D178925003E69E4 /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AB106C71D178925003E69E4 /* main.m */; }; 14 | 5AB106CB1D178925003E69E4 /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AB106CA1D178925003E69E4 /* AppDelegate.m */; }; 15 | 5AB106CE1D178925003E69E4 /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AB106CD1D178925003E69E4 /* ViewController.m */; }; 16 | 5AB106D31D178925003E69E4 /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 5AB106D21D178925003E69E4 /* Assets.xcassets */; }; 17 | 5AB106D61D178925003E69E4 /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 5AB106D41D178925003E69E4 /* LaunchScreen.storyboard */; }; 18 | 5AB106E11D178926003E69E4 /* FTFoldingTableViewUITests.m in Sources */ = {isa = PBXBuildFile; fileRef = 5AB106E01D178926003E69E4 /* FTFoldingTableViewUITests.m */; }; 19 | /* End PBXBuildFile section */ 20 | 21 | /* Begin PBXContainerItemProxy section */ 22 | 5AB106DD1D178926003E69E4 /* PBXContainerItemProxy */ = { 23 | isa = PBXContainerItemProxy; 24 | containerPortal = 5AB106BB1D178925003E69E4 /* Project object */; 25 | proxyType = 1; 26 | remoteGlobalIDString = 5AB106C21D178925003E69E4; 27 | remoteInfo = FTFoldingTableView; 28 | }; 29 | /* End PBXContainerItemProxy section */ 30 | 31 | /* Begin PBXFileReference section */ 32 | 2ABD2C4F1E44520F00EBB748 /* Arrowhead.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = Arrowhead.png; sourceTree = ""; }; 33 | 2ABD2C501E44520F00EBB748 /* FTFoldingTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = FTFoldingTableView.h; sourceTree = ""; }; 34 | 2ABD2C511E44520F00EBB748 /* FTFoldingTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = FTFoldingTableView.m; sourceTree = ""; }; 35 | 5A4B4FB31D4F3D3200134E33 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 36 | 5AB106C31D178925003E69E4 /* FTFoldingTableView.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = FTFoldingTableView.app; sourceTree = BUILT_PRODUCTS_DIR; }; 37 | 5AB106C71D178925003E69E4 /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 38 | 5AB106C91D178925003E69E4 /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 39 | 5AB106CA1D178925003E69E4 /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 40 | 5AB106CC1D178925003E69E4 /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 41 | 5AB106CD1D178925003E69E4 /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 42 | 5AB106D21D178925003E69E4 /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 43 | 5AB106D51D178925003E69E4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 44 | 5AB106D71D178925003E69E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 45 | 5AB106DC1D178926003E69E4 /* FTFoldingTableViewUITests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = FTFoldingTableViewUITests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 46 | 5AB106E01D178926003E69E4 /* FTFoldingTableViewUITests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = FTFoldingTableViewUITests.m; sourceTree = ""; }; 47 | 5AB106E21D178926003E69E4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 48 | /* End PBXFileReference section */ 49 | 50 | /* Begin PBXFrameworksBuildPhase section */ 51 | 5AB106C01D178925003E69E4 /* Frameworks */ = { 52 | isa = PBXFrameworksBuildPhase; 53 | buildActionMask = 2147483647; 54 | files = ( 55 | ); 56 | runOnlyForDeploymentPostprocessing = 0; 57 | }; 58 | 5AB106D91D178926003E69E4 /* Frameworks */ = { 59 | isa = PBXFrameworksBuildPhase; 60 | buildActionMask = 2147483647; 61 | files = ( 62 | ); 63 | runOnlyForDeploymentPostprocessing = 0; 64 | }; 65 | /* End PBXFrameworksBuildPhase section */ 66 | 67 | /* Begin PBXGroup section */ 68 | 2ABD2C4E1E44520F00EBB748 /* FTFoldingTableView */ = { 69 | isa = PBXGroup; 70 | children = ( 71 | 2ABD2C4F1E44520F00EBB748 /* Arrowhead.png */, 72 | 2ABD2C501E44520F00EBB748 /* FTFoldingTableView.h */, 73 | 2ABD2C511E44520F00EBB748 /* FTFoldingTableView.m */, 74 | ); 75 | name = FTFoldingTableView; 76 | path = ../../FTFoldingTableView; 77 | sourceTree = ""; 78 | }; 79 | 5AB106BA1D178925003E69E4 = { 80 | isa = PBXGroup; 81 | children = ( 82 | 5AB106C51D178925003E69E4 /* FTFoldingTableView */, 83 | 5AB106DF1D178926003E69E4 /* FTFoldingTableViewUITests */, 84 | 5AB106C41D178925003E69E4 /* Products */, 85 | ); 86 | sourceTree = ""; 87 | }; 88 | 5AB106C41D178925003E69E4 /* Products */ = { 89 | isa = PBXGroup; 90 | children = ( 91 | 5AB106C31D178925003E69E4 /* FTFoldingTableView.app */, 92 | 5AB106DC1D178926003E69E4 /* FTFoldingTableViewUITests.xctest */, 93 | ); 94 | name = Products; 95 | sourceTree = ""; 96 | }; 97 | 5AB106C51D178925003E69E4 /* FTFoldingTableView */ = { 98 | isa = PBXGroup; 99 | children = ( 100 | 2ABD2C4E1E44520F00EBB748 /* FTFoldingTableView */, 101 | 5AB106C91D178925003E69E4 /* AppDelegate.h */, 102 | 5AB106CA1D178925003E69E4 /* AppDelegate.m */, 103 | 5AB106CC1D178925003E69E4 /* ViewController.h */, 104 | 5AB106CD1D178925003E69E4 /* ViewController.m */, 105 | 5A4B4FB31D4F3D3200134E33 /* Main.storyboard */, 106 | 5AB106D21D178925003E69E4 /* Assets.xcassets */, 107 | 5AB106D41D178925003E69E4 /* LaunchScreen.storyboard */, 108 | 5AB106D71D178925003E69E4 /* Info.plist */, 109 | 5AB106C61D178925003E69E4 /* Supporting Files */, 110 | ); 111 | path = FTFoldingTableView; 112 | sourceTree = ""; 113 | }; 114 | 5AB106C61D178925003E69E4 /* Supporting Files */ = { 115 | isa = PBXGroup; 116 | children = ( 117 | 5AB106C71D178925003E69E4 /* main.m */, 118 | ); 119 | name = "Supporting Files"; 120 | sourceTree = ""; 121 | }; 122 | 5AB106DF1D178926003E69E4 /* FTFoldingTableViewUITests */ = { 123 | isa = PBXGroup; 124 | children = ( 125 | 5AB106E01D178926003E69E4 /* FTFoldingTableViewUITests.m */, 126 | 5AB106E21D178926003E69E4 /* Info.plist */, 127 | ); 128 | path = FTFoldingTableViewUITests; 129 | sourceTree = ""; 130 | }; 131 | /* End PBXGroup section */ 132 | 133 | /* Begin PBXNativeTarget section */ 134 | 5AB106C21D178925003E69E4 /* FTFoldingTableView */ = { 135 | isa = PBXNativeTarget; 136 | buildConfigurationList = 5AB106E51D178926003E69E4 /* Build configuration list for PBXNativeTarget "FTFoldingTableView" */; 137 | buildPhases = ( 138 | 5AB106BF1D178925003E69E4 /* Sources */, 139 | 5AB106C01D178925003E69E4 /* Frameworks */, 140 | 5AB106C11D178925003E69E4 /* Resources */, 141 | ); 142 | buildRules = ( 143 | ); 144 | dependencies = ( 145 | ); 146 | name = FTFoldingTableView; 147 | productName = FTFoldingTableView; 148 | productReference = 5AB106C31D178925003E69E4 /* FTFoldingTableView.app */; 149 | productType = "com.apple.product-type.application"; 150 | }; 151 | 5AB106DB1D178926003E69E4 /* FTFoldingTableViewUITests */ = { 152 | isa = PBXNativeTarget; 153 | buildConfigurationList = 5AB106E81D178926003E69E4 /* Build configuration list for PBXNativeTarget "FTFoldingTableViewUITests" */; 154 | buildPhases = ( 155 | 5AB106D81D178926003E69E4 /* Sources */, 156 | 5AB106D91D178926003E69E4 /* Frameworks */, 157 | 5AB106DA1D178926003E69E4 /* Resources */, 158 | ); 159 | buildRules = ( 160 | ); 161 | dependencies = ( 162 | 5AB106DE1D178926003E69E4 /* PBXTargetDependency */, 163 | ); 164 | name = FTFoldingTableViewUITests; 165 | productName = FTFoldingTableViewUITests; 166 | productReference = 5AB106DC1D178926003E69E4 /* FTFoldingTableViewUITests.xctest */; 167 | productType = "com.apple.product-type.bundle.ui-testing"; 168 | }; 169 | /* End PBXNativeTarget section */ 170 | 171 | /* Begin PBXProject section */ 172 | 5AB106BB1D178925003E69E4 /* Project object */ = { 173 | isa = PBXProject; 174 | attributes = { 175 | LastUpgradeCheck = 1010; 176 | ORGANIZATIONNAME = liufengting; 177 | TargetAttributes = { 178 | 5AB106C21D178925003E69E4 = { 179 | CreatedOnToolsVersion = 7.3.1; 180 | DevelopmentTeam = E83AC9WR2F; 181 | DevelopmentTeamName = "锋婷 刘 (Personal Team)"; 182 | ProvisioningStyle = Automatic; 183 | }; 184 | 5AB106DB1D178926003E69E4 = { 185 | CreatedOnToolsVersion = 7.3.1; 186 | TestTargetID = 5AB106C21D178925003E69E4; 187 | }; 188 | }; 189 | }; 190 | buildConfigurationList = 5AB106BE1D178925003E69E4 /* Build configuration list for PBXProject "FTFoldingTableView" */; 191 | compatibilityVersion = "Xcode 3.2"; 192 | developmentRegion = English; 193 | hasScannedForEncodings = 0; 194 | knownRegions = ( 195 | en, 196 | Base, 197 | ); 198 | mainGroup = 5AB106BA1D178925003E69E4; 199 | productRefGroup = 5AB106C41D178925003E69E4 /* Products */; 200 | projectDirPath = ""; 201 | projectRoot = ""; 202 | targets = ( 203 | 5AB106C21D178925003E69E4 /* FTFoldingTableView */, 204 | 5AB106DB1D178926003E69E4 /* FTFoldingTableViewUITests */, 205 | ); 206 | }; 207 | /* End PBXProject section */ 208 | 209 | /* Begin PBXResourcesBuildPhase section */ 210 | 5AB106C11D178925003E69E4 /* Resources */ = { 211 | isa = PBXResourcesBuildPhase; 212 | buildActionMask = 2147483647; 213 | files = ( 214 | 5AB106D61D178925003E69E4 /* LaunchScreen.storyboard in Resources */, 215 | 2ABD2C521E44520F00EBB748 /* Arrowhead.png in Resources */, 216 | 5AB106D31D178925003E69E4 /* Assets.xcassets in Resources */, 217 | 5A4B4FB41D4F3D3200134E33 /* Main.storyboard in Resources */, 218 | ); 219 | runOnlyForDeploymentPostprocessing = 0; 220 | }; 221 | 5AB106DA1D178926003E69E4 /* Resources */ = { 222 | isa = PBXResourcesBuildPhase; 223 | buildActionMask = 2147483647; 224 | files = ( 225 | ); 226 | runOnlyForDeploymentPostprocessing = 0; 227 | }; 228 | /* End PBXResourcesBuildPhase section */ 229 | 230 | /* Begin PBXSourcesBuildPhase section */ 231 | 5AB106BF1D178925003E69E4 /* Sources */ = { 232 | isa = PBXSourcesBuildPhase; 233 | buildActionMask = 2147483647; 234 | files = ( 235 | 5AB106CE1D178925003E69E4 /* ViewController.m in Sources */, 236 | 5AB106CB1D178925003E69E4 /* AppDelegate.m in Sources */, 237 | 5AB106C81D178925003E69E4 /* main.m in Sources */, 238 | 2ABD2C531E44520F00EBB748 /* FTFoldingTableView.m in Sources */, 239 | ); 240 | runOnlyForDeploymentPostprocessing = 0; 241 | }; 242 | 5AB106D81D178926003E69E4 /* Sources */ = { 243 | isa = PBXSourcesBuildPhase; 244 | buildActionMask = 2147483647; 245 | files = ( 246 | 5AB106E11D178926003E69E4 /* FTFoldingTableViewUITests.m in Sources */, 247 | ); 248 | runOnlyForDeploymentPostprocessing = 0; 249 | }; 250 | /* End PBXSourcesBuildPhase section */ 251 | 252 | /* Begin PBXTargetDependency section */ 253 | 5AB106DE1D178926003E69E4 /* PBXTargetDependency */ = { 254 | isa = PBXTargetDependency; 255 | target = 5AB106C21D178925003E69E4 /* FTFoldingTableView */; 256 | targetProxy = 5AB106DD1D178926003E69E4 /* PBXContainerItemProxy */; 257 | }; 258 | /* End PBXTargetDependency section */ 259 | 260 | /* Begin PBXVariantGroup section */ 261 | 5AB106D41D178925003E69E4 /* LaunchScreen.storyboard */ = { 262 | isa = PBXVariantGroup; 263 | children = ( 264 | 5AB106D51D178925003E69E4 /* Base */, 265 | ); 266 | name = LaunchScreen.storyboard; 267 | sourceTree = ""; 268 | }; 269 | /* End PBXVariantGroup section */ 270 | 271 | /* Begin XCBuildConfiguration section */ 272 | 5AB106E31D178926003E69E4 /* Debug */ = { 273 | isa = XCBuildConfiguration; 274 | buildSettings = { 275 | ALWAYS_SEARCH_USER_PATHS = NO; 276 | CLANG_ANALYZER_NONNULL = YES; 277 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 278 | CLANG_CXX_LIBRARY = "libc++"; 279 | CLANG_ENABLE_MODULES = YES; 280 | CLANG_ENABLE_OBJC_ARC = YES; 281 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 282 | CLANG_WARN_BOOL_CONVERSION = YES; 283 | CLANG_WARN_COMMA = YES; 284 | CLANG_WARN_CONSTANT_CONVERSION = YES; 285 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 286 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 287 | CLANG_WARN_EMPTY_BODY = YES; 288 | CLANG_WARN_ENUM_CONVERSION = YES; 289 | CLANG_WARN_INFINITE_RECURSION = YES; 290 | CLANG_WARN_INT_CONVERSION = YES; 291 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 292 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 293 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 294 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 295 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 296 | CLANG_WARN_STRICT_PROTOTYPES = YES; 297 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 298 | CLANG_WARN_UNREACHABLE_CODE = YES; 299 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 300 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 301 | COPY_PHASE_STRIP = NO; 302 | DEBUG_INFORMATION_FORMAT = dwarf; 303 | ENABLE_STRICT_OBJC_MSGSEND = YES; 304 | ENABLE_TESTABILITY = YES; 305 | GCC_C_LANGUAGE_STANDARD = gnu99; 306 | GCC_DYNAMIC_NO_PIC = NO; 307 | GCC_NO_COMMON_BLOCKS = YES; 308 | GCC_OPTIMIZATION_LEVEL = 0; 309 | GCC_PREPROCESSOR_DEFINITIONS = ( 310 | "DEBUG=1", 311 | "$(inherited)", 312 | ); 313 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 314 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 315 | GCC_WARN_UNDECLARED_SELECTOR = YES; 316 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 317 | GCC_WARN_UNUSED_FUNCTION = YES; 318 | GCC_WARN_UNUSED_VARIABLE = YES; 319 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 320 | MTL_ENABLE_DEBUG_INFO = YES; 321 | ONLY_ACTIVE_ARCH = YES; 322 | SDKROOT = iphoneos; 323 | }; 324 | name = Debug; 325 | }; 326 | 5AB106E41D178926003E69E4 /* Release */ = { 327 | isa = XCBuildConfiguration; 328 | buildSettings = { 329 | ALWAYS_SEARCH_USER_PATHS = NO; 330 | CLANG_ANALYZER_NONNULL = YES; 331 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 332 | CLANG_CXX_LIBRARY = "libc++"; 333 | CLANG_ENABLE_MODULES = YES; 334 | CLANG_ENABLE_OBJC_ARC = YES; 335 | CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; 336 | CLANG_WARN_BOOL_CONVERSION = YES; 337 | CLANG_WARN_COMMA = YES; 338 | CLANG_WARN_CONSTANT_CONVERSION = YES; 339 | CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; 340 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 341 | CLANG_WARN_EMPTY_BODY = YES; 342 | CLANG_WARN_ENUM_CONVERSION = YES; 343 | CLANG_WARN_INFINITE_RECURSION = YES; 344 | CLANG_WARN_INT_CONVERSION = YES; 345 | CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; 346 | CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; 347 | CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; 348 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 349 | CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; 350 | CLANG_WARN_STRICT_PROTOTYPES = YES; 351 | CLANG_WARN_SUSPICIOUS_MOVE = YES; 352 | CLANG_WARN_UNREACHABLE_CODE = YES; 353 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 354 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 355 | COPY_PHASE_STRIP = NO; 356 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 357 | ENABLE_NS_ASSERTIONS = NO; 358 | ENABLE_STRICT_OBJC_MSGSEND = YES; 359 | GCC_C_LANGUAGE_STANDARD = gnu99; 360 | GCC_NO_COMMON_BLOCKS = YES; 361 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 362 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 363 | GCC_WARN_UNDECLARED_SELECTOR = YES; 364 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 365 | GCC_WARN_UNUSED_FUNCTION = YES; 366 | GCC_WARN_UNUSED_VARIABLE = YES; 367 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 368 | MTL_ENABLE_DEBUG_INFO = NO; 369 | SDKROOT = iphoneos; 370 | VALIDATE_PRODUCT = YES; 371 | }; 372 | name = Release; 373 | }; 374 | 5AB106E61D178926003E69E4 /* Debug */ = { 375 | isa = XCBuildConfiguration; 376 | buildSettings = { 377 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 378 | CODE_SIGN_IDENTITY = "iPhone Developer"; 379 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 380 | DEVELOPMENT_TEAM = E83AC9WR2F; 381 | INFOPLIST_FILE = FTFoldingTableView/Info.plist; 382 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 383 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 384 | PRODUCT_BUNDLE_IDENTIFIER = com.liufengting.FTPageController; 385 | PRODUCT_NAME = "$(TARGET_NAME)"; 386 | }; 387 | name = Debug; 388 | }; 389 | 5AB106E71D178926003E69E4 /* Release */ = { 390 | isa = XCBuildConfiguration; 391 | buildSettings = { 392 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 393 | CODE_SIGN_IDENTITY = "iPhone Developer"; 394 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 395 | DEVELOPMENT_TEAM = E83AC9WR2F; 396 | INFOPLIST_FILE = FTFoldingTableView/Info.plist; 397 | IPHONEOS_DEPLOYMENT_TARGET = 8.0; 398 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 399 | PRODUCT_BUNDLE_IDENTIFIER = com.liufengting.FTPageController; 400 | PRODUCT_NAME = "$(TARGET_NAME)"; 401 | }; 402 | name = Release; 403 | }; 404 | 5AB106E91D178926003E69E4 /* Debug */ = { 405 | isa = XCBuildConfiguration; 406 | buildSettings = { 407 | INFOPLIST_FILE = FTFoldingTableViewUITests/Info.plist; 408 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 409 | PRODUCT_BUNDLE_IDENTIFIER = com.liufengting.FTFoldingTableViewUITests; 410 | PRODUCT_NAME = "$(TARGET_NAME)"; 411 | TEST_TARGET_NAME = FTFoldingTableView; 412 | }; 413 | name = Debug; 414 | }; 415 | 5AB106EA1D178926003E69E4 /* Release */ = { 416 | isa = XCBuildConfiguration; 417 | buildSettings = { 418 | INFOPLIST_FILE = FTFoldingTableViewUITests/Info.plist; 419 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; 420 | PRODUCT_BUNDLE_IDENTIFIER = com.liufengting.FTFoldingTableViewUITests; 421 | PRODUCT_NAME = "$(TARGET_NAME)"; 422 | TEST_TARGET_NAME = FTFoldingTableView; 423 | }; 424 | name = Release; 425 | }; 426 | /* End XCBuildConfiguration section */ 427 | 428 | /* Begin XCConfigurationList section */ 429 | 5AB106BE1D178925003E69E4 /* Build configuration list for PBXProject "FTFoldingTableView" */ = { 430 | isa = XCConfigurationList; 431 | buildConfigurations = ( 432 | 5AB106E31D178926003E69E4 /* Debug */, 433 | 5AB106E41D178926003E69E4 /* Release */, 434 | ); 435 | defaultConfigurationIsVisible = 0; 436 | defaultConfigurationName = Release; 437 | }; 438 | 5AB106E51D178926003E69E4 /* Build configuration list for PBXNativeTarget "FTFoldingTableView" */ = { 439 | isa = XCConfigurationList; 440 | buildConfigurations = ( 441 | 5AB106E61D178926003E69E4 /* Debug */, 442 | 5AB106E71D178926003E69E4 /* Release */, 443 | ); 444 | defaultConfigurationIsVisible = 0; 445 | defaultConfigurationName = Release; 446 | }; 447 | 5AB106E81D178926003E69E4 /* Build configuration list for PBXNativeTarget "FTFoldingTableViewUITests" */ = { 448 | isa = XCConfigurationList; 449 | buildConfigurations = ( 450 | 5AB106E91D178926003E69E4 /* Debug */, 451 | 5AB106EA1D178926003E69E4 /* Release */, 452 | ); 453 | defaultConfigurationIsVisible = 0; 454 | defaultConfigurationName = Release; 455 | }; 456 | /* End XCConfigurationList section */ 457 | }; 458 | rootObject = 5AB106BB1D178925003E69E4 /* Project object */; 459 | } 460 | -------------------------------------------------------------------------------- /FTFoldingTableView/FTFoldingTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // FTFoldingTableView.m 3 | // FTFoldingTableView 4 | // 5 | // Created by liufengting on 16/6/20. 6 | // Copyright © 2016 LiuFengting . All rights reserved. 7 | // 8 | 9 | #import "FTFoldingTableView.h" 10 | 11 | #pragma mark - Constants 12 | /** 13 | * Constants 14 | */ 15 | #define FTFoldingDefaultMargin 8.0f 16 | #define FTFoldingDefaultIconSize 24.0f 17 | #define FTFoldingDefaultSepertorLineWidth 0.3f 18 | 19 | #pragma mark - FTFoldingTableView 20 | /** 21 | * FTFoldingTableView 22 | */ 23 | @interface FTFoldingTableView () 24 | 25 | @property (nonatomic, strong) NSMutableArray *statusArray; 26 | 27 | @end 28 | 29 | @implementation FTFoldingTableView 30 | 31 | #pragma mark - Initial Methods 32 | 33 | - (instancetype)init { 34 | self = [super init]; 35 | if (self) { 36 | [self setupDelegateAndDataSource]; 37 | } 38 | return self; 39 | } 40 | 41 | - (instancetype)initWithFrame:(CGRect)frame { 42 | self = [super initWithFrame:frame]; 43 | if (self) { 44 | [self setupDelegateAndDataSource]; 45 | } 46 | return self; 47 | } 48 | 49 | - (instancetype)initWithFrame:(CGRect)frame style:(UITableViewStyle)style { 50 | self = [super initWithFrame:frame style:style]; 51 | if (self) { 52 | [self setupDelegateAndDataSource]; 53 | } 54 | return self; 55 | } 56 | 57 | - (instancetype)initWithCoder:(NSCoder *)aDecoder { 58 | self = [super initWithCoder:aDecoder]; 59 | if (self) { 60 | [self setupDelegateAndDataSource]; 61 | } 62 | return self; 63 | } 64 | 65 | #pragma mark - Setup Methods 66 | 67 | - (void)setupDelegateAndDataSource { 68 | self.delegate = self; 69 | self.dataSource = self; 70 | if (self.style == UITableViewStylePlain) { 71 | self.tableFooterView = [[UIView alloc] init]; 72 | } 73 | [[NSNotificationCenter defaultCenter] addObserver:self 74 | selector:@selector(onChangeStatusBarOrientationNotification:) 75 | name:UIApplicationDidChangeStatusBarOrientationNotification 76 | object:nil]; 77 | } 78 | 79 | - (NSMutableArray *)statusArray { 80 | if (!_statusArray) { 81 | _statusArray = [NSMutableArray array]; 82 | } 83 | if (_statusArray.count) { 84 | if (_statusArray.count > self.numberOfSections) { 85 | [_statusArray removeObjectsInRange:NSMakeRange(self.numberOfSections - 1, _statusArray.count - self.numberOfSections)]; 86 | }else if (_statusArray.count < self.numberOfSections) { 87 | for (NSInteger i = self.numberOfSections - _statusArray.count; i < self.numberOfSections; i++) { 88 | [_statusArray addObject:[NSNumber numberWithInteger:FTFoldingSectionStateFold]]; 89 | } 90 | } 91 | }else{ 92 | for (NSInteger i = 0; i < self.numberOfSections; i++) { 93 | [_statusArray addObject:[NSNumber numberWithInteger:FTFoldingSectionStateFold]]; 94 | } 95 | } 96 | return _statusArray; 97 | } 98 | 99 | - (void)onChangeStatusBarOrientationNotification:(NSNotification *)notification { 100 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 101 | [self reloadData]; 102 | }); 103 | } 104 | 105 | #pragma mark - UI Configration 106 | 107 | - (FTFoldingSectionHeaderArrowPosition )perferedArrowPosition { 108 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(perferedArrowPositionForFTFoldingTableView:)]) { 109 | return [_foldingDelegate perferedArrowPositionForFTFoldingTableView:self]; 110 | } 111 | return FTFoldingSectionHeaderArrowPositionRight; 112 | } 113 | 114 | - (UIColor *)backgroundColorForSection:(NSInteger )section { 115 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:backgroundColorForHeaderInSection:)]) { 116 | return [_foldingDelegate ftFoldingTableView:self backgroundColorForHeaderInSection:section]; 117 | } 118 | return [UIColor colorWithRed:102/255.f green:102/255.f blue:255/255.f alpha:1.f]; 119 | } 120 | 121 | - (NSString *)titleForSection:(NSInteger )section { 122 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:titleForHeaderInSection:)]) { 123 | return [_foldingDelegate ftFoldingTableView:self titleForHeaderInSection:section]; 124 | } 125 | return [NSString string]; 126 | } 127 | 128 | - (UIFont *)titleFontForSection:(NSInteger )section { 129 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:fontForTitleInSection:)]) { 130 | return [_foldingDelegate ftFoldingTableView:self fontForTitleInSection:section]; 131 | } 132 | return [UIFont boldSystemFontOfSize:16]; 133 | } 134 | 135 | - (UIColor *)titleColorForSection:(NSInteger )section { 136 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:textColorForTitleInSection:)]) { 137 | return [_foldingDelegate ftFoldingTableView:self textColorForTitleInSection:section]; 138 | } 139 | return [UIColor whiteColor]; 140 | } 141 | 142 | - (NSString *)descriptionForSection:(NSInteger )section { 143 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:descriptionForHeaderInSection:)]) { 144 | return [_foldingDelegate ftFoldingTableView:self descriptionForHeaderInSection:section]; 145 | } 146 | return [NSString string]; 147 | } 148 | 149 | - (UIFont *)descriptionFontForSection:(NSInteger )section { 150 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:fontForDescriptionInSection:)]) { 151 | return [_foldingDelegate ftFoldingTableView:self fontForDescriptionInSection:section]; 152 | } 153 | return [UIFont systemFontOfSize:13]; 154 | } 155 | 156 | - (UIColor *)descriptionColorForSection:(NSInteger )section { 157 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:textColorForDescriptionInSection:)]) { 158 | return [_foldingDelegate ftFoldingTableView:self textColorForDescriptionInSection:section]; 159 | } 160 | return [UIColor whiteColor]; 161 | } 162 | 163 | - (UIImage *)arrowImageForSection:(NSInteger )section { 164 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:arrowImageForSection:)]) { 165 | return [_foldingDelegate ftFoldingTableView:self arrowImageForSection:section]; 166 | } 167 | return [UIImage imageNamed:@"Arrowhead"]; 168 | } 169 | 170 | #pragma mark - UITableViewDelegate,UITableViewDataSource 171 | 172 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 173 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(numberOfSectionForFTFoldingTableView:)]) { 174 | return [_foldingDelegate numberOfSectionForFTFoldingTableView:self]; 175 | }else{ 176 | return self.numberOfSections; 177 | } 178 | } 179 | 180 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 181 | if (((NSNumber *)self.statusArray[section]).integerValue == FTFoldingSectionStateExpand) { 182 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:numberOfRowsInSection:)]) { 183 | return [_foldingDelegate ftFoldingTableView:self numberOfRowsInSection:section]; 184 | } 185 | } 186 | return 0; 187 | } 188 | 189 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 190 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:heightForHeaderInSection:)]) { 191 | return [_foldingDelegate ftFoldingTableView:self heightForHeaderInSection:section]; 192 | }else{ 193 | return self.sectionHeaderHeight; 194 | } 195 | } 196 | 197 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 198 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:heightForRowAtIndexPath:)]) { 199 | return [_foldingDelegate ftFoldingTableView:self heightForRowAtIndexPath:indexPath]; 200 | }else{ 201 | return self.rowHeight; 202 | } 203 | } 204 | 205 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section { 206 | if (self.style == UITableViewStylePlain) { 207 | return 0; 208 | }else{ 209 | return 0.01; 210 | } 211 | } 212 | 213 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 214 | FTFoldingSectionHeader *sectionHeaderView = [[FTFoldingSectionHeader alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, [self tableView:self heightForHeaderInSection:section]) 215 | withTag:section]; 216 | 217 | [sectionHeaderView setupWithBackgroundColor:[self backgroundColorForSection:section] 218 | titleString:[self titleForSection:section] 219 | titleColor:[self titleColorForSection:section] 220 | titleFont:[self titleFontForSection:section] 221 | descriptionString:[self descriptionForSection:section] 222 | descriptionColor:[self descriptionColorForSection:section] 223 | descriptionFont:[self descriptionFontForSection:section] 224 | arrowImage:[self arrowImageForSection:section] 225 | arrowPosition:[self perferedArrowPosition] 226 | sectionState:((NSNumber *)self.statusArray[section]).integerValue]; 227 | 228 | sectionHeaderView.tapDelegate = self; 229 | 230 | return sectionHeaderView; 231 | } 232 | 233 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 234 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:cellForRowAtIndexPath:)]) { 235 | return [_foldingDelegate ftFoldingTableView:self cellForRowAtIndexPath:indexPath]; 236 | } 237 | return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"DefaultCellIndentifier"]; 238 | } 239 | 240 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 241 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:didSelectRowAtIndexPath:)]) { 242 | [_foldingDelegate ftFoldingTableView:self didSelectRowAtIndexPath:indexPath]; 243 | } 244 | } 245 | 246 | - (void)tableView:(UITableView *)tableView didDeselectRowAtIndexPath:(NSIndexPath *)indexPath { 247 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:didDeselectRowAtIndexPath:)]) { 248 | [_foldingDelegate ftFoldingTableView:self didDeselectRowAtIndexPath:indexPath]; 249 | } 250 | } 251 | 252 | #pragma mark - FTFoldingSectionHeaderDelegate 253 | 254 | - (void)ftFoldingSectionHeaderTappedAtIndex:(NSInteger)index { 255 | BOOL currentIsOpen = ((NSNumber *)self.statusArray[index]).boolValue; 256 | 257 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:willChangeToSectionState:section:)]) { 258 | [_foldingDelegate ftFoldingTableView:self 259 | willChangeToSectionState:(currentIsOpen == YES) ? FTFoldingSectionStateFold : FTFoldingSectionStateExpand 260 | section:index]; 261 | } 262 | 263 | [self.statusArray replaceObjectAtIndex:index withObject:[NSNumber numberWithBool:!currentIsOpen]]; 264 | 265 | NSInteger numberOfRow = [_foldingDelegate ftFoldingTableView:self numberOfRowsInSection:index]; 266 | NSMutableArray *rowArray = [NSMutableArray array]; 267 | if (numberOfRow) { 268 | for (NSInteger i = 0; i < numberOfRow; i++) { 269 | [rowArray addObject:[NSIndexPath indexPathForRow:i inSection:index]]; 270 | } 271 | } 272 | if (rowArray.count) { 273 | if (currentIsOpen) { 274 | [self deleteRowsAtIndexPaths:[NSArray arrayWithArray:rowArray] withRowAnimation:UITableViewRowAnimationTop]; 275 | }else{ 276 | [self insertRowsAtIndexPaths:[NSArray arrayWithArray:rowArray] withRowAnimation:UITableViewRowAnimationTop]; 277 | } 278 | } 279 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(ftFoldingTableView:didChangeToSectionState:section:)]) { 280 | [_foldingDelegate ftFoldingTableView:self 281 | didChangeToSectionState:(currentIsOpen == YES) ? FTFoldingSectionStateFold : FTFoldingSectionStateExpand 282 | section:index]; 283 | } 284 | } 285 | 286 | - (FTFoldingSectionState)foldingStateForSection:(NSInteger)section { 287 | if (section <= self.statusArray.count - 1) { 288 | return ((NSNumber *)self.statusArray[section]).integerValue; 289 | } 290 | return FTFoldingSectionStateFold; 291 | } 292 | 293 | - (void)expandSection:(NSInteger)section { 294 | if ([self foldingStateForSection:section] == FTFoldingSectionStateFold) { 295 | [self ftFoldingSectionHeaderTappedAtIndex:section]; 296 | } 297 | } 298 | 299 | - (void)foldSection:(NSInteger)section { 300 | if ([self foldingStateForSection:section] == FTFoldingSectionStateExpand) { 301 | [self ftFoldingSectionHeaderTappedAtIndex:section]; 302 | } 303 | } 304 | 305 | - (void)expandAllSections { 306 | [self.statusArray enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 307 | if (obj.integerValue == FTFoldingSectionStateFold) { 308 | [self ftFoldingSectionHeaderTappedAtIndex:idx]; 309 | } 310 | }]; 311 | } 312 | 313 | - (void)foldAllSections { 314 | [self.statusArray enumerateObjectsUsingBlock:^(NSNumber * _Nonnull obj, NSUInteger idx, BOOL * _Nonnull stop) { 315 | if (obj.boolValue == FTFoldingSectionStateExpand) { 316 | [self ftFoldingSectionHeaderTappedAtIndex:idx]; 317 | } 318 | }]; 319 | } 320 | 321 | @end 322 | 323 | #pragma mark - FTFoldingSectionHeader 324 | /** 325 | * FTFoldingSectionHeader 326 | */ 327 | @interface FTFoldingSectionHeader () 328 | 329 | @property (nonatomic, strong)UILabel *titleLabel; 330 | @property (nonatomic, strong)UILabel *descriptionLabel; 331 | @property (nonatomic, strong)UIImageView *arrowImageView; 332 | @property (nonatomic, strong)UIView *sepertorLine; 333 | @property (nonatomic, assign)FTFoldingSectionHeaderArrowPosition arrowPosition; 334 | @property (nonatomic, assign)FTFoldingSectionState sectionState; 335 | @property (nonatomic, strong)UITapGestureRecognizer *tapGesture; 336 | 337 | @end 338 | 339 | @implementation FTFoldingSectionHeader 340 | 341 | - (instancetype)initWithFrame:(CGRect)frame withTag:(NSInteger)tag { 342 | self = [super initWithFrame:frame]; 343 | if (self) { 344 | self.tag = tag; 345 | [self setupSubviewsWithArrowPosition:FTFoldingSectionHeaderArrowPositionRight]; 346 | } 347 | return self; 348 | } 349 | 350 | - (void)awakeFromNib { 351 | [super awakeFromNib]; 352 | [self setupSubviewsWithArrowPosition:FTFoldingSectionHeaderArrowPositionRight]; 353 | 354 | } 355 | 356 | - (UILabel *)titleLabel { 357 | if (!_titleLabel) { 358 | _titleLabel = [[UILabel alloc]initWithFrame:CGRectZero]; 359 | _titleLabel.backgroundColor = [UIColor clearColor]; 360 | _titleLabel.textAlignment = NSTextAlignmentLeft; 361 | } 362 | return _titleLabel; 363 | } 364 | 365 | - (UILabel *)descriptionLabel { 366 | if (!_descriptionLabel) { 367 | _descriptionLabel = [[UILabel alloc]initWithFrame:CGRectZero]; 368 | _descriptionLabel.backgroundColor = [UIColor clearColor]; 369 | _descriptionLabel.textAlignment = NSTextAlignmentRight; 370 | } 371 | return _descriptionLabel; 372 | } 373 | 374 | - (UIImageView *)arrowImageView { 375 | if (!_arrowImageView) { 376 | _arrowImageView = [[UIImageView alloc]initWithFrame:CGRectZero]; 377 | _arrowImageView.backgroundColor = [UIColor clearColor]; 378 | _arrowImageView.contentMode = UIViewContentModeScaleAspectFit; 379 | } 380 | return _arrowImageView; 381 | } 382 | 383 | - (UIView *)sepertorLine { 384 | if (!_sepertorLine) { 385 | _sepertorLine = [[UIView alloc]initWithFrame:CGRectZero]; 386 | _sepertorLine.backgroundColor = [UIColor whiteColor]; 387 | } 388 | return _sepertorLine; 389 | } 390 | 391 | - (UITapGestureRecognizer *)tapGesture { 392 | if (!_tapGesture) { 393 | _tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onTapped:)]; 394 | } 395 | return _tapGesture; 396 | } 397 | 398 | - (void)setupWithBackgroundColor:(UIColor *)backgroundColor 399 | titleString:(NSString *)titleString 400 | titleColor:(UIColor *)titleColor 401 | titleFont:(UIFont *)titleFont 402 | descriptionString:(NSString *)descriptionString 403 | descriptionColor:(UIColor *)descriptionColor 404 | descriptionFont:(UIFont *)descriptionFont 405 | arrowImage:(UIImage *)arrowImage 406 | arrowPosition:(FTFoldingSectionHeaderArrowPosition)arrowPosition 407 | sectionState:(FTFoldingSectionState)sectionState { 408 | [self setBackgroundColor:backgroundColor]; 409 | 410 | [self setupSubviewsWithArrowPosition:arrowPosition]; 411 | 412 | self.titleLabel.text = titleString; 413 | self.titleLabel.textColor = titleColor; 414 | self.titleLabel.font = titleFont; 415 | 416 | self.descriptionLabel.text = descriptionString; 417 | self.descriptionLabel.textColor = descriptionColor; 418 | self.descriptionLabel.font = descriptionFont; 419 | 420 | self.arrowImageView.image = arrowImage; 421 | self.arrowPosition = arrowPosition; 422 | self.sectionState = sectionState; 423 | 424 | if (sectionState == FTFoldingSectionStateExpand) { 425 | if (self.arrowPosition == FTFoldingSectionHeaderArrowPositionRight) { 426 | self.arrowImageView.transform = CGAffineTransformMakeRotation(-M_PI/2); 427 | }else{ 428 | self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 429 | } 430 | } else { 431 | if (self.arrowPosition == FTFoldingSectionHeaderArrowPositionRight) { 432 | _arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 433 | }else{ 434 | self.arrowImageView.transform = CGAffineTransformMakeRotation(0); 435 | } 436 | } 437 | 438 | } 439 | 440 | - (void)setupSubviewsWithArrowPosition:(FTFoldingSectionHeaderArrowPosition)arrowPosition { 441 | CGFloat labelWidth = (self.frame.size.width - FTFoldingDefaultMargin*2 - FTFoldingDefaultIconSize)/2; 442 | CGFloat labelHeight = self.frame.size.height; 443 | CGRect arrowRect = CGRectMake(0, (self.frame.size.height - FTFoldingDefaultIconSize)/2, FTFoldingDefaultIconSize, FTFoldingDefaultIconSize); 444 | CGRect titleRect = CGRectMake(FTFoldingDefaultMargin + FTFoldingDefaultIconSize, 0, labelWidth, labelHeight); 445 | CGRect descriptionRect = CGRectMake(FTFoldingDefaultMargin + FTFoldingDefaultIconSize + labelWidth, 0, labelWidth, labelHeight); 446 | CGRect lineRect = CGRectMake(0, self.bounds.size.height - FTFoldingDefaultSepertorLineWidth, self.bounds.size.width, FTFoldingDefaultSepertorLineWidth); 447 | if (arrowPosition == FTFoldingSectionHeaderArrowPositionRight) { 448 | arrowRect.origin.x = FTFoldingDefaultMargin*2 + labelWidth*2; 449 | titleRect.origin.x = FTFoldingDefaultMargin; 450 | descriptionRect.origin.x = FTFoldingDefaultMargin + labelWidth; 451 | } 452 | 453 | [self.titleLabel setFrame:titleRect]; 454 | [self.descriptionLabel setFrame:descriptionRect]; 455 | [self.arrowImageView setFrame:arrowRect]; 456 | [self.sepertorLine setFrame:lineRect]; 457 | 458 | 459 | [self addSubview:self.titleLabel]; 460 | [self addSubview:self.descriptionLabel]; 461 | [self addSubview:self.arrowImageView]; 462 | [self addGestureRecognizer:self.tapGesture]; 463 | [self addSubview:self.sepertorLine]; 464 | 465 | } 466 | 467 | - (void)shouldExpand:(BOOL)shouldExpand { 468 | 469 | [UIView animateWithDuration:0.2 470 | animations:^{ 471 | if (shouldExpand) { 472 | if (self.arrowPosition == FTFoldingSectionHeaderArrowPositionRight) { 473 | self.arrowImageView.transform = CGAffineTransformMakeRotation(-M_PI/2); 474 | }else{ 475 | self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 476 | } 477 | } else { 478 | if (self.arrowPosition == FTFoldingSectionHeaderArrowPositionRight) { 479 | self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 480 | }else{ 481 | self.arrowImageView.transform = CGAffineTransformMakeRotation(0); 482 | } 483 | } 484 | } completion:^(BOOL finished) { 485 | if (finished == YES) { 486 | self.sepertorLine.hidden = shouldExpand; 487 | } 488 | }]; 489 | } 490 | 491 | - (void)onTapped:(UITapGestureRecognizer *)gesture { 492 | [self shouldExpand:![NSNumber numberWithInteger:self.sectionState].boolValue]; 493 | if (_tapDelegate && [_tapDelegate respondsToSelector:@selector(ftFoldingSectionHeaderTappedAtIndex:)]) { 494 | self.sectionState = [NSNumber numberWithInteger:(![NSNumber numberWithInteger:self.sectionState].boolValue)].integerValue; 495 | [_tapDelegate ftFoldingSectionHeaderTappedAtIndex:self.tag]; 496 | } 497 | } 498 | 499 | @end 500 | 501 | --------------------------------------------------------------------------------