├── SubTable@2x.png ├── SubTableExample ├── SubTableExample │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── AppDelegate.h │ ├── SubTable │ │ ├── SubRow │ │ │ ├── ExpandedContainer.h │ │ │ ├── ExpandedContainer.m │ │ │ ├── ChildCell │ │ │ │ ├── SubTableViewCell.h │ │ │ │ └── SubTableViewCell.m │ │ │ ├── SubTableView.h │ │ │ └── SubTableView.m │ │ ├── ParentCell │ │ │ ├── ParentTableViewCell.h │ │ │ └── ParentTableViewCell.m │ │ ├── ParentTableView.h │ │ └── ParentTableView.m │ ├── main.m │ ├── SubTableExample-Prefix.pch │ ├── ViewController.h │ ├── Images.xcassets │ │ ├── AppIcon.appiconset │ │ │ └── Contents.json │ │ └── LaunchImage.launchimage │ │ │ └── Contents.json │ ├── SubTableExample-Info.plist │ ├── ViewController.xib │ ├── AppDelegate.m │ └── ViewController.m ├── SubTableExampleTests │ ├── en.lproj │ │ └── InfoPlist.strings │ ├── SubTableExampleTests-Info.plist │ └── SubTableExampleTests.m └── SubTableExample.xcodeproj │ ├── xcuserdata │ └── Alex.xcuserdatad │ │ ├── xcdebugger │ │ └── Breakpoints_v2.xcbkptlist │ │ └── xcschemes │ │ ├── xcschememanagement.plist │ │ └── SubTableExample.xcscheme │ ├── project.xcworkspace │ ├── contents.xcworkspacedata │ ├── xcuserdata │ │ └── Alex.xcuserdatad │ │ │ ├── UserInterfaceState.xcuserstate │ │ │ └── WorkspaceSettings.xcsettings │ └── xcshareddata │ │ └── SubTableExample.xccheckout │ └── project.pbxproj ├── .gitignore ├── SubTable ├── SubRow │ ├── ExpandedContainer.h │ ├── ExpandedContainer.m │ ├── ChildCell │ │ ├── SubTableViewCell.h │ │ └── SubTableViewCell.m │ ├── SubTableView.h │ └── SubTableView.m ├── ParentCell │ ├── ParentTableViewCell.h │ └── ParentTableViewCell.m ├── ParentTableView.h └── ParentTableView.m ├── LICENSE └── README.md /SubTable@2x.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajkoshy7/SubTable/HEAD/SubTable@2x.png -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExampleTests/en.lproj/InfoPlist.strings: -------------------------------------------------------------------------------- 1 | /* Localized versions of Info.plist keys */ 2 | 3 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/xcuserdata/Alex.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/project.xcworkspace/xcuserdata/Alex.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/ajkoshy7/SubTable/HEAD/SubTableExample/SubTableExample.xcodeproj/project.xcworkspace/xcuserdata/Alex.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CocoaPods 2 | # 3 | # We recommend against adding the Pods directory to your .gitignore. However 4 | # you should judge for yourself, the pros and cons are mentioned at: 5 | # http://guides.cocoapods.org/using/using-cocoapods.html#should-i-ignore-the-pods-directory-in-source-control? 6 | # 7 | # Pods/ 8 | 9 | -------------------------------------------------------------------------------- /SubTable/SubRow/ExpandedContainer.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExpandedContainer.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SubTableView.h" 11 | #import "SubTableViewCell.h" 12 | 13 | @interface ExpandedContainer : SubTableView 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/SubRow/ExpandedContainer.h: -------------------------------------------------------------------------------- 1 | // 2 | // ExpandedContainer.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "SubTableView.h" 11 | #import "SubTableViewCell.h" 12 | 13 | @interface ExpandedContainer : SubTableView 14 | 15 | @end 16 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | #import "AppDelegate.h" 12 | 13 | int main(int argc, char * argv[]) 14 | { 15 | @autoreleasepool { 16 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTableExample-Prefix.pch: -------------------------------------------------------------------------------- 1 | // 2 | // Prefix header 3 | // 4 | // The contents of this file are implicitly included at the beginning of every source file. 5 | // 6 | 7 | #import 8 | 9 | #ifndef __IPHONE_3_0 10 | #warning "This project uses features only available in iOS SDK 3.0 and later." 11 | #endif 12 | 13 | #ifdef __OBJC__ 14 | #import 15 | #import 16 | #endif 17 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ParentTableView.h" 11 | 12 | @interface ViewController : UIViewController 13 | 14 | @property (strong, nonatomic) IBOutlet ParentTableView *tableView; 15 | 16 | @end 17 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/project.xcworkspace/xcuserdata/Alex.xcuserdatad/WorkspaceSettings.xcsettings: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | HasAskedToTakeAutomaticSnapshotBeforeSignificantChanges 6 | 7 | SnapshotAutomaticallyBeforeSignificantChanges 8 | 9 | 10 | 11 | -------------------------------------------------------------------------------- /SubTable/SubRow/ExpandedContainer.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExpandedContainer.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ExpandedContainer.h" 10 | #import "SubTableViewCell.h" 11 | 12 | @implementation ExpandedContainer 13 | 14 | #pragma mark - Table view delegate 15 | 16 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 17 | 18 | // SubTableViewCell *cell = (SubTableViewCell *)[tableView cellForRowAtIndexPath:indexPath]; 19 | // ... 20 | 21 | [self.delegate didSelectRowAtChildIndex:indexPath.row underParentIndex:self.parentIndex]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /SubTable/SubRow/ChildCell/SubTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableViewCell.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SubTableViewCell : UITableViewCell { 12 | 13 | UILabel *titleLabel; 14 | UILabel *subtitleLabel; 15 | } 16 | 17 | @property (strong, nonatomic) UILabel *titleLabel; 18 | @property (strong, nonatomic) UILabel *subtitleLabel; 19 | 20 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; 21 | - (void)setupDisplay; 22 | - (void)setCellForegroundColor:(UIColor *) foregroundColor; 23 | - (void)setCellBackgroundColor:(UIColor *) backgroundColor; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/SubRow/ExpandedContainer.m: -------------------------------------------------------------------------------- 1 | // 2 | // ExpandedContainer.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ExpandedContainer.h" 10 | #import "SubTableViewCell.h" 11 | 12 | @implementation ExpandedContainer 13 | 14 | #pragma mark - Table view delegate 15 | 16 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 17 | 18 | // SubTableViewCell *cell = (SubTableViewCell *)[tableView cellForRowAtIndexPath:indexPath]; 19 | // ... 20 | 21 | [self.delegate didSelectRowAtChildIndex:indexPath.row underParentIndex:self.parentIndex]; 22 | } 23 | 24 | @end 25 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/SubRow/ChildCell/SubTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableViewCell.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SubTableViewCell : UITableViewCell { 12 | 13 | UILabel *titleLabel; 14 | UILabel *subtitleLabel; 15 | } 16 | 17 | @property (strong, nonatomic) UILabel *titleLabel; 18 | @property (strong, nonatomic) UILabel *subtitleLabel; 19 | 20 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; 21 | - (void)setupDisplay; 22 | - (void)setCellForegroundColor:(UIColor *) foregroundColor; 23 | - (void)setCellBackgroundColor:(UIColor *) backgroundColor; 24 | 25 | @end 26 | -------------------------------------------------------------------------------- /SubTable/ParentCell/ParentTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableViewCell.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ParentTableViewCell : UITableViewCell { 12 | 13 | NSInteger parentIndex; 14 | UILabel *titleLabel; 15 | UILabel *subtitleLabel; 16 | } 17 | 18 | @property (nonatomic) NSInteger parentIndex; 19 | @property (strong, nonatomic) UILabel *titleLabel; 20 | @property (strong, nonatomic) UILabel *subtitleLabel; 21 | 22 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; 23 | - (void)setCellForegroundColor:(UIColor *)foregroundColor; 24 | - (void)setCellBackgroundColor:(UIColor *)backgroundColor; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | SubTableExample.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | FAEF419C197751FE00DC189F 16 | 17 | primary 18 | 19 | 20 | FAEF41B7197751FE00DC189F 21 | 22 | primary 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/ParentCell/ParentTableViewCell.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableViewCell.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ParentTableViewCell : UITableViewCell { 12 | 13 | NSInteger parentIndex; 14 | UILabel *titleLabel; 15 | UILabel *subtitleLabel; 16 | } 17 | 18 | @property (nonatomic) NSInteger parentIndex; 19 | @property (strong, nonatomic) UILabel *titleLabel; 20 | @property (strong, nonatomic) UILabel *subtitleLabel; 21 | 22 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; 23 | - (void)setCellForegroundColor:(UIColor *)foregroundColor; 24 | - (void)setCellBackgroundColor:(UIColor *)backgroundColor; 25 | 26 | @end 27 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExampleTests/SubTableExampleTests-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | ${EXECUTABLE_NAME} 9 | CFBundleIdentifier 10 | ajkoshy7.${PRODUCT_NAME:rfc1034identifier} 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundlePackageType 14 | BNDL 15 | CFBundleShortVersionString 16 | 1.0 17 | CFBundleSignature 18 | ???? 19 | CFBundleVersion 20 | 1 21 | 22 | 23 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExampleTests/SubTableExampleTests.m: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableExampleTests.m 3 | // SubTableExampleTests 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface SubTableExampleTests : XCTestCase 12 | 13 | @end 14 | 15 | @implementation SubTableExampleTests 16 | 17 | - (void)setUp 18 | { 19 | [super setUp]; 20 | // Put setup code here. This method is called before the invocation of each test method in the class. 21 | } 22 | 23 | - (void)tearDown 24 | { 25 | // Put teardown code here. This method is called after the invocation of each test method in the class. 26 | [super tearDown]; 27 | } 28 | 29 | - (void)testExample 30 | { 31 | XCTFail(@"No implementation for \"%s\"", __PRETTY_FUNCTION__); 32 | } 33 | 34 | @end 35 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/Images.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" : "40x40", 11 | "scale" : "2x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "60x60", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "ipad", 20 | "size" : "29x29", 21 | "scale" : "1x" 22 | }, 23 | { 24 | "idiom" : "ipad", 25 | "size" : "29x29", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "ipad", 30 | "size" : "40x40", 31 | "scale" : "1x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "40x40", 36 | "scale" : "2x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "76x76", 41 | "scale" : "1x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "76x76", 46 | "scale" : "2x" 47 | } 48 | ], 49 | "info" : { 50 | "version" : 1, 51 | "author" : "xcode" 52 | } 53 | } -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2014 Alex Koshy 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. -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/Images.xcassets/LaunchImage.launchimage/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "orientation" : "portrait", 5 | "idiom" : "iphone", 6 | "extent" : "full-screen", 7 | "minimum-system-version" : "7.0", 8 | "scale" : "2x" 9 | }, 10 | { 11 | "orientation" : "portrait", 12 | "idiom" : "iphone", 13 | "subtype" : "retina4", 14 | "extent" : "full-screen", 15 | "minimum-system-version" : "7.0", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "orientation" : "portrait", 20 | "idiom" : "ipad", 21 | "extent" : "full-screen", 22 | "minimum-system-version" : "7.0", 23 | "scale" : "1x" 24 | }, 25 | { 26 | "orientation" : "landscape", 27 | "idiom" : "ipad", 28 | "extent" : "full-screen", 29 | "minimum-system-version" : "7.0", 30 | "scale" : "1x" 31 | }, 32 | { 33 | "orientation" : "portrait", 34 | "idiom" : "ipad", 35 | "extent" : "full-screen", 36 | "minimum-system-version" : "7.0", 37 | "scale" : "2x" 38 | }, 39 | { 40 | "orientation" : "landscape", 41 | "idiom" : "ipad", 42 | "extent" : "full-screen", 43 | "minimum-system-version" : "7.0", 44 | "scale" : "2x" 45 | } 46 | ], 47 | "info" : { 48 | "version" : 1, 49 | "author" : "xcode" 50 | } 51 | } -------------------------------------------------------------------------------- /SubTable/SubRow/SubTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableView.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol SubTableViewCellDelegate 12 | 13 | @required 14 | - (NSInteger)numberOfChildrenUnderParentIndex:(NSInteger)parentIndex; 15 | - (NSInteger)heightForChildRows; 16 | 17 | @optional 18 | - (void)didSelectRowAtChildIndex:(NSInteger)childIndex 19 | underParentIndex:(NSInteger)parentIndex; 20 | - (NSString *)titleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex; 21 | - (NSString *)subtitleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex; 22 | 23 | @end 24 | 25 | 26 | 27 | @interface SubTableView : UITableViewCell { 28 | UITableView *insideTableView; 29 | __weak id delegate; 30 | UIColor *bgColor; 31 | UIColor *fgColor; 32 | UIFont *font; 33 | } 34 | 35 | @property (nonatomic,strong) UITableView *insideTableView; 36 | @property (nonatomic,weak,getter = getDelegate, setter = setDelegate:) id delegate; 37 | @property (nonatomic) NSInteger parentIndex; 38 | 39 | @property (nonatomic, strong, getter = getSubTableForegroundColor, setter = setSubTableForegroundColor:) UIColor *fgColor; 40 | @property (nonatomic, strong, getter = getSubTableBackgroundColor, setter = setSubTableBackgroundColor:) UIColor *bgColor; 41 | @property (nonatomic, strong, getter = getSubTableFont, setter = setSubTableFont:) UIFont *font; 42 | 43 | - (void)reload; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/SubRow/SubTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableView.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @protocol SubTableViewCellDelegate 12 | 13 | @required 14 | - (NSInteger)numberOfChildrenUnderParentIndex:(NSInteger)parentIndex; 15 | - (NSInteger)heightForChildRows; 16 | 17 | @optional 18 | - (void)didSelectRowAtChildIndex:(NSInteger)childIndex 19 | underParentIndex:(NSInteger)parentIndex; 20 | - (NSString *)titleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex; 21 | - (NSString *)subtitleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex; 22 | 23 | @end 24 | 25 | 26 | 27 | @interface SubTableView : UITableViewCell { 28 | UITableView *insideTableView; 29 | __weak id delegate; 30 | UIColor *bgColor; 31 | UIColor *fgColor; 32 | UIFont *font; 33 | } 34 | 35 | @property (nonatomic,strong) UITableView *insideTableView; 36 | @property (nonatomic,weak,getter = getDelegate, setter = setDelegate:) id delegate; 37 | @property (nonatomic) NSInteger parentIndex; 38 | 39 | @property (nonatomic, strong, getter = getSubTableForegroundColor, setter = setSubTableForegroundColor:) UIColor *fgColor; 40 | @property (nonatomic, strong, getter = getSubTableBackgroundColor, setter = setSubTableBackgroundColor:) UIColor *bgColor; 41 | @property (nonatomic, strong, getter = getSubTableFont, setter = setSubTableFont:) UIFont *font; 42 | 43 | - (void)reload; 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTableExample-Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleDisplayName 8 | ${PRODUCT_NAME} 9 | CFBundleExecutable 10 | ${EXECUTABLE_NAME} 11 | CFBundleIdentifier 12 | ajkoshy7.${PRODUCT_NAME:rfc1034identifier} 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | ${PRODUCT_NAME} 17 | CFBundlePackageType 18 | APPL 19 | CFBundleShortVersionString 20 | 1.0 21 | CFBundleSignature 22 | ???? 23 | CFBundleVersion 24 | 1.0 25 | LSRequiresIPhoneOS 26 | 27 | UIRequiredDeviceCapabilities 28 | 29 | armv7 30 | 31 | UISupportedInterfaceOrientations 32 | 33 | UIInterfaceOrientationPortrait 34 | UIInterfaceOrientationLandscapeLeft 35 | UIInterfaceOrientationLandscapeRight 36 | 37 | UISupportedInterfaceOrientations~ipad 38 | 39 | UIInterfaceOrientationPortrait 40 | UIInterfaceOrientationPortraitUpsideDown 41 | UIInterfaceOrientationLandscapeLeft 42 | UIInterfaceOrientationLandscapeRight 43 | 44 | 45 | 46 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/project.xcworkspace/xcshareddata/SubTableExample.xccheckout: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDESourceControlProjectFavoriteDictionaryKey 6 | 7 | IDESourceControlProjectIdentifier 8 | 3F333FF6-F4FC-4168-B5FB-FBEB3B20FD3F 9 | IDESourceControlProjectName 10 | SubTableExample 11 | IDESourceControlProjectOriginsDictionary 12 | 13 | 0A686B62-C257-4938-A352-6A18ABFFDDD1 14 | https://github.com/ajkoshy7/SubTable.git 15 | 16 | IDESourceControlProjectPath 17 | Examples/SubTableExample/SubTableExample.xcodeproj/project.xcworkspace 18 | IDESourceControlProjectRelativeInstallPathDictionary 19 | 20 | 0A686B62-C257-4938-A352-6A18ABFFDDD1 21 | ../../../.. 22 | 23 | IDESourceControlProjectURL 24 | https://github.com/ajkoshy7/SubTable.git 25 | IDESourceControlProjectVersion 26 | 110 27 | IDESourceControlProjectWCCIdentifier 28 | 0A686B62-C257-4938-A352-6A18ABFFDDD1 29 | IDESourceControlProjectWCConfigurations 30 | 31 | 32 | IDESourceControlRepositoryExtensionIdentifierKey 33 | public.vcs.git 34 | IDESourceControlWCCIdentifierKey 35 | 0A686B62-C257-4938-A352-6A18ABFFDDD1 36 | IDESourceControlWCCName 37 | SubTableExample 38 | 39 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /SubTable/ParentTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableView.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpandedContainer.h" 11 | 12 | @class ViewController; 13 | 14 | @protocol SubTableViewDelegate 15 | 16 | @optional 17 | - (void)tableView:(UITableView *)tableView didSelectCellAtChildIndex:(NSInteger)childIndex withInParentCellIndex:(NSInteger)parentIndex; 18 | - (void)tableView:(UITableView *)tableView didDeselectCellAtChildIndex:(NSInteger)childIndex withInParentCellIndex:(NSInteger)parentIndex; 19 | - (void)tableView:(UITableView *)tableView didSelectParentCellAtIndex:(NSInteger)parentIndex; 20 | 21 | @end 22 | 23 | 24 | 25 | @protocol SubTableViewDataSource 26 | 27 | @required 28 | - (NSInteger)numberOfParentCells; 29 | - (NSInteger)numberOfChildCellsUnderParentIndex:(NSInteger)parentIndex; 30 | - (NSInteger)heightForParentRows; 31 | - (NSInteger)heightForChildRows; 32 | 33 | @optional 34 | 35 | // Parent DataSource 36 | - (NSString *)titleLabelForParentCellAtIndex:(NSInteger)parentIndex; 37 | - (NSString *)subtitleLabelForParentCellAtIndex:(NSInteger)parentIndex; 38 | 39 | // Child DataSource 40 | - (NSString *)titleLabelForCellAtChildIndex:(NSInteger)childIndex withinParentCellIndex:(NSInteger)parentIndex; 41 | - (NSString *)subtitleLabelForCellAtChildIndex:(NSInteger)childIndex withinParentCellIndex:(NSInteger)parentIndex; 42 | 43 | @end 44 | 45 | 46 | 47 | @interface ParentTableView : UITableView 48 | { 49 | __weak id tableViewDelegate; 50 | __weak id dataSourceDelegate; 51 | NSMutableArray * expansionStates; 52 | } 53 | 54 | @property (nonatomic, weak) id tableViewDelegate; 55 | @property (nonatomic, weak, getter = getDataSourceDelegate, setter = setDataSourceDelegate:) id dataSourceDelegate; 56 | @property (nonatomic, strong) NSMutableArray * expansionStates; 57 | 58 | @property (assign, nonatomic) NSInteger selectedRow; 59 | - (void)collapseAllRows; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/ParentTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableView.h 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "ExpandedContainer.h" 11 | 12 | @class ViewController; 13 | 14 | @protocol SubTableViewDelegate 15 | 16 | @optional 17 | - (void)tableView:(UITableView *)tableView didSelectCellAtChildIndex:(NSInteger)childIndex withInParentCellIndex:(NSInteger)parentIndex; 18 | - (void)tableView:(UITableView *)tableView didDeselectCellAtChildIndex:(NSInteger)childIndex withInParentCellIndex:(NSInteger)parentIndex; 19 | - (void)tableView:(UITableView *)tableView didSelectParentCellAtIndex:(NSInteger)parentIndex; 20 | 21 | @end 22 | 23 | 24 | 25 | @protocol SubTableViewDataSource 26 | 27 | @required 28 | - (NSInteger)numberOfParentCells; 29 | - (NSInteger)numberOfChildCellsUnderParentIndex:(NSInteger)parentIndex; 30 | - (NSInteger)heightForParentRows; 31 | - (NSInteger)heightForChildRows; 32 | 33 | @optional 34 | 35 | // Parent DataSource 36 | - (NSString *)titleLabelForParentCellAtIndex:(NSInteger)parentIndex; 37 | - (NSString *)subtitleLabelForParentCellAtIndex:(NSInteger)parentIndex; 38 | 39 | // Child DataSource 40 | - (NSString *)titleLabelForCellAtChildIndex:(NSInteger)childIndex withinParentCellIndex:(NSInteger)parentIndex; 41 | - (NSString *)subtitleLabelForCellAtChildIndex:(NSInteger)childIndex withinParentCellIndex:(NSInteger)parentIndex; 42 | 43 | @end 44 | 45 | 46 | 47 | @interface ParentTableView : UITableView 48 | { 49 | __weak id tableViewDelegate; 50 | __weak id dataSourceDelegate; 51 | NSMutableArray * expansionStates; 52 | } 53 | 54 | @property (nonatomic, weak) id tableViewDelegate; 55 | @property (nonatomic, weak, getter = getDataSourceDelegate, setter = setDataSourceDelegate:) id dataSourceDelegate; 56 | @property (nonatomic, strong) NSMutableArray * expansionStates; 57 | 58 | @property (assign, nonatomic) NSInteger selectedRow; 59 | - (void)collapseAllRows; 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SubTable/ParentCell/ParentTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableViewCell.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ParentTableViewCell.h" 10 | 11 | @implementation ParentTableViewCell 12 | @synthesize parentIndex; 13 | @synthesize titleLabel; 14 | @synthesize subtitleLabel; 15 | 16 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; { 17 | 18 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 19 | [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 20 | [[self contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 21 | 22 | if (!self) { 23 | return self; 24 | } 25 | 26 | self.contentView.backgroundColor = [UIColor clearColor]; 27 | self.selectionStyle = UITableViewCellSelectionStyleNone; 28 | 29 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 16, 200, 23)]; 30 | titleLabel.backgroundColor = [UIColor clearColor]; 31 | titleLabel.opaque = NO; 32 | titleLabel.textColor = [UIColor darkTextColor]; 33 | titleLabel.textAlignment = NSTextAlignmentLeft; 34 | [self.contentView addSubview:titleLabel]; 35 | 36 | 37 | self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 41, 200, 16)]; 38 | subtitleLabel.backgroundColor = [UIColor clearColor]; 39 | subtitleLabel.opaque = NO; 40 | subtitleLabel.textColor = [UIColor darkTextColor]; 41 | subtitleLabel.textAlignment = NSTextAlignmentLeft; 42 | [self.contentView addSubview:subtitleLabel]; 43 | 44 | UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 73, 320, 2)]; 45 | bottomLine.backgroundColor = [UIColor colorWithWhite:( 42/255.0) alpha:1.0]; 46 | [self.contentView addSubview:bottomLine]; 47 | 48 | [self.contentView setAutoresizesSubviews:YES]; 49 | 50 | return self; 51 | } 52 | 53 | - (void)setCellForegroundColor:(UIColor *)foregroundColor { 54 | self.titleLabel.textColor = foregroundColor; 55 | self.subtitleLabel.textColor = [UIColor colorWithWhite:0.9 alpha:1.0]; 56 | } 57 | - (void)setCellBackgroundColor:(UIColor *)backgroundColor { 58 | self.contentView.backgroundColor = backgroundColor; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/ParentCell/ParentTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableViewCell.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ParentTableViewCell.h" 10 | 11 | @implementation ParentTableViewCell 12 | @synthesize parentIndex; 13 | @synthesize titleLabel; 14 | @synthesize subtitleLabel; 15 | 16 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier; { 17 | 18 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 19 | [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 20 | [[self contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 21 | 22 | if (!self) { 23 | return self; 24 | } 25 | 26 | self.contentView.backgroundColor = [UIColor clearColor]; 27 | self.selectionStyle = UITableViewCellSelectionStyleNone; 28 | 29 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 16, 200, 23)]; 30 | titleLabel.backgroundColor = [UIColor clearColor]; 31 | titleLabel.opaque = NO; 32 | titleLabel.textColor = [UIColor darkTextColor]; 33 | titleLabel.textAlignment = NSTextAlignmentLeft; 34 | [self.contentView addSubview:titleLabel]; 35 | 36 | 37 | self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectMake(20, 41, 200, 16)]; 38 | subtitleLabel.backgroundColor = [UIColor clearColor]; 39 | subtitleLabel.opaque = NO; 40 | subtitleLabel.textColor = [UIColor darkTextColor]; 41 | subtitleLabel.textAlignment = NSTextAlignmentLeft; 42 | [self.contentView addSubview:subtitleLabel]; 43 | 44 | UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 73, 320, 2)]; 45 | bottomLine.backgroundColor = [UIColor colorWithWhite:( 42/255.0) alpha:1.0]; 46 | [self.contentView addSubview:bottomLine]; 47 | 48 | [self.contentView setAutoresizesSubviews:YES]; 49 | 50 | return self; 51 | } 52 | 53 | - (void)setCellForegroundColor:(UIColor *)foregroundColor { 54 | self.titleLabel.textColor = foregroundColor; 55 | self.subtitleLabel.textColor = [UIColor colorWithWhite:0.9 alpha:1.0]; 56 | } 57 | - (void)setCellBackgroundColor:(UIColor *)backgroundColor { 58 | self.contentView.backgroundColor = backgroundColor; 59 | } 60 | 61 | @end 62 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/ViewController.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 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | -------------------------------------------------------------------------------- /SubTable/SubRow/ChildCell/SubTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableViewCell.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "SubTableViewCell.h" 10 | 11 | @implementation SubTableViewCell 12 | @synthesize titleLabel; 13 | @synthesize subtitleLabel; 14 | 15 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier { 16 | 17 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 18 | [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 19 | [[self contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 20 | 21 | if (!self) 22 | return self; 23 | 24 | self.contentView.backgroundColor = [UIColor whiteColor]; 25 | 26 | self.selectionStyle = UITableViewCellSelectionStyleNone; 27 | 28 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 29 | titleLabel.backgroundColor = [UIColor clearColor]; 30 | titleLabel.opaque = NO; 31 | titleLabel.textColor = [UIColor blackColor]; 32 | titleLabel.textAlignment = NSTextAlignmentLeft; 33 | [self.contentView addSubview:titleLabel]; 34 | 35 | self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 36 | subtitleLabel.backgroundColor = [UIColor clearColor]; 37 | subtitleLabel.opaque = NO; 38 | subtitleLabel.textColor = [UIColor blackColor]; 39 | subtitleLabel.textAlignment = NSTextAlignmentLeft; 40 | [self.contentView addSubview:subtitleLabel]; 41 | 42 | return self; 43 | } 44 | 45 | - (void)layoutSubviews { 46 | [super layoutSubviews]; 47 | [self setupDisplay]; 48 | } 49 | 50 | - (void)setupDisplay { 51 | 52 | [self.contentView setAutoresizesSubviews:YES]; 53 | 54 | self.titleLabel.frame = CGRectMake(35, 10, 165, 20); 55 | self.subtitleLabel.frame = CGRectMake(35, 30, 165, 16); 56 | 57 | self.titleLabel.font = [UIFont boldSystemFontOfSize:16]; 58 | self.subtitleLabel.font = [UIFont systemFontOfSize:12]; 59 | } 60 | 61 | - (void)setCellForegroundColor:(UIColor *)foregroundColor { 62 | titleLabel.textColor = foregroundColor; 63 | subtitleLabel.textColor = [UIColor colorWithWhite:0.9 alpha:1.0]; 64 | } 65 | 66 | - (void)setCellBackgroundColor:(UIColor *) backgroundColor { 67 | self.contentView.backgroundColor = backgroundColor; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/SubRow/ChildCell/SubTableViewCell.m: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableViewCell.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "SubTableViewCell.h" 10 | 11 | @implementation SubTableViewCell 12 | @synthesize titleLabel; 13 | @synthesize subtitleLabel; 14 | 15 | - (id)initWithReuseIdentifier:(NSString *)reuseIdentifier { 16 | 17 | self = [super initWithStyle:UITableViewCellStyleDefault reuseIdentifier:reuseIdentifier]; 18 | [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 19 | [[self contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 20 | 21 | if (!self) 22 | return self; 23 | 24 | self.contentView.backgroundColor = [UIColor whiteColor]; 25 | 26 | self.selectionStyle = UITableViewCellSelectionStyleNone; 27 | 28 | self.titleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 29 | titleLabel.backgroundColor = [UIColor clearColor]; 30 | titleLabel.opaque = NO; 31 | titleLabel.textColor = [UIColor blackColor]; 32 | titleLabel.textAlignment = NSTextAlignmentLeft; 33 | [self.contentView addSubview:titleLabel]; 34 | 35 | self.subtitleLabel = [[UILabel alloc] initWithFrame:CGRectZero]; 36 | subtitleLabel.backgroundColor = [UIColor clearColor]; 37 | subtitleLabel.opaque = NO; 38 | subtitleLabel.textColor = [UIColor blackColor]; 39 | subtitleLabel.textAlignment = NSTextAlignmentLeft; 40 | [self.contentView addSubview:subtitleLabel]; 41 | 42 | return self; 43 | } 44 | 45 | - (void)layoutSubviews { 46 | [super layoutSubviews]; 47 | [self setupDisplay]; 48 | } 49 | 50 | - (void)setupDisplay { 51 | 52 | [self.contentView setAutoresizesSubviews:YES]; 53 | 54 | self.titleLabel.frame = CGRectMake(35, 10, 165, 20); 55 | self.subtitleLabel.frame = CGRectMake(35, 30, 165, 16); 56 | 57 | self.titleLabel.font = [UIFont boldSystemFontOfSize:16]; 58 | self.subtitleLabel.font = [UIFont systemFontOfSize:12]; 59 | } 60 | 61 | - (void)setCellForegroundColor:(UIColor *)foregroundColor { 62 | titleLabel.textColor = foregroundColor; 63 | subtitleLabel.textColor = [UIColor colorWithWhite:0.9 alpha:1.0]; 64 | } 65 | 66 | - (void)setCellBackgroundColor:(UIColor *) backgroundColor { 67 | self.contentView.backgroundColor = backgroundColor; 68 | } 69 | 70 | @end 71 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | #import "ViewController.h" 11 | 12 | @implementation AppDelegate 13 | 14 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 15 | 16 | self.window = [[UIWindow alloc] initWithFrame:[[UIScreen mainScreen] bounds]]; 17 | // Override point for customization after application launch. 18 | self.window.backgroundColor = [UIColor whiteColor]; 19 | 20 | ViewController *vc = [[ViewController alloc] initWithNibName:@"ViewController" bundle:nil]; 21 | UINavigationController *nav = [[UINavigationController alloc] initWithRootViewController:vc]; 22 | nav.navigationBar.barStyle = UIBarStyleBlack; 23 | nav.navigationBar.translucent = YES; 24 | self.window.rootViewController = nav; 25 | [self.window makeKeyAndVisible]; 26 | 27 | return YES; 28 | } 29 | 30 | - (void)applicationWillResignActive:(UIApplication *)application { 31 | 32 | // 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. 33 | // 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. 34 | } 35 | - (void)applicationDidEnterBackground:(UIApplication *)application { 36 | 37 | // 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. 38 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 39 | } 40 | - (void)applicationWillEnterForeground:(UIApplication *)application { 41 | 42 | // 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. 43 | } 44 | - (void)applicationDidBecomeActive:(UIApplication *)application { 45 | 46 | // 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. 47 | } 48 | - (void)applicationWillTerminate:(UIApplication *)application { 49 | 50 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 51 | } 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # SubTable 2 | A lightweight subclass of UITableView with Expandable/Collapsible rows. Implemented by inserting a cell below an expanded parent cell to act as a container. The container is adjusted to fit the height of the combined row heights of all child row heights in the nested table view. Both the parent row and child row heights can be adjusted to suit your needs. 3 | 4 | ## Features 5 | * A UITableView subclass implemented using a second, nested table view 6 | * Support for custom and independent row heights for parent and child table views 7 | * Recycled cells for both parent and child table views, allowing for high performance at large numbers of parents and children 8 | * Easy to plug in and customize to fit your project 9 | 10 | ## Examples 11 | This repo contains an example project optimized for iPhone to use as a template for testing purposes 12 | 13 | ![alt tag](https://github.com/ajkoshy7/SubTable/blob/master/SubTable@2x.png) 14 | 15 | ## Usage 16 | The easiest way to install is by copying the SubTable directory to your project: 17 | Initialize a ParentTableView: 18 | ```objective-c 19 | ParentTableView *tableView = [[ParentTableView alloc] init]; 20 | ``` 21 | Optionally, add a UITableView to your xib file and set its class to `ParentTableView` 22 | Set your ViewController as it's delegate using: 23 | ```objective-c 24 | [self.tableView setDataSourceDelegate:self]; 25 | [self.tableView setTableViewDelegate:self]; 26 | ``` 27 | Implement the following required delegate methods in your ViewController: 28 | ```objective-c 29 | - (NSInteger)numberOfParentCells; 30 | - (NSInteger)heightForParentRows; 31 | - (NSInteger)numberOfChildCellsUnderParentIndex:(NSInteger)parentIndex; 32 | - (NSInteger)heightForChildRows; 33 | ``` 34 | ## License 35 | 36 | Copyright (c) 2014 Alex Koshy ajkoshy7@gmail.com 37 | 38 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 39 | 40 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 41 | 42 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 43 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "ParentTableView.h" 11 | #import "ParentTableViewCell.h" 12 | #import "SubTableView.h" 13 | #import "SubTableViewCell.h" 14 | 15 | @interface ViewController () 16 | 17 | @end 18 | 19 | @implementation ViewController 20 | 21 | - (id)initWithNibName:(NSString *)nibNameOrNil bundle:(NSBundle *)nibBundleOrNil { 22 | 23 | self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil]; 24 | if (self) { 25 | // Custom initialization 26 | self.title = @"SubTable"; 27 | } 28 | return self; 29 | } 30 | - (void)viewDidLoad { 31 | 32 | [super viewDidLoad]; 33 | 34 | [self.tableView setDataSourceDelegate:self]; 35 | [self.tableView setTableViewDelegate:self]; 36 | } 37 | 38 | 39 | 40 | #pragma mark - SubTableViewDelegate 41 | 42 | // @optional 43 | - (void)tableView:(UITableView *)tableView didSelectCellAtChildIndex:(NSInteger)childIndex withInParentCellIndex:(NSInteger)parentIndex { 44 | // ... 45 | } 46 | - (void)tableView:(UITableView *)tableView didDeselectCellAtChildIndex:(NSInteger)childIndex withInParentCellIndex:(NSInteger)parentIndex { 47 | // ... 48 | } 49 | - (void)tableView:(UITableView *)tableView didSelectParentCellAtIndex:(NSInteger)parentIndex { 50 | // .. 51 | } 52 | 53 | 54 | #pragma mark - SubTableDataSource - Parent 55 | 56 | // @required 57 | - (NSInteger)numberOfParentCells { 58 | 59 | return 50; 60 | } 61 | - (NSInteger)heightForParentRows { 62 | 63 | return 75; 64 | } 65 | 66 | // @optional 67 | - (NSString *)titleLabelForParentCellAtIndex:(NSInteger)parentIndex { 68 | 69 | return [NSString stringWithFormat:@"Parent %i",parentIndex + 1]; 70 | } 71 | - (NSString *)subtitleLabelForParentCellAtIndex:(NSInteger)parentIndex { 72 | 73 | NSInteger childCount = [self numberOfChildCellsUnderParentIndex:parentIndex]; 74 | if (childCount > 1) 75 | return [NSString stringWithFormat:@"%i children", (int)childCount]; 76 | else if (childCount == 1) 77 | return [NSString stringWithFormat:@"%i child", (int)childCount]; 78 | else 79 | return @"No children"; 80 | } 81 | 82 | 83 | 84 | #pragma mark - SubTableDataSource - Child 85 | 86 | // @required 87 | - (NSInteger)numberOfChildCellsUnderParentIndex:(NSInteger)parentIndex { 88 | 89 | return 5; 90 | } 91 | - (NSInteger)heightForChildRows { 92 | 93 | return 55; 94 | } 95 | 96 | // @optional 97 | - (NSString *)titleLabelForCellAtChildIndex:(NSInteger)childIndex withinParentCellIndex:(NSInteger)parentIndex { 98 | 99 | return [NSString stringWithFormat:@"Child %i",childIndex + 1]; 100 | } 101 | - (NSString *)subtitleLabelForCellAtChildIndex:(NSInteger)childIndex withinParentCellIndex:(NSInteger)parentIndex { 102 | 103 | return [NSString stringWithFormat:@"nested under parent %i",parentIndex + 1]; 104 | } 105 | 106 | @end 107 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/xcuserdata/Alex.xcuserdatad/xcschemes/SubTableExample.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 42 | 43 | 49 | 50 | 51 | 52 | 61 | 62 | 68 | 69 | 70 | 71 | 72 | 73 | 79 | 80 | 86 | 87 | 88 | 89 | 91 | 92 | 95 | 96 | 97 | -------------------------------------------------------------------------------- /SubTable/SubRow/SubTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableView.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "SubTableView.h" 10 | #import "SubTableViewCell.h" 11 | 12 | @implementation SubTableView 13 | 14 | @synthesize insideTableView; 15 | 16 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 17 | 18 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 19 | if (self) { 20 | 21 | [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 22 | [[self contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 23 | fgColor = [UIColor darkTextColor]; 24 | bgColor = [UIColor clearColor]; 25 | font = [UIFont systemFontOfSize:16.0]; 26 | [self configureInsideTableView]; 27 | } 28 | return self; 29 | } 30 | 31 | 32 | 33 | #pragma mark - Configuration 34 | 35 | - (void)configureInsideTableView { 36 | 37 | self.insideTableView = [[UITableView alloc] init]; 38 | insideTableView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, self.contentView.frame.size.height); 39 | 40 | insideTableView.dataSource = self; 41 | insideTableView.delegate = self; 42 | 43 | [self.insideTableView setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 44 | insideTableView.scrollEnabled = NO; 45 | 46 | insideTableView.backgroundColor = [UIColor clearColor]; 47 | insideTableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); 48 | insideTableView.separatorColor = [UIColor colorWithWhite:( 70/255.0) alpha:1.0]; 49 | 50 | [self.contentView addSubview:self.insideTableView]; 51 | } 52 | 53 | 54 | 55 | #pragma mark - Getters/Setters 56 | 57 | /*** 58 | * Delegate 59 | */ 60 | - (id)getDelegate { 61 | return delegate; 62 | } 63 | // TODO combine set delegate and parentIndex into one method for better safety 64 | - (void)setDelegate:(id)deleg { 65 | 66 | delegate = deleg; 67 | NSInteger numberOfChild = [delegate numberOfChildrenUnderParentIndex:self.parentIndex]; 68 | NSInteger rowHeight = [delegate heightForChildRows]; 69 | insideTableView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, rowHeight * numberOfChild); 70 | } 71 | 72 | /*** 73 | * Foreground 74 | */ 75 | - (UIColor *)getSubTableForegroundColor { 76 | return fgColor; 77 | } 78 | - (void)setSubTableForegroundColor:(UIColor *)p_fgColor { 79 | fgColor = p_fgColor; 80 | } 81 | 82 | /*** 83 | * Background 84 | */ 85 | - (UIColor *)getSubTableBackgroundColor { 86 | return bgColor; 87 | } 88 | - (void)setSubTableBackgroundColor:(UIColor *)p_bgColor { 89 | bgColor = p_bgColor; 90 | } 91 | 92 | /*** 93 | * Font 94 | */ 95 | - (UIFont *)getSubTableFont { 96 | return font; 97 | } 98 | - (void)setSubTableFont:(UIFont *) p_font { 99 | font = p_font; 100 | } 101 | 102 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 103 | [super setSelected:selected animated:animated]; 104 | } 105 | - (void)reload { 106 | [self.insideTableView reloadData]; 107 | } 108 | 109 | 110 | 111 | #pragma mark - Table view data source 112 | 113 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 114 | 115 | return 1; 116 | } 117 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 118 | 119 | NSInteger count = [self.delegate numberOfChildrenUnderParentIndex:self.parentIndex]; 120 | if (count > 0) 121 | return count; 122 | else 123 | return 1; 124 | } 125 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 126 | 127 | static NSString *CELL_IDENTIFIER = @"SubTableViewCell_Reuse_Id"; 128 | 129 | SubTableViewCell *cell = (SubTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CELL_IDENTIFIER]; 130 | if (cell == nil) { 131 | cell = [[SubTableViewCell alloc] initWithReuseIdentifier:CELL_IDENTIFIER]; 132 | } 133 | 134 | NSInteger count = [self.delegate numberOfChildrenUnderParentIndex:self.parentIndex]; 135 | if (count > 0) { 136 | 137 | NSInteger row = [indexPath row]; 138 | cell.titleLabel.text = [self.delegate titleLabelForChildIndex:row underParentIndex:self.parentIndex]; 139 | cell.subtitleLabel.text = [self.delegate subtitleLabelForChildIndex:row underParentIndex:self.parentIndex]; 140 | 141 | [cell setCellBackgroundColor:[UIColor colorWithWhite:0.15 alpha:1.0]]; 142 | [cell setCellForegroundColor:fgColor]; 143 | [cell.titleLabel setFont:font]; 144 | 145 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 146 | return cell; 147 | } 148 | else { 149 | 150 | cell.titleLabel.text = @""; 151 | cell.subtitleLabel.text = @""; 152 | 153 | [cell setCellBackgroundColor:[UIColor colorWithWhite:0.15 alpha:1.0]]; 154 | [cell setCellForegroundColor:fgColor]; 155 | 156 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 157 | return cell; 158 | } 159 | } 160 | 161 | 162 | 163 | #pragma mark - Table view delegate 164 | 165 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 166 | 167 | return [delegate heightForChildRows]; 168 | } 169 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 170 | // must be implemented by concrete subclasses 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/SubRow/SubTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // SubTableView.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "SubTableView.h" 10 | #import "SubTableViewCell.h" 11 | 12 | @implementation SubTableView 13 | 14 | @synthesize insideTableView; 15 | 16 | - (id)initWithStyle:(UITableViewCellStyle)style reuseIdentifier:(NSString *)reuseIdentifier { 17 | 18 | self = [super initWithStyle:style reuseIdentifier:reuseIdentifier]; 19 | if (self) { 20 | 21 | [self setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 22 | [[self contentView] setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 23 | fgColor = [UIColor darkTextColor]; 24 | bgColor = [UIColor clearColor]; 25 | font = [UIFont systemFontOfSize:16.0]; 26 | [self configureInsideTableView]; 27 | } 28 | return self; 29 | } 30 | 31 | 32 | 33 | #pragma mark - Configuration 34 | 35 | - (void)configureInsideTableView { 36 | 37 | self.insideTableView = [[UITableView alloc] init]; 38 | insideTableView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, self.contentView.frame.size.height); 39 | 40 | insideTableView.dataSource = self; 41 | insideTableView.delegate = self; 42 | 43 | [self.insideTableView setAutoresizingMask:UIViewAutoresizingFlexibleWidth]; 44 | insideTableView.scrollEnabled = NO; 45 | 46 | insideTableView.backgroundColor = [UIColor clearColor]; 47 | insideTableView.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); 48 | insideTableView.separatorColor = [UIColor colorWithWhite:( 70/255.0) alpha:1.0]; 49 | 50 | [self.contentView addSubview:self.insideTableView]; 51 | } 52 | 53 | 54 | 55 | #pragma mark - Getters/Setters 56 | 57 | /*** 58 | * Delegate 59 | */ 60 | - (id)getDelegate { 61 | return delegate; 62 | } 63 | // TODO combine set delegate and parentIndex into one method for better safety 64 | - (void)setDelegate:(id)deleg { 65 | 66 | delegate = deleg; 67 | NSInteger numberOfChild = [delegate numberOfChildrenUnderParentIndex:self.parentIndex]; 68 | NSInteger rowHeight = [delegate heightForChildRows]; 69 | insideTableView.frame = CGRectMake(0, 0, self.contentView.frame.size.width, rowHeight * numberOfChild); 70 | } 71 | 72 | /*** 73 | * Foreground 74 | */ 75 | - (UIColor *)getSubTableForegroundColor { 76 | return fgColor; 77 | } 78 | - (void)setSubTableForegroundColor:(UIColor *)p_fgColor { 79 | fgColor = p_fgColor; 80 | } 81 | 82 | /*** 83 | * Background 84 | */ 85 | - (UIColor *)getSubTableBackgroundColor { 86 | return bgColor; 87 | } 88 | - (void)setSubTableBackgroundColor:(UIColor *)p_bgColor { 89 | bgColor = p_bgColor; 90 | } 91 | 92 | /*** 93 | * Font 94 | */ 95 | - (UIFont *)getSubTableFont { 96 | return font; 97 | } 98 | - (void)setSubTableFont:(UIFont *) p_font { 99 | font = p_font; 100 | } 101 | 102 | - (void)setSelected:(BOOL)selected animated:(BOOL)animated { 103 | [super setSelected:selected animated:animated]; 104 | } 105 | - (void)reload { 106 | [self.insideTableView reloadData]; 107 | } 108 | 109 | 110 | 111 | #pragma mark - Table view data source 112 | 113 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 114 | 115 | return 1; 116 | } 117 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 118 | 119 | NSInteger count = [self.delegate numberOfChildrenUnderParentIndex:self.parentIndex]; 120 | if (count > 0) 121 | return count; 122 | else 123 | return 1; 124 | } 125 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 126 | 127 | static NSString *CELL_IDENTIFIER = @"SubTableViewCell_Reuse_Id"; 128 | 129 | SubTableViewCell *cell = (SubTableViewCell *)[tableView dequeueReusableCellWithIdentifier:CELL_IDENTIFIER]; 130 | if (cell == nil) { 131 | cell = [[SubTableViewCell alloc] initWithReuseIdentifier:CELL_IDENTIFIER]; 132 | } 133 | 134 | NSInteger count = [self.delegate numberOfChildrenUnderParentIndex:self.parentIndex]; 135 | if (count > 0) { 136 | 137 | NSInteger row = [indexPath row]; 138 | cell.titleLabel.text = [self.delegate titleLabelForChildIndex:row underParentIndex:self.parentIndex]; 139 | cell.subtitleLabel.text = [self.delegate subtitleLabelForChildIndex:row underParentIndex:self.parentIndex]; 140 | 141 | [cell setCellBackgroundColor:[UIColor colorWithWhite:0.15 alpha:1.0]]; 142 | [cell setCellForegroundColor:fgColor]; 143 | [cell.titleLabel setFont:font]; 144 | 145 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 146 | return cell; 147 | } 148 | else { 149 | 150 | cell.titleLabel.text = @""; 151 | cell.subtitleLabel.text = @""; 152 | 153 | [cell setCellBackgroundColor:[UIColor colorWithWhite:0.15 alpha:1.0]]; 154 | [cell setCellForegroundColor:fgColor]; 155 | 156 | cell.selectionStyle = UITableViewCellSelectionStyleNone; 157 | return cell; 158 | } 159 | } 160 | 161 | 162 | 163 | #pragma mark - Table view delegate 164 | 165 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 166 | 167 | return [delegate heightForChildRows]; 168 | } 169 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 170 | // must be implemented by concrete subclasses 171 | } 172 | 173 | @end 174 | -------------------------------------------------------------------------------- /SubTable/ParentTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableView.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ParentTableView.h" 10 | #import "ParentTableViewCell.h" 11 | #import "ExpandedContainer.h" 12 | 13 | @interface ParentTableView () { 14 | 15 | ParentTableViewCell *previouslySelectedCell; 16 | } 17 | 18 | @end 19 | 20 | @implementation ParentTableView 21 | @synthesize tableViewDelegate, expansionStates; 22 | 23 | - (id)initWithFrame:(CGRect)frame dataSource:dataDelegate tableViewDelegate:tableDelegate { 24 | 25 | self = [super initWithFrame:frame style:UITableViewStylePlain]; 26 | if (self) { 27 | // Initialization code 28 | [self initialize]; 29 | } 30 | return self; 31 | } 32 | - (id)initWithCoder:(NSCoder *)coder { 33 | 34 | self = [super initWithCoder:coder]; 35 | if (self) { 36 | // Initialization code 37 | [self initialize]; 38 | } 39 | return self; 40 | } 41 | - (void)initialize { 42 | 43 | [self setDataSource:self]; 44 | [self setDelegate:self]; 45 | 46 | self.backgroundColor = [UIColor colorWithWhite:( 20/255.0) alpha:1.0]; 47 | self.separatorStyle = UITableViewCellSeparatorStyleNone; 48 | self.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); 49 | self.separatorColor = [UIColor darkGrayColor]; 50 | 51 | UIView *footer = [[UIView alloc] initWithFrame:CGRectZero]; 52 | self.tableFooterView = footer; 53 | } 54 | 55 | 56 | 57 | #pragma mark - Configuration 58 | 59 | - (id)getDataSourceDelegate { 60 | 61 | return dataSourceDelegate; 62 | } 63 | - (void)setDataSourceDelegate:(id)deleg { 64 | 65 | dataSourceDelegate = deleg; 66 | [self initExpansionStates]; 67 | } 68 | - (void)initExpansionStates { 69 | 70 | expansionStates = [[NSMutableArray alloc] initWithCapacity:[self.dataSourceDelegate numberOfParentCells]]; 71 | for(int i = 0; i < [self.dataSourceDelegate numberOfParentCells]; i++) { 72 | [expansionStates addObject:@"NO"]; 73 | } 74 | } 75 | 76 | 77 | 78 | #pragma mark - Table Interaction 79 | 80 | - (void)expandForParentAtRow:(NSInteger)row { 81 | 82 | NSUInteger parentIndex = [self parentIndexForRow:row]; 83 | 84 | if ([[self.expansionStates objectAtIndex:parentIndex] boolValue]) { 85 | return; 86 | } 87 | 88 | // update expansionStates so backing data is ready before calling insertRowsAtIndexPaths 89 | [self.expansionStates replaceObjectAtIndex:parentIndex withObject:@"YES"]; 90 | [self insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; 91 | } 92 | - (void)collapseForParentAtRow:(NSInteger)row { 93 | 94 | if (![self.dataSourceDelegate numberOfParentCells] > 0) { 95 | return; 96 | } 97 | 98 | NSUInteger parentIndex = [self parentIndexForRow:row]; 99 | 100 | if (![[self.expansionStates objectAtIndex:parentIndex] boolValue]) { 101 | return; 102 | } 103 | 104 | // update expansionStates so backing data is ready before calling deleteRowsAtIndexPaths 105 | [self.expansionStates replaceObjectAtIndex:parentIndex withObject:@"NO"]; 106 | [self deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; 107 | } 108 | - (void)collapseAllRows { 109 | 110 | if ([self.expansionStates containsObject:@"YES"]) { 111 | 112 | NSInteger row = [self.expansionStates indexOfObject:@"YES"]; 113 | 114 | [self.expansionStates replaceObjectAtIndex:row withObject:@"NO"]; 115 | [self deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; 116 | } 117 | } 118 | 119 | 120 | 121 | #pragma mark - Table Information 122 | 123 | - (NSUInteger)rowForParentIndex:(NSUInteger)parentIndex { 124 | 125 | NSUInteger row = 0; 126 | NSUInteger currentParentIndex = 0; 127 | 128 | if (parentIndex == 0) { 129 | return 0; 130 | } 131 | 132 | while (currentParentIndex < parentIndex) { 133 | BOOL expanded = [[self.expansionStates objectAtIndex:currentParentIndex] boolValue]; 134 | if (expanded) { 135 | row++; 136 | } 137 | currentParentIndex++; 138 | row++; 139 | } 140 | return row; 141 | } 142 | - (NSUInteger)parentIndexForRow:(NSUInteger)row { 143 | 144 | NSUInteger parentIndex = -1; 145 | 146 | NSUInteger i = 0; 147 | while (i <= row) { 148 | parentIndex++; 149 | i++; 150 | if ([[self.expansionStates objectAtIndex:parentIndex] boolValue]) { 151 | i++; 152 | } 153 | } 154 | return parentIndex; 155 | } 156 | - (BOOL)isExpansionCell:(NSUInteger)row { 157 | 158 | if (row < 1) { 159 | return NO; 160 | } 161 | NSUInteger parentIndex = [self parentIndexForRow:row]; 162 | NSUInteger parentIndex2 = [self parentIndexForRow:(row-1)]; 163 | return (parentIndex == parentIndex2); 164 | } 165 | 166 | 167 | 168 | #pragma mark - UITableViewDataSource 169 | 170 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 171 | 172 | NSInteger row = indexPath.row; 173 | NSInteger rowHeight = [self.dataSourceDelegate heightForParentRows]; 174 | 175 | BOOL isExpansionCell = [self isExpansionCell:row]; 176 | if (isExpansionCell) { 177 | 178 | NSInteger parentIndex = [self parentIndexForRow:row]; 179 | NSInteger numberOfChildren = [self.dataSourceDelegate numberOfChildCellsUnderParentIndex:parentIndex]; 180 | NSInteger childRowHeight = [self.dataSourceDelegate heightForChildRows]; 181 | return childRowHeight * numberOfChildren; 182 | } 183 | else 184 | return rowHeight; 185 | } 186 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 187 | 188 | return 1; 189 | } 190 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 191 | 192 | if (![self.dataSourceDelegate numberOfParentCells] > 0) { 193 | return 0; 194 | } 195 | 196 | // returns sum of parent cells and expanded cells 197 | NSInteger parentCount = [self.dataSourceDelegate numberOfParentCells]; 198 | NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:self.expansionStates]; 199 | NSUInteger expandedParentCount = [countedSet countForObject:@"YES"]; 200 | 201 | return parentCount + expandedParentCount; 202 | } 203 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 204 | 205 | static NSString *PARENT_IDENTIFIER = @"CellReuseId_Parent"; 206 | static NSString *CHILD_CONTAINER_IDENTIFIER = @"CellReuseId_Container"; 207 | 208 | NSInteger row = indexPath.row; 209 | NSUInteger parentIndex = [self parentIndexForRow:row]; 210 | BOOL isParentCell = ![self isExpansionCell:row]; 211 | 212 | if (isParentCell) { 213 | 214 | ParentTableViewCell *cell = (ParentTableViewCell *)[self dequeueReusableCellWithIdentifier:PARENT_IDENTIFIER]; 215 | if (cell == nil) { 216 | cell = [[ParentTableViewCell alloc] initWithReuseIdentifier:PARENT_IDENTIFIER]; 217 | } 218 | 219 | cell.titleLabel.text = [self.dataSourceDelegate titleLabelForParentCellAtIndex:parentIndex]; 220 | [cell.titleLabel setFont:[UIFont boldSystemFontOfSize:19]]; 221 | 222 | cell.subtitleLabel.text = [self.dataSourceDelegate subtitleLabelForParentCellAtIndex:parentIndex]; 223 | [cell.subtitleLabel setFont:[UIFont systemFontOfSize:13]]; 224 | 225 | [cell setCellForegroundColor:[UIColor whiteColor]]; 226 | [cell setCellBackgroundColor:[UIColor colorWithWhite:( 30/255.0) alpha:1.0]]; 227 | [cell setParentIndex:parentIndex]; 228 | cell.tag = parentIndex; 229 | 230 | [self deselectCell:cell]; 231 | if ([[self.expansionStates objectAtIndex:[cell parentIndex]] boolValue]) 232 | [self selectCell:cell]; 233 | 234 | return cell; 235 | } 236 | else { 237 | 238 | ExpandedContainer *cell = (ExpandedContainer *)[self dequeueReusableCellWithIdentifier:CHILD_CONTAINER_IDENTIFIER]; 239 | if (cell == nil) { 240 | cell = [[ExpandedContainer alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CHILD_CONTAINER_IDENTIFIER]; 241 | } 242 | 243 | [cell setSubTableForegroundColor:[UIColor whiteColor]]; 244 | [cell setSubTableBackgroundColor:[UIColor colorWithWhite:( 30/255.0) alpha:1.0]]; 245 | [cell setParentIndex:parentIndex]; 246 | 247 | [cell setDelegate:self]; 248 | [cell reload]; 249 | 250 | return cell; 251 | } 252 | } 253 | 254 | 255 | 256 | #pragma mark - Table view - Cell Selection 257 | 258 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 259 | 260 | UITableViewCell *selectedPCell = [tableView cellForRowAtIndexPath:indexPath]; 261 | if ([selectedPCell isKindOfClass:[ParentTableViewCell class]]) { 262 | 263 | ParentTableViewCell *pCell = (ParentTableViewCell *)selectedPCell; 264 | self.selectedRow = [pCell parentIndex]; 265 | 266 | if ([[self.expansionStates objectAtIndex:[pCell parentIndex]] boolValue]) { 267 | 268 | // clicked an already expanded cell 269 | [self collapseForParentAtRow:indexPath.row]; 270 | [self deselectCell:pCell]; 271 | previouslySelectedCell = nil; 272 | } 273 | else { 274 | 275 | // clicked a collapsed cell 276 | [self collapseAllRows]; 277 | [self expandForParentAtRow:[pCell parentIndex]]; 278 | 279 | [self deselectCell:previouslySelectedCell]; 280 | previouslySelectedCell = pCell; 281 | [self selectCell:previouslySelectedCell]; 282 | } 283 | 284 | if ([self.tableViewDelegate respondsToSelector:@selector(tableView:didSelectParentCellAtIndex:)]) { 285 | [self.tableViewDelegate tableView:tableView didSelectParentCellAtIndex:[pCell parentIndex]]; 286 | } 287 | } 288 | } 289 | - (void)selectCell:(ParentTableViewCell *)cell { 290 | 291 | cell.titleLabel.textColor = [UIColor whiteColor]; 292 | cell.subtitleLabel.textColor = [UIColor colorWithWhite:0.98 alpha:1.0]; 293 | } 294 | - (void)deselectCell:(ParentTableViewCell *)cell { 295 | 296 | cell.titleLabel.textColor = [UIColor colorWithWhite:0.85 alpha:1.0]; 297 | cell.subtitleLabel.textColor = [UIColor colorWithWhite:0.85 alpha:1.0]; 298 | } 299 | 300 | 301 | 302 | # pragma mark - TableView - Section 303 | 304 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 305 | 306 | return 30; 307 | } 308 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 309 | 310 | return @"click to expand"; 311 | } 312 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 313 | 314 | NSString *oldSectionTitle = [self tableView:tableView titleForHeaderInSection:section]; 315 | NSString *sectionTitle = [NSString stringWithFormat:@" %@",oldSectionTitle]; 316 | if (sectionTitle == nil) { 317 | return nil; 318 | } 319 | 320 | UILabel *label = [[UILabel alloc] init]; 321 | label.frame = CGRectMake(0, 0, 320, 30); 322 | label.backgroundColor = [UIColor colorWithWhite:( 20/255.0) alpha:1.0]; 323 | label.textColor = [UIColor colorWithWhite:0.7 alpha:1.0]; 324 | label.shadowColor = [UIColor darkGrayColor]; 325 | label.shadowOffset = CGSizeMake(-1.0, 1.0); 326 | label.font = [UIFont systemFontOfSize:17]; 327 | label.text = sectionTitle; 328 | 329 | UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 28, 320, 2)]; 330 | bottomLine.backgroundColor = [UIColor colorWithWhite:( 50/255.0) alpha:1.0]; 331 | 332 | UIView *view = [[UIView alloc] init]; 333 | [view addSubview:label]; 334 | [view addSubview:bottomLine]; 335 | 336 | return view; 337 | } 338 | 339 | 340 | 341 | #pragma mark - SubRow Delegate 342 | 343 | // @required 344 | - (NSInteger)numberOfChildrenUnderParentIndex:(NSInteger)parentIndex { 345 | 346 | return [self.dataSourceDelegate numberOfChildCellsUnderParentIndex:parentIndex]; 347 | } 348 | - (NSInteger)heightForChildRows { 349 | 350 | return [self.dataSourceDelegate heightForChildRows]; 351 | } 352 | 353 | // @optional 354 | - (void)didSelectRowAtChildIndex:(NSInteger)childIndex 355 | underParentIndex:(NSInteger)parentIndex { 356 | 357 | NSIndexPath * indexPath = [NSIndexPath indexPathForRow:[self rowForParentIndex:parentIndex] inSection:0]; 358 | UITableViewCell *selectedCell = [self cellForRowAtIndexPath:indexPath]; 359 | if ([selectedCell isKindOfClass:[ParentTableViewCell class]]) { 360 | 361 | // ParentTableViewCell * pCell = (ParentTableViewCell *)selectedCell; 362 | 363 | // Insert code here to detect and handle child cell selection 364 | // ... 365 | } 366 | } 367 | - (NSString *)titleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex { 368 | 369 | return [self.dataSourceDelegate titleLabelForCellAtChildIndex:childIndex withinParentCellIndex:parentIndex]; 370 | } 371 | - (NSString *)subtitleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex { 372 | 373 | return [self.dataSourceDelegate subtitleLabelForCellAtChildIndex:childIndex withinParentCellIndex:parentIndex]; 374 | } 375 | 376 | @end 377 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample/SubTable/ParentTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // ParentTableView.m 3 | // SubTableExample 4 | // 5 | // Created by Alex Koshy on 7/16/14. 6 | // Copyright (c) 2014 ajkoshy7. All rights reserved. 7 | // 8 | 9 | #import "ParentTableView.h" 10 | #import "ParentTableViewCell.h" 11 | #import "ExpandedContainer.h" 12 | 13 | @interface ParentTableView () { 14 | 15 | ParentTableViewCell *previouslySelectedCell; 16 | } 17 | 18 | @end 19 | 20 | @implementation ParentTableView 21 | @synthesize tableViewDelegate, expansionStates; 22 | 23 | - (id)initWithFrame:(CGRect)frame dataSource:dataDelegate tableViewDelegate:tableDelegate { 24 | 25 | self = [super initWithFrame:frame style:UITableViewStylePlain]; 26 | if (self) { 27 | // Initialization code 28 | [self initialize]; 29 | } 30 | return self; 31 | } 32 | - (id)initWithCoder:(NSCoder *)coder { 33 | 34 | self = [super initWithCoder:coder]; 35 | if (self) { 36 | // Initialization code 37 | [self initialize]; 38 | } 39 | return self; 40 | } 41 | - (void)initialize { 42 | 43 | [self setDataSource:self]; 44 | [self setDelegate:self]; 45 | 46 | self.backgroundColor = [UIColor colorWithWhite:( 20/255.0) alpha:1.0]; 47 | self.separatorStyle = UITableViewCellSeparatorStyleNone; 48 | self.separatorInset = UIEdgeInsetsMake(0, 0, 0, 0); 49 | self.separatorColor = [UIColor darkGrayColor]; 50 | 51 | UIView *footer = [[UIView alloc] initWithFrame:CGRectZero]; 52 | self.tableFooterView = footer; 53 | } 54 | 55 | 56 | 57 | #pragma mark - Configuration 58 | 59 | - (id)getDataSourceDelegate { 60 | 61 | return dataSourceDelegate; 62 | } 63 | - (void)setDataSourceDelegate:(id)deleg { 64 | 65 | dataSourceDelegate = deleg; 66 | [self initExpansionStates]; 67 | } 68 | - (void)initExpansionStates { 69 | 70 | expansionStates = [[NSMutableArray alloc] initWithCapacity:[self.dataSourceDelegate numberOfParentCells]]; 71 | for(int i = 0; i < [self.dataSourceDelegate numberOfParentCells]; i++) { 72 | [expansionStates addObject:@"NO"]; 73 | } 74 | } 75 | 76 | 77 | 78 | #pragma mark - Table Interaction 79 | 80 | - (void)expandForParentAtRow:(NSInteger)row { 81 | 82 | NSUInteger parentIndex = [self parentIndexForRow:row]; 83 | 84 | if ([[self.expansionStates objectAtIndex:parentIndex] boolValue]) { 85 | return; 86 | } 87 | 88 | // update expansionStates so backing data is ready before calling insertRowsAtIndexPaths 89 | [self.expansionStates replaceObjectAtIndex:parentIndex withObject:@"YES"]; 90 | [self insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; 91 | } 92 | - (void)collapseForParentAtRow:(NSInteger)row { 93 | 94 | if (![self.dataSourceDelegate numberOfParentCells] > 0) { 95 | return; 96 | } 97 | 98 | NSUInteger parentIndex = [self parentIndexForRow:row]; 99 | 100 | if (![[self.expansionStates objectAtIndex:parentIndex] boolValue]) { 101 | return; 102 | } 103 | 104 | // update expansionStates so backing data is ready before calling deleteRowsAtIndexPaths 105 | [self.expansionStates replaceObjectAtIndex:parentIndex withObject:@"NO"]; 106 | [self deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; 107 | } 108 | - (void)collapseAllRows { 109 | 110 | if ([self.expansionStates containsObject:@"YES"]) { 111 | 112 | NSInteger row = [self.expansionStates indexOfObject:@"YES"]; 113 | 114 | [self.expansionStates replaceObjectAtIndex:row withObject:@"NO"]; 115 | [self deleteRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade]; 116 | } 117 | } 118 | 119 | 120 | 121 | #pragma mark - Table Information 122 | 123 | - (NSUInteger)rowForParentIndex:(NSUInteger)parentIndex { 124 | 125 | NSUInteger row = 0; 126 | NSUInteger currentParentIndex = 0; 127 | 128 | if (parentIndex == 0) { 129 | return 0; 130 | } 131 | 132 | while (currentParentIndex < parentIndex) { 133 | BOOL expanded = [[self.expansionStates objectAtIndex:currentParentIndex] boolValue]; 134 | if (expanded) { 135 | row++; 136 | } 137 | currentParentIndex++; 138 | row++; 139 | } 140 | return row; 141 | } 142 | - (NSUInteger)parentIndexForRow:(NSUInteger)row { 143 | 144 | NSUInteger parentIndex = -1; 145 | 146 | NSUInteger i = 0; 147 | while (i <= row) { 148 | parentIndex++; 149 | i++; 150 | if ([[self.expansionStates objectAtIndex:parentIndex] boolValue]) { 151 | i++; 152 | } 153 | } 154 | return parentIndex; 155 | } 156 | - (BOOL)isExpansionCell:(NSUInteger)row { 157 | 158 | if (row < 1) { 159 | return NO; 160 | } 161 | NSUInteger parentIndex = [self parentIndexForRow:row]; 162 | NSUInteger parentIndex2 = [self parentIndexForRow:(row-1)]; 163 | return (parentIndex == parentIndex2); 164 | } 165 | 166 | 167 | 168 | #pragma mark - UITableViewDataSource 169 | 170 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath { 171 | 172 | NSInteger row = indexPath.row; 173 | NSInteger rowHeight = [self.dataSourceDelegate heightForParentRows]; 174 | 175 | BOOL isExpansionCell = [self isExpansionCell:row]; 176 | if (isExpansionCell) { 177 | 178 | NSInteger parentIndex = [self parentIndexForRow:row]; 179 | NSInteger numberOfChildren = [self.dataSourceDelegate numberOfChildCellsUnderParentIndex:parentIndex]; 180 | NSInteger childRowHeight = [self.dataSourceDelegate heightForChildRows]; 181 | return childRowHeight * numberOfChildren; 182 | } 183 | else 184 | return rowHeight; 185 | } 186 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView { 187 | 188 | return 1; 189 | } 190 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section { 191 | 192 | if (![self.dataSourceDelegate numberOfParentCells] > 0) { 193 | return 0; 194 | } 195 | 196 | // returns sum of parent cells and expanded cells 197 | NSInteger parentCount = [self.dataSourceDelegate numberOfParentCells]; 198 | NSCountedSet *countedSet = [[NSCountedSet alloc] initWithArray:self.expansionStates]; 199 | NSUInteger expandedParentCount = [countedSet countForObject:@"YES"]; 200 | 201 | return parentCount + expandedParentCount; 202 | } 203 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath { 204 | 205 | static NSString *PARENT_IDENTIFIER = @"CellReuseId_Parent"; 206 | static NSString *CHILD_CONTAINER_IDENTIFIER = @"CellReuseId_Container"; 207 | 208 | NSInteger row = indexPath.row; 209 | NSUInteger parentIndex = [self parentIndexForRow:row]; 210 | BOOL isParentCell = ![self isExpansionCell:row]; 211 | 212 | if (isParentCell) { 213 | 214 | ParentTableViewCell *cell = (ParentTableViewCell *)[self dequeueReusableCellWithIdentifier:PARENT_IDENTIFIER]; 215 | if (cell == nil) { 216 | cell = [[ParentTableViewCell alloc] initWithReuseIdentifier:PARENT_IDENTIFIER]; 217 | } 218 | 219 | cell.titleLabel.text = [self.dataSourceDelegate titleLabelForParentCellAtIndex:parentIndex]; 220 | [cell.titleLabel setFont:[UIFont boldSystemFontOfSize:19]]; 221 | 222 | cell.subtitleLabel.text = [self.dataSourceDelegate subtitleLabelForParentCellAtIndex:parentIndex]; 223 | [cell.subtitleLabel setFont:[UIFont systemFontOfSize:13]]; 224 | 225 | [cell setCellForegroundColor:[UIColor whiteColor]]; 226 | [cell setCellBackgroundColor:[UIColor colorWithWhite:( 30/255.0) alpha:1.0]]; 227 | [cell setParentIndex:parentIndex]; 228 | cell.tag = parentIndex; 229 | 230 | [self deselectCell:cell]; 231 | if ([[self.expansionStates objectAtIndex:[cell parentIndex]] boolValue]) 232 | [self selectCell:cell]; 233 | 234 | return cell; 235 | } 236 | else { 237 | 238 | ExpandedContainer *cell = (ExpandedContainer *)[self dequeueReusableCellWithIdentifier:CHILD_CONTAINER_IDENTIFIER]; 239 | if (cell == nil) { 240 | cell = [[ExpandedContainer alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CHILD_CONTAINER_IDENTIFIER]; 241 | } 242 | 243 | [cell setSubTableForegroundColor:[UIColor whiteColor]]; 244 | [cell setSubTableBackgroundColor:[UIColor colorWithWhite:( 30/255.0) alpha:1.0]]; 245 | [cell setParentIndex:parentIndex]; 246 | 247 | [cell setDelegate:self]; 248 | [cell reload]; 249 | 250 | return cell; 251 | } 252 | } 253 | 254 | 255 | 256 | #pragma mark - Table view - Cell Selection 257 | 258 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath { 259 | 260 | UITableViewCell *selectedPCell = [tableView cellForRowAtIndexPath:indexPath]; 261 | if ([selectedPCell isKindOfClass:[ParentTableViewCell class]]) { 262 | 263 | ParentTableViewCell *pCell = (ParentTableViewCell *)selectedPCell; 264 | self.selectedRow = [pCell parentIndex]; 265 | 266 | if ([[self.expansionStates objectAtIndex:[pCell parentIndex]] boolValue]) { 267 | 268 | // clicked an already expanded cell 269 | [self collapseForParentAtRow:indexPath.row]; 270 | [self deselectCell:pCell]; 271 | previouslySelectedCell = nil; 272 | } 273 | else { 274 | 275 | // clicked a collapsed cell 276 | [self collapseAllRows]; 277 | [self expandForParentAtRow:[pCell parentIndex]]; 278 | 279 | [self deselectCell:previouslySelectedCell]; 280 | previouslySelectedCell = pCell; 281 | [self selectCell:previouslySelectedCell]; 282 | } 283 | 284 | if ([self.tableViewDelegate respondsToSelector:@selector(tableView:didSelectParentCellAtIndex:)]) { 285 | [self.tableViewDelegate tableView:tableView didSelectParentCellAtIndex:[pCell parentIndex]]; 286 | } 287 | } 288 | } 289 | - (void)selectCell:(ParentTableViewCell *)cell { 290 | 291 | cell.titleLabel.textColor = [UIColor whiteColor]; 292 | cell.subtitleLabel.textColor = [UIColor colorWithWhite:0.98 alpha:1.0]; 293 | } 294 | - (void)deselectCell:(ParentTableViewCell *)cell { 295 | 296 | cell.titleLabel.textColor = [UIColor colorWithWhite:0.85 alpha:1.0]; 297 | cell.subtitleLabel.textColor = [UIColor colorWithWhite:0.85 alpha:1.0]; 298 | } 299 | 300 | 301 | 302 | # pragma mark - TableView - Section 303 | 304 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section { 305 | 306 | return 30; 307 | } 308 | - (NSString *)tableView:(UITableView *)tableView titleForHeaderInSection:(NSInteger)section { 309 | 310 | return @"click to expand"; 311 | } 312 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section { 313 | 314 | NSString *oldSectionTitle = [self tableView:tableView titleForHeaderInSection:section]; 315 | NSString *sectionTitle = [NSString stringWithFormat:@" %@",oldSectionTitle]; 316 | if (sectionTitle == nil) { 317 | return nil; 318 | } 319 | 320 | UILabel *label = [[UILabel alloc] init]; 321 | label.frame = CGRectMake(0, 0, 320, 30); 322 | label.backgroundColor = [UIColor colorWithWhite:( 20/255.0) alpha:1.0]; 323 | label.textColor = [UIColor colorWithWhite:0.7 alpha:1.0]; 324 | label.shadowColor = [UIColor darkGrayColor]; 325 | label.shadowOffset = CGSizeMake(-1.0, 1.0); 326 | label.font = [UIFont systemFontOfSize:17]; 327 | label.text = sectionTitle; 328 | 329 | UIImageView *bottomLine = [[UIImageView alloc] initWithFrame:CGRectMake(0, 28, 320, 2)]; 330 | bottomLine.backgroundColor = [UIColor colorWithWhite:( 50/255.0) alpha:1.0]; 331 | 332 | UIView *view = [[UIView alloc] init]; 333 | [view addSubview:label]; 334 | [view addSubview:bottomLine]; 335 | 336 | return view; 337 | } 338 | 339 | 340 | 341 | #pragma mark - SubRow Delegate 342 | 343 | // @required 344 | - (NSInteger)numberOfChildrenUnderParentIndex:(NSInteger)parentIndex { 345 | 346 | return [self.dataSourceDelegate numberOfChildCellsUnderParentIndex:parentIndex]; 347 | } 348 | - (NSInteger)heightForChildRows { 349 | 350 | return [self.dataSourceDelegate heightForChildRows]; 351 | } 352 | 353 | // @optional 354 | - (void)didSelectRowAtChildIndex:(NSInteger)childIndex 355 | underParentIndex:(NSInteger)parentIndex { 356 | 357 | NSIndexPath * indexPath = [NSIndexPath indexPathForRow:[self rowForParentIndex:parentIndex] inSection:0]; 358 | UITableViewCell *selectedCell = [self cellForRowAtIndexPath:indexPath]; 359 | if ([selectedCell isKindOfClass:[ParentTableViewCell class]]) { 360 | 361 | // ParentTableViewCell * pCell = (ParentTableViewCell *)selectedCell; 362 | 363 | // Insert code here to detect and handle child cell selection 364 | // ... 365 | } 366 | } 367 | - (NSString *)titleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex { 368 | 369 | return [self.dataSourceDelegate titleLabelForCellAtChildIndex:childIndex withinParentCellIndex:parentIndex]; 370 | } 371 | - (NSString *)subtitleLabelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex { 372 | 373 | return [self.dataSourceDelegate subtitleLabelForCellAtChildIndex:childIndex withinParentCellIndex:parentIndex]; 374 | } 375 | 376 | @end 377 | -------------------------------------------------------------------------------- /SubTableExample/SubTableExample.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | FA4FB0DC1978D53800CAE647 /* ExpandedContainer.m in Sources */ = {isa = PBXBuildFile; fileRef = FA4FB0DB1978D53800CAE647 /* ExpandedContainer.m */; }; 11 | FAEF41A1197751FE00DC189F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAEF41A0197751FE00DC189F /* Foundation.framework */; }; 12 | FAEF41A3197751FE00DC189F /* CoreGraphics.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAEF41A2197751FE00DC189F /* CoreGraphics.framework */; }; 13 | FAEF41A5197751FE00DC189F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAEF41A4197751FE00DC189F /* UIKit.framework */; }; 14 | FAEF41AB197751FE00DC189F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FAEF41A9197751FE00DC189F /* InfoPlist.strings */; }; 15 | FAEF41AD197751FE00DC189F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41AC197751FE00DC189F /* main.m */; }; 16 | FAEF41B1197751FE00DC189F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41B0197751FE00DC189F /* AppDelegate.m */; }; 17 | FAEF41B3197751FE00DC189F /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = FAEF41B2197751FE00DC189F /* Images.xcassets */; }; 18 | FAEF41BA197751FE00DC189F /* XCTest.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAEF41B9197751FE00DC189F /* XCTest.framework */; }; 19 | FAEF41BB197751FE00DC189F /* Foundation.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAEF41A0197751FE00DC189F /* Foundation.framework */; }; 20 | FAEF41BC197751FE00DC189F /* UIKit.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = FAEF41A4197751FE00DC189F /* UIKit.framework */; }; 21 | FAEF41C4197751FE00DC189F /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = FAEF41C2197751FE00DC189F /* InfoPlist.strings */; }; 22 | FAEF41C6197751FE00DC189F /* SubTableExampleTests.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41C5197751FE00DC189F /* SubTableExampleTests.m */; }; 23 | FAEF41E0197752D800DC189F /* ParentTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41D1197752D800DC189F /* ParentTableView.m */; }; 24 | FAEF41E1197752D800DC189F /* ParentTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41D4197752D800DC189F /* ParentTableViewCell.m */; }; 25 | FAEF41E2197752D800DC189F /* SubTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41D7197752D800DC189F /* SubTableView.m */; }; 26 | FAEF41E3197752D800DC189F /* SubTableViewCell.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41DA197752D800DC189F /* SubTableViewCell.m */; }; 27 | FAEF41E91977530800DC189F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = FAEF41E71977530800DC189F /* ViewController.m */; }; 28 | FAEF41EA1977530800DC189F /* ViewController.xib in Resources */ = {isa = PBXBuildFile; fileRef = FAEF41E81977530800DC189F /* ViewController.xib */; }; 29 | /* End PBXBuildFile section */ 30 | 31 | /* Begin PBXContainerItemProxy section */ 32 | FAEF41BD197751FE00DC189F /* PBXContainerItemProxy */ = { 33 | isa = PBXContainerItemProxy; 34 | containerPortal = FAEF4195197751FE00DC189F /* Project object */; 35 | proxyType = 1; 36 | remoteGlobalIDString = FAEF419C197751FE00DC189F; 37 | remoteInfo = SubTableExample; 38 | }; 39 | /* End PBXContainerItemProxy section */ 40 | 41 | /* Begin PBXFileReference section */ 42 | FA4FB0DA1978D53800CAE647 /* ExpandedContainer.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ExpandedContainer.h; sourceTree = ""; }; 43 | FA4FB0DB1978D53800CAE647 /* ExpandedContainer.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ExpandedContainer.m; sourceTree = ""; }; 44 | FAEF419D197751FE00DC189F /* SubTableExample.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = SubTableExample.app; sourceTree = BUILT_PRODUCTS_DIR; }; 45 | FAEF41A0197751FE00DC189F /* Foundation.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = Foundation.framework; path = System/Library/Frameworks/Foundation.framework; sourceTree = SDKROOT; }; 46 | FAEF41A2197751FE00DC189F /* CoreGraphics.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = CoreGraphics.framework; path = System/Library/Frameworks/CoreGraphics.framework; sourceTree = SDKROOT; }; 47 | FAEF41A4197751FE00DC189F /* UIKit.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = UIKit.framework; path = System/Library/Frameworks/UIKit.framework; sourceTree = SDKROOT; }; 48 | FAEF41A8197751FE00DC189F /* SubTableExample-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SubTableExample-Info.plist"; sourceTree = ""; }; 49 | FAEF41AA197751FE00DC189F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 50 | FAEF41AC197751FE00DC189F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 51 | FAEF41AE197751FE00DC189F /* SubTableExample-Prefix.pch */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = "SubTableExample-Prefix.pch"; sourceTree = ""; }; 52 | FAEF41AF197751FE00DC189F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 53 | FAEF41B0197751FE00DC189F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 54 | FAEF41B2197751FE00DC189F /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 55 | FAEF41B8197751FE00DC189F /* SubTableExampleTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = SubTableExampleTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; 56 | FAEF41B9197751FE00DC189F /* XCTest.framework */ = {isa = PBXFileReference; lastKnownFileType = wrapper.framework; name = XCTest.framework; path = Library/Frameworks/XCTest.framework; sourceTree = DEVELOPER_DIR; }; 57 | FAEF41C1197751FE00DC189F /* SubTableExampleTests-Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = "SubTableExampleTests-Info.plist"; sourceTree = ""; }; 58 | FAEF41C3197751FE00DC189F /* en */ = {isa = PBXFileReference; lastKnownFileType = text.plist.strings; name = en; path = en.lproj/InfoPlist.strings; sourceTree = ""; }; 59 | FAEF41C5197751FE00DC189F /* SubTableExampleTests.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = SubTableExampleTests.m; sourceTree = ""; }; 60 | FAEF41D0197752D800DC189F /* ParentTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParentTableView.h; sourceTree = ""; }; 61 | FAEF41D1197752D800DC189F /* ParentTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParentTableView.m; sourceTree = ""; }; 62 | FAEF41D3197752D800DC189F /* ParentTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ParentTableViewCell.h; sourceTree = ""; }; 63 | FAEF41D4197752D800DC189F /* ParentTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ParentTableViewCell.m; sourceTree = ""; }; 64 | FAEF41D6197752D800DC189F /* SubTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubTableView.h; sourceTree = ""; }; 65 | FAEF41D7197752D800DC189F /* SubTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SubTableView.m; sourceTree = ""; }; 66 | FAEF41D9197752D800DC189F /* SubTableViewCell.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = SubTableViewCell.h; sourceTree = ""; }; 67 | FAEF41DA197752D800DC189F /* SubTableViewCell.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = SubTableViewCell.m; sourceTree = ""; }; 68 | FAEF41E61977530800DC189F /* ViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 69 | FAEF41E71977530800DC189F /* ViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 70 | FAEF41E81977530800DC189F /* ViewController.xib */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.xib; path = ViewController.xib; sourceTree = ""; }; 71 | /* End PBXFileReference section */ 72 | 73 | /* Begin PBXFrameworksBuildPhase section */ 74 | FAEF419A197751FE00DC189F /* Frameworks */ = { 75 | isa = PBXFrameworksBuildPhase; 76 | buildActionMask = 2147483647; 77 | files = ( 78 | FAEF41A3197751FE00DC189F /* CoreGraphics.framework in Frameworks */, 79 | FAEF41A5197751FE00DC189F /* UIKit.framework in Frameworks */, 80 | FAEF41A1197751FE00DC189F /* Foundation.framework in Frameworks */, 81 | ); 82 | runOnlyForDeploymentPostprocessing = 0; 83 | }; 84 | FAEF41B5197751FE00DC189F /* Frameworks */ = { 85 | isa = PBXFrameworksBuildPhase; 86 | buildActionMask = 2147483647; 87 | files = ( 88 | FAEF41BA197751FE00DC189F /* XCTest.framework in Frameworks */, 89 | FAEF41BC197751FE00DC189F /* UIKit.framework in Frameworks */, 90 | FAEF41BB197751FE00DC189F /* Foundation.framework in Frameworks */, 91 | ); 92 | runOnlyForDeploymentPostprocessing = 0; 93 | }; 94 | /* End PBXFrameworksBuildPhase section */ 95 | 96 | /* Begin PBXGroup section */ 97 | FAEF4194197751FE00DC189F = { 98 | isa = PBXGroup; 99 | children = ( 100 | FAEF41A6197751FE00DC189F /* SubTableExample */, 101 | FAEF41BF197751FE00DC189F /* SubTableExampleTests */, 102 | FAEF419F197751FE00DC189F /* Frameworks */, 103 | FAEF419E197751FE00DC189F /* Products */, 104 | ); 105 | sourceTree = ""; 106 | }; 107 | FAEF419E197751FE00DC189F /* Products */ = { 108 | isa = PBXGroup; 109 | children = ( 110 | FAEF419D197751FE00DC189F /* SubTableExample.app */, 111 | FAEF41B8197751FE00DC189F /* SubTableExampleTests.xctest */, 112 | ); 113 | name = Products; 114 | sourceTree = ""; 115 | }; 116 | FAEF419F197751FE00DC189F /* Frameworks */ = { 117 | isa = PBXGroup; 118 | children = ( 119 | FAEF41A0197751FE00DC189F /* Foundation.framework */, 120 | FAEF41A2197751FE00DC189F /* CoreGraphics.framework */, 121 | FAEF41A4197751FE00DC189F /* UIKit.framework */, 122 | FAEF41B9197751FE00DC189F /* XCTest.framework */, 123 | ); 124 | name = Frameworks; 125 | sourceTree = ""; 126 | }; 127 | FAEF41A6197751FE00DC189F /* SubTableExample */ = { 128 | isa = PBXGroup; 129 | children = ( 130 | FAEF41AF197751FE00DC189F /* AppDelegate.h */, 131 | FAEF41B0197751FE00DC189F /* AppDelegate.m */, 132 | FAEF41E61977530800DC189F /* ViewController.h */, 133 | FAEF41E71977530800DC189F /* ViewController.m */, 134 | FAEF41E81977530800DC189F /* ViewController.xib */, 135 | FAEF41CF197752D800DC189F /* SubTable */, 136 | FAEF41B2197751FE00DC189F /* Images.xcassets */, 137 | FAEF41A7197751FE00DC189F /* Supporting Files */, 138 | ); 139 | path = SubTableExample; 140 | sourceTree = ""; 141 | }; 142 | FAEF41A7197751FE00DC189F /* Supporting Files */ = { 143 | isa = PBXGroup; 144 | children = ( 145 | FAEF41A8197751FE00DC189F /* SubTableExample-Info.plist */, 146 | FAEF41A9197751FE00DC189F /* InfoPlist.strings */, 147 | FAEF41AC197751FE00DC189F /* main.m */, 148 | FAEF41AE197751FE00DC189F /* SubTableExample-Prefix.pch */, 149 | ); 150 | name = "Supporting Files"; 151 | sourceTree = ""; 152 | }; 153 | FAEF41BF197751FE00DC189F /* SubTableExampleTests */ = { 154 | isa = PBXGroup; 155 | children = ( 156 | FAEF41C5197751FE00DC189F /* SubTableExampleTests.m */, 157 | FAEF41C0197751FE00DC189F /* Supporting Files */, 158 | ); 159 | path = SubTableExampleTests; 160 | sourceTree = ""; 161 | }; 162 | FAEF41C0197751FE00DC189F /* Supporting Files */ = { 163 | isa = PBXGroup; 164 | children = ( 165 | FAEF41C1197751FE00DC189F /* SubTableExampleTests-Info.plist */, 166 | FAEF41C2197751FE00DC189F /* InfoPlist.strings */, 167 | ); 168 | name = "Supporting Files"; 169 | sourceTree = ""; 170 | }; 171 | FAEF41CF197752D800DC189F /* SubTable */ = { 172 | isa = PBXGroup; 173 | children = ( 174 | FAEF41D0197752D800DC189F /* ParentTableView.h */, 175 | FAEF41D1197752D800DC189F /* ParentTableView.m */, 176 | FAEF41D2197752D800DC189F /* ParentCell */, 177 | FAEF41D5197752D800DC189F /* SubRow */, 178 | ); 179 | path = SubTable; 180 | sourceTree = ""; 181 | }; 182 | FAEF41D2197752D800DC189F /* ParentCell */ = { 183 | isa = PBXGroup; 184 | children = ( 185 | FAEF41D3197752D800DC189F /* ParentTableViewCell.h */, 186 | FAEF41D4197752D800DC189F /* ParentTableViewCell.m */, 187 | ); 188 | path = ParentCell; 189 | sourceTree = ""; 190 | }; 191 | FAEF41D5197752D800DC189F /* SubRow */ = { 192 | isa = PBXGroup; 193 | children = ( 194 | FA4FB0DA1978D53800CAE647 /* ExpandedContainer.h */, 195 | FA4FB0DB1978D53800CAE647 /* ExpandedContainer.m */, 196 | FAEF41D6197752D800DC189F /* SubTableView.h */, 197 | FAEF41D7197752D800DC189F /* SubTableView.m */, 198 | FAEF41D8197752D800DC189F /* ChildCell */, 199 | ); 200 | path = SubRow; 201 | sourceTree = ""; 202 | }; 203 | FAEF41D8197752D800DC189F /* ChildCell */ = { 204 | isa = PBXGroup; 205 | children = ( 206 | FAEF41D9197752D800DC189F /* SubTableViewCell.h */, 207 | FAEF41DA197752D800DC189F /* SubTableViewCell.m */, 208 | ); 209 | path = ChildCell; 210 | sourceTree = ""; 211 | }; 212 | /* End PBXGroup section */ 213 | 214 | /* Begin PBXNativeTarget section */ 215 | FAEF419C197751FE00DC189F /* SubTableExample */ = { 216 | isa = PBXNativeTarget; 217 | buildConfigurationList = FAEF41C9197751FE00DC189F /* Build configuration list for PBXNativeTarget "SubTableExample" */; 218 | buildPhases = ( 219 | FAEF4199197751FE00DC189F /* Sources */, 220 | FAEF419A197751FE00DC189F /* Frameworks */, 221 | FAEF419B197751FE00DC189F /* Resources */, 222 | ); 223 | buildRules = ( 224 | ); 225 | dependencies = ( 226 | ); 227 | name = SubTableExample; 228 | productName = SubTableExample; 229 | productReference = FAEF419D197751FE00DC189F /* SubTableExample.app */; 230 | productType = "com.apple.product-type.application"; 231 | }; 232 | FAEF41B7197751FE00DC189F /* SubTableExampleTests */ = { 233 | isa = PBXNativeTarget; 234 | buildConfigurationList = FAEF41CC197751FE00DC189F /* Build configuration list for PBXNativeTarget "SubTableExampleTests" */; 235 | buildPhases = ( 236 | FAEF41B4197751FE00DC189F /* Sources */, 237 | FAEF41B5197751FE00DC189F /* Frameworks */, 238 | FAEF41B6197751FE00DC189F /* Resources */, 239 | ); 240 | buildRules = ( 241 | ); 242 | dependencies = ( 243 | FAEF41BE197751FE00DC189F /* PBXTargetDependency */, 244 | ); 245 | name = SubTableExampleTests; 246 | productName = SubTableExampleTests; 247 | productReference = FAEF41B8197751FE00DC189F /* SubTableExampleTests.xctest */; 248 | productType = "com.apple.product-type.bundle.unit-test"; 249 | }; 250 | /* End PBXNativeTarget section */ 251 | 252 | /* Begin PBXProject section */ 253 | FAEF4195197751FE00DC189F /* Project object */ = { 254 | isa = PBXProject; 255 | attributes = { 256 | LastUpgradeCheck = 0510; 257 | ORGANIZATIONNAME = ajkoshy7; 258 | TargetAttributes = { 259 | FAEF41B7197751FE00DC189F = { 260 | TestTargetID = FAEF419C197751FE00DC189F; 261 | }; 262 | }; 263 | }; 264 | buildConfigurationList = FAEF4198197751FE00DC189F /* Build configuration list for PBXProject "SubTableExample" */; 265 | compatibilityVersion = "Xcode 3.2"; 266 | developmentRegion = English; 267 | hasScannedForEncodings = 0; 268 | knownRegions = ( 269 | en, 270 | ); 271 | mainGroup = FAEF4194197751FE00DC189F; 272 | productRefGroup = FAEF419E197751FE00DC189F /* Products */; 273 | projectDirPath = ""; 274 | projectRoot = ""; 275 | targets = ( 276 | FAEF419C197751FE00DC189F /* SubTableExample */, 277 | FAEF41B7197751FE00DC189F /* SubTableExampleTests */, 278 | ); 279 | }; 280 | /* End PBXProject section */ 281 | 282 | /* Begin PBXResourcesBuildPhase section */ 283 | FAEF419B197751FE00DC189F /* Resources */ = { 284 | isa = PBXResourcesBuildPhase; 285 | buildActionMask = 2147483647; 286 | files = ( 287 | FAEF41AB197751FE00DC189F /* InfoPlist.strings in Resources */, 288 | FAEF41EA1977530800DC189F /* ViewController.xib in Resources */, 289 | FAEF41B3197751FE00DC189F /* Images.xcassets in Resources */, 290 | ); 291 | runOnlyForDeploymentPostprocessing = 0; 292 | }; 293 | FAEF41B6197751FE00DC189F /* Resources */ = { 294 | isa = PBXResourcesBuildPhase; 295 | buildActionMask = 2147483647; 296 | files = ( 297 | FAEF41C4197751FE00DC189F /* InfoPlist.strings in Resources */, 298 | ); 299 | runOnlyForDeploymentPostprocessing = 0; 300 | }; 301 | /* End PBXResourcesBuildPhase section */ 302 | 303 | /* Begin PBXSourcesBuildPhase section */ 304 | FAEF4199197751FE00DC189F /* Sources */ = { 305 | isa = PBXSourcesBuildPhase; 306 | buildActionMask = 2147483647; 307 | files = ( 308 | FAEF41E91977530800DC189F /* ViewController.m in Sources */, 309 | FAEF41B1197751FE00DC189F /* AppDelegate.m in Sources */, 310 | FA4FB0DC1978D53800CAE647 /* ExpandedContainer.m in Sources */, 311 | FAEF41E2197752D800DC189F /* SubTableView.m in Sources */, 312 | FAEF41E0197752D800DC189F /* ParentTableView.m in Sources */, 313 | FAEF41E1197752D800DC189F /* ParentTableViewCell.m in Sources */, 314 | FAEF41AD197751FE00DC189F /* main.m in Sources */, 315 | FAEF41E3197752D800DC189F /* SubTableViewCell.m in Sources */, 316 | ); 317 | runOnlyForDeploymentPostprocessing = 0; 318 | }; 319 | FAEF41B4197751FE00DC189F /* Sources */ = { 320 | isa = PBXSourcesBuildPhase; 321 | buildActionMask = 2147483647; 322 | files = ( 323 | FAEF41C6197751FE00DC189F /* SubTableExampleTests.m in Sources */, 324 | ); 325 | runOnlyForDeploymentPostprocessing = 0; 326 | }; 327 | /* End PBXSourcesBuildPhase section */ 328 | 329 | /* Begin PBXTargetDependency section */ 330 | FAEF41BE197751FE00DC189F /* PBXTargetDependency */ = { 331 | isa = PBXTargetDependency; 332 | target = FAEF419C197751FE00DC189F /* SubTableExample */; 333 | targetProxy = FAEF41BD197751FE00DC189F /* PBXContainerItemProxy */; 334 | }; 335 | /* End PBXTargetDependency section */ 336 | 337 | /* Begin PBXVariantGroup section */ 338 | FAEF41A9197751FE00DC189F /* InfoPlist.strings */ = { 339 | isa = PBXVariantGroup; 340 | children = ( 341 | FAEF41AA197751FE00DC189F /* en */, 342 | ); 343 | name = InfoPlist.strings; 344 | sourceTree = ""; 345 | }; 346 | FAEF41C2197751FE00DC189F /* InfoPlist.strings */ = { 347 | isa = PBXVariantGroup; 348 | children = ( 349 | FAEF41C3197751FE00DC189F /* en */, 350 | ); 351 | name = InfoPlist.strings; 352 | sourceTree = ""; 353 | }; 354 | /* End PBXVariantGroup section */ 355 | 356 | /* Begin XCBuildConfiguration section */ 357 | FAEF41C7197751FE00DC189F /* Debug */ = { 358 | isa = XCBuildConfiguration; 359 | buildSettings = { 360 | ALWAYS_SEARCH_USER_PATHS = NO; 361 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 362 | CLANG_CXX_LIBRARY = "libc++"; 363 | CLANG_ENABLE_MODULES = YES; 364 | CLANG_ENABLE_OBJC_ARC = YES; 365 | CLANG_WARN_BOOL_CONVERSION = YES; 366 | CLANG_WARN_CONSTANT_CONVERSION = YES; 367 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 368 | CLANG_WARN_EMPTY_BODY = YES; 369 | CLANG_WARN_ENUM_CONVERSION = YES; 370 | CLANG_WARN_INT_CONVERSION = YES; 371 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 372 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 373 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 374 | COPY_PHASE_STRIP = NO; 375 | GCC_C_LANGUAGE_STANDARD = gnu99; 376 | GCC_DYNAMIC_NO_PIC = NO; 377 | GCC_OPTIMIZATION_LEVEL = 0; 378 | GCC_PREPROCESSOR_DEFINITIONS = ( 379 | "DEBUG=1", 380 | "$(inherited)", 381 | ); 382 | GCC_SYMBOLS_PRIVATE_EXTERN = NO; 383 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 384 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 385 | GCC_WARN_UNDECLARED_SELECTOR = YES; 386 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 387 | GCC_WARN_UNUSED_FUNCTION = YES; 388 | GCC_WARN_UNUSED_VARIABLE = YES; 389 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 390 | ONLY_ACTIVE_ARCH = YES; 391 | SDKROOT = iphoneos; 392 | TARGETED_DEVICE_FAMILY = "1,2"; 393 | }; 394 | name = Debug; 395 | }; 396 | FAEF41C8197751FE00DC189F /* Release */ = { 397 | isa = XCBuildConfiguration; 398 | buildSettings = { 399 | ALWAYS_SEARCH_USER_PATHS = NO; 400 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 401 | CLANG_CXX_LIBRARY = "libc++"; 402 | CLANG_ENABLE_MODULES = YES; 403 | CLANG_ENABLE_OBJC_ARC = YES; 404 | CLANG_WARN_BOOL_CONVERSION = YES; 405 | CLANG_WARN_CONSTANT_CONVERSION = YES; 406 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 407 | CLANG_WARN_EMPTY_BODY = YES; 408 | CLANG_WARN_ENUM_CONVERSION = YES; 409 | CLANG_WARN_INT_CONVERSION = YES; 410 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 411 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 412 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 413 | COPY_PHASE_STRIP = YES; 414 | ENABLE_NS_ASSERTIONS = NO; 415 | GCC_C_LANGUAGE_STANDARD = gnu99; 416 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 417 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 418 | GCC_WARN_UNDECLARED_SELECTOR = YES; 419 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 420 | GCC_WARN_UNUSED_FUNCTION = YES; 421 | GCC_WARN_UNUSED_VARIABLE = YES; 422 | IPHONEOS_DEPLOYMENT_TARGET = 7.1; 423 | SDKROOT = iphoneos; 424 | TARGETED_DEVICE_FAMILY = "1,2"; 425 | VALIDATE_PRODUCT = YES; 426 | }; 427 | name = Release; 428 | }; 429 | FAEF41CA197751FE00DC189F /* Debug */ = { 430 | isa = XCBuildConfiguration; 431 | buildSettings = { 432 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 433 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 434 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 435 | GCC_PREFIX_HEADER = "SubTableExample/SubTableExample-Prefix.pch"; 436 | INFOPLIST_FILE = "SubTableExample/SubTableExample-Info.plist"; 437 | PRODUCT_NAME = "$(TARGET_NAME)"; 438 | WRAPPER_EXTENSION = app; 439 | }; 440 | name = Debug; 441 | }; 442 | FAEF41CB197751FE00DC189F /* Release */ = { 443 | isa = XCBuildConfiguration; 444 | buildSettings = { 445 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 446 | ASSETCATALOG_COMPILER_LAUNCHIMAGE_NAME = LaunchImage; 447 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 448 | GCC_PREFIX_HEADER = "SubTableExample/SubTableExample-Prefix.pch"; 449 | INFOPLIST_FILE = "SubTableExample/SubTableExample-Info.plist"; 450 | PRODUCT_NAME = "$(TARGET_NAME)"; 451 | WRAPPER_EXTENSION = app; 452 | }; 453 | name = Release; 454 | }; 455 | FAEF41CD197751FE00DC189F /* Debug */ = { 456 | isa = XCBuildConfiguration; 457 | buildSettings = { 458 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SubTableExample.app/SubTableExample"; 459 | FRAMEWORK_SEARCH_PATHS = ( 460 | "$(SDKROOT)/Developer/Library/Frameworks", 461 | "$(inherited)", 462 | "$(DEVELOPER_FRAMEWORKS_DIR)", 463 | ); 464 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 465 | GCC_PREFIX_HEADER = "SubTableExample/SubTableExample-Prefix.pch"; 466 | GCC_PREPROCESSOR_DEFINITIONS = ( 467 | "DEBUG=1", 468 | "$(inherited)", 469 | ); 470 | INFOPLIST_FILE = "SubTableExampleTests/SubTableExampleTests-Info.plist"; 471 | PRODUCT_NAME = "$(TARGET_NAME)"; 472 | TEST_HOST = "$(BUNDLE_LOADER)"; 473 | WRAPPER_EXTENSION = xctest; 474 | }; 475 | name = Debug; 476 | }; 477 | FAEF41CE197751FE00DC189F /* Release */ = { 478 | isa = XCBuildConfiguration; 479 | buildSettings = { 480 | BUNDLE_LOADER = "$(BUILT_PRODUCTS_DIR)/SubTableExample.app/SubTableExample"; 481 | FRAMEWORK_SEARCH_PATHS = ( 482 | "$(SDKROOT)/Developer/Library/Frameworks", 483 | "$(inherited)", 484 | "$(DEVELOPER_FRAMEWORKS_DIR)", 485 | ); 486 | GCC_PRECOMPILE_PREFIX_HEADER = YES; 487 | GCC_PREFIX_HEADER = "SubTableExample/SubTableExample-Prefix.pch"; 488 | INFOPLIST_FILE = "SubTableExampleTests/SubTableExampleTests-Info.plist"; 489 | PRODUCT_NAME = "$(TARGET_NAME)"; 490 | TEST_HOST = "$(BUNDLE_LOADER)"; 491 | WRAPPER_EXTENSION = xctest; 492 | }; 493 | name = Release; 494 | }; 495 | /* End XCBuildConfiguration section */ 496 | 497 | /* Begin XCConfigurationList section */ 498 | FAEF4198197751FE00DC189F /* Build configuration list for PBXProject "SubTableExample" */ = { 499 | isa = XCConfigurationList; 500 | buildConfigurations = ( 501 | FAEF41C7197751FE00DC189F /* Debug */, 502 | FAEF41C8197751FE00DC189F /* Release */, 503 | ); 504 | defaultConfigurationIsVisible = 0; 505 | defaultConfigurationName = Release; 506 | }; 507 | FAEF41C9197751FE00DC189F /* Build configuration list for PBXNativeTarget "SubTableExample" */ = { 508 | isa = XCConfigurationList; 509 | buildConfigurations = ( 510 | FAEF41CA197751FE00DC189F /* Debug */, 511 | FAEF41CB197751FE00DC189F /* Release */, 512 | ); 513 | defaultConfigurationIsVisible = 0; 514 | defaultConfigurationName = Release; 515 | }; 516 | FAEF41CC197751FE00DC189F /* Build configuration list for PBXNativeTarget "SubTableExampleTests" */ = { 517 | isa = XCConfigurationList; 518 | buildConfigurations = ( 519 | FAEF41CD197751FE00DC189F /* Debug */, 520 | FAEF41CE197751FE00DC189F /* Release */, 521 | ); 522 | defaultConfigurationIsVisible = 0; 523 | defaultConfigurationName = Release; 524 | }; 525 | /* End XCConfigurationList section */ 526 | }; 527 | rootObject = FAEF4195197751FE00DC189F /* Project object */; 528 | } 529 | --------------------------------------------------------------------------------