├── LICENSE ├── README.md ├── YUFoldingTableView ├── YUFoldingSectionHeader.h ├── YUFoldingSectionHeader.m ├── YUFoldingTableView.h ├── YUFoldingTableView.m └── YUFolding_arrow.png ├── YUFoldingTableViewDemo.xcodeproj ├── project.pbxproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcuserdata │ │ └── administrator.xcuserdatad │ │ └── UserInterfaceState.xcuserstate └── xcuserdata │ └── administrator.xcuserdatad │ ├── xcdebugger │ └── Breakpoints_v2.xcbkptlist │ └── xcschemes │ ├── YUFoldingTableViewDemo.xcscheme │ └── xcschememanagement.plist └── YUFoldingTableViewDemo ├── AppDelegate.h ├── AppDelegate.m ├── Assets.xcassets └── AppIcon.appiconset │ └── Contents.json ├── Base.lproj ├── LaunchScreen.storyboard └── Main.storyboard ├── Info.plist ├── ViewController.h ├── ViewController.m ├── YUCustomHeaderView.h ├── YUCustomHeaderView.m ├── YUCustomTestController.h ├── YUCustomTestController.m ├── YUTestViewController.h ├── YUTestViewController.m ├── main.m └── 效果图 └── 效果图.gif /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 Timely 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # YUFoldingTableView 2 | 可快速集成UITableView的折叠cell 3 | # [详情请参考简书](http://www.jianshu.com/p/fa8e80766529) 4 | 5 | #效果: 6 | ![Aaron Swartz](https://github.com/XuanYuLin/YUFoldingTableView/raw/master/YUFoldingTableViewDemo/效果图/效果图.gif) 7 | # 使用步骤 8 | ## 1.导入头文件,遵守协议 9 | 10 | ``` 11 | #import "ViewController.h" 12 | #import "YUFoldingTableView.h" 13 | @interface ViewController () 14 | @property (nonatomic, weak) YUFoldingTableView *foldingTableView; 15 | @end 16 | ``` 17 | ## 2.创建YUFoldingTableView 18 | ``` 19 | self.automaticallyAdjustsScrollViewInsets = NO; 20 | YUFoldingTableView *foldingTableView = [[YUFoldingTableView alloc] initWithFrame:CGRectMake(0, 64, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height - 64)]; 21 | _foldingTableView = foldingTableView; 22 | [self.view addSubview:foldingTableView]; 23 | foldingTableView.foldingDelegate = self; 24 | // 可以设置cell默认展开,不设置的话,默认折叠 25 | foldingTableView.foldingState = YUFoldingSectionStateShow; 26 | ``` 27 | ## 3.实现YUFoldingTableView的代理,用法和UItableView类似 28 | ``` 29 | #pragma mark - YUFoldingTableViewDelegate / required(必须实现的代理) 30 | - (NSInteger )numberOfSectionForYUFoldingTableView:(YUFoldingTableView *)yuTableView 31 | { 32 | return 5; 33 | } 34 | - (NSInteger )yuFoldingTableView:(YUFoldingTableView *)yuTableView numberOfRowsInSection:(NSInteger )section 35 | { 36 | return 3; 37 | } 38 | - (CGFloat )yuFoldingTableView:(YUFoldingTableView *)yuTableView heightForHeaderInSection:(NSInteger )section 39 | { 40 | return 50; 41 | } 42 | - (CGFloat )yuFoldingTableView:(YUFoldingTableView *)yuTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 43 | { 44 | return 50; 45 | } 46 | - (UITableViewCell *)yuFoldingTableView:(YUFoldingTableView *)yuTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 47 | { 48 | static NSString *cellID = @"cellID"; 49 | UITableViewCell *cell = [yuTableView dequeueReusableCellWithIdentifier:cellID]; 50 | if (cell == nil) { 51 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; 52 | } 53 | cell.textLabel.text = [NSString stringWithFormat:@"Row %ld",indexPath.row]; 54 | return cell; 55 | } 56 | 57 | #pragma mark - YUFoldingTableViewDelegate / optional (可选择实现的) 58 | // 自定义sectionHeaderView 59 | - (UIView *)yuFoldingTableView:(UITableView *)yuTableView viewForHeaderInSection:(NSInteger)section 60 | { 61 | static NSString *headerIdentifier = @"headerIdentifier"; 62 | YUCustomHeaderView *headerFooterView = [yuTableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier]; 63 | if (headerFooterView == nil) { 64 | headerFooterView = [[YUCustomHeaderView alloc] initWithReuseIdentifier:headerIdentifier]; 65 | } 66 | headerFooterView.contentView.backgroundColor = [UIColor colorWithRed:200/255.0 green:200/255.0 blue:200/255.0 alpha:0.2]; 67 | headerFooterView.title = [NSString stringWithFormat:@"标题 - %ld", section]; 68 | headerFooterView.descriptionText = [NSString stringWithFormat:@"自定义的sectionHeaderView - %ld", section]; 69 | return headerFooterView; 70 | } 71 | - (NSString *)yuFoldingTableView:(YUFoldingTableView *)yuTableView titleForHeaderInSection:(NSInteger)section 72 | { 73 | return [NSString stringWithFormat:@"Title %ld",section]; 74 | } 75 | // 返回箭头的位置 76 | - (YUFoldingSectionHeaderArrowPosition)perferedArrowPositionForYUFoldingTableView:(YUFoldingTableView *)yuTableView 77 | { 78 | return YUFoldingSectionHeaderArrowPositionLeft; 79 | } 80 | 81 | - (void )yuFoldingTableView:(YUFoldingTableView *)yuTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 82 | { 83 | [yuTableView deselectRowAtIndexPath:indexPath animated:YES]; 84 | } 85 | - (NSString *)yuFoldingTableView:(YUFoldingTableView *)yuTableView descriptionForHeaderInSection:(NSInteger )section 86 | { 87 | return @"detailText"; 88 | } 89 | ``` 90 | -------------------------------------------------------------------------------- /YUFoldingTableView/YUFoldingSectionHeader.h: -------------------------------------------------------------------------------- 1 | // 2 | // YUFoldingSectionHeader.h 3 | // YUFoldingTableView 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 liufengting. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | typedef NS_ENUM(NSUInteger, YUFoldingSectionState) { 12 | 13 | YUFoldingSectionStateFlod, // 折叠 14 | YUFoldingSectionStateShow, // 打开 15 | }; 16 | 17 | // 箭头的位置 18 | typedef NS_ENUM(NSUInteger, YUFoldingSectionHeaderArrowPosition) { 19 | 20 | YUFoldingSectionHeaderArrowPositionLeft, 21 | YUFoldingSectionHeaderArrowPositionRight, 22 | }; 23 | 24 | @protocol YUFoldingSectionHeaderDelegate 25 | 26 | - (void)yuFoldingSectionHeaderTappedAtIndex:(NSInteger)index; 27 | 28 | @end 29 | 30 | 31 | @interface YUFoldingSectionHeader : UITableViewHeaderFooterView 32 | 33 | @property (nonatomic, weak) id tapDelegate; 34 | 35 | @property (nonatomic, assign) BOOL autoHiddenSeperatorLine; 36 | 37 | @property (nonatomic, strong) UIColor *separatorLineColor; 38 | 39 | - (void)configWithBackgroundColor:(UIColor *)backgroundColor 40 | titleString:(NSString *)titleString 41 | titleColor:(UIColor *)titleColor 42 | titleFont:(UIFont *)titleFont 43 | descriptionString:(NSString *)descriptionString 44 | descriptionColor:(UIColor *)descriptionColor 45 | descriptionFont:(UIFont *)descriptionFont 46 | arrowImage:(UIImage *)arrowImage 47 | arrowPosition:(YUFoldingSectionHeaderArrowPosition)arrowPosition 48 | sectionState:(YUFoldingSectionState)sectionState 49 | sectionIndex:(NSInteger)sectionIndex; 50 | 51 | 52 | 53 | @end 54 | -------------------------------------------------------------------------------- /YUFoldingTableView/YUFoldingSectionHeader.m: -------------------------------------------------------------------------------- 1 | // 2 | // YUFoldingSectionHeader.m 3 | // YUFoldingTableView 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "YUFoldingSectionHeader.h" 10 | 11 | static CGFloat const YUFoldingSeperatorLineWidth = 0.3f; 12 | static CGFloat const YUFoldingMargin = 8.0f; 13 | static CGFloat const YUFoldingIconWidth = 24.0f; 14 | 15 | @interface YUFoldingSectionHeader () 16 | 17 | @property (nonatomic, strong) UILabel *titleLabel; 18 | @property (nonatomic, strong) UILabel *descriptionLabel; 19 | @property (nonatomic, strong) UIImageView *arrowImageView; 20 | @property (nonatomic, strong) CAShapeLayer *separatorLine; 21 | @property (nonatomic, assign) YUFoldingSectionHeaderArrowPosition arrowPosition; 22 | @property (nonatomic, assign) YUFoldingSectionState sectionState; 23 | @property (nonatomic, strong) UITapGestureRecognizer *tapGesture; 24 | 25 | @property (nonatomic, assign) NSInteger sectionIndex; 26 | 27 | @end 28 | 29 | @implementation YUFoldingSectionHeader 30 | 31 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier 32 | { 33 | if (self = [super initWithReuseIdentifier:reuseIdentifier]) { 34 | 35 | [self setupSubviews]; 36 | 37 | } 38 | return self; 39 | } 40 | 41 | - (void)awakeFromNib 42 | { 43 | [super awakeFromNib]; 44 | 45 | [self setupSubviews]; 46 | 47 | } 48 | 49 | // 创建子视图 50 | - (void)setupSubviews 51 | { 52 | _autoHiddenSeperatorLine = NO; 53 | _separatorLineColor = [UIColor whiteColor]; 54 | _arrowPosition = YUFoldingSectionHeaderArrowPositionRight; 55 | 56 | [self.contentView addSubview:self.titleLabel]; 57 | [self.contentView addSubview:self.descriptionLabel]; 58 | [self.contentView addSubview:self.arrowImageView]; 59 | [self.contentView addGestureRecognizer:self.tapGesture]; 60 | [self.contentView.layer addSublayer:self.separatorLine]; 61 | } 62 | 63 | - (void)configWithBackgroundColor:(UIColor *)backgroundColor 64 | titleString:(NSString *)titleString 65 | titleColor:(UIColor *)titleColor 66 | titleFont:(UIFont *)titleFont 67 | descriptionString:(NSString *)descriptionString 68 | descriptionColor:(UIColor *)descriptionColor 69 | descriptionFont:(UIFont *)descriptionFont 70 | arrowImage:(UIImage *)arrowImage 71 | arrowPosition:(YUFoldingSectionHeaderArrowPosition)arrowPosition 72 | sectionState:(YUFoldingSectionState)sectionState 73 | sectionIndex:(NSInteger)sectionIndex 74 | { 75 | _sectionIndex = sectionIndex; 76 | [self.contentView setBackgroundColor:backgroundColor]; 77 | 78 | self.titleLabel.text = titleString; 79 | self.titleLabel.textColor = titleColor; 80 | self.titleLabel.font = titleFont; 81 | 82 | self.descriptionLabel.text = descriptionString; 83 | self.descriptionLabel.textColor = descriptionColor; 84 | self.descriptionLabel.font = descriptionFont; 85 | 86 | self.arrowImageView.image = arrowImage; 87 | self.arrowPosition = arrowPosition; 88 | self.sectionState = sectionState; 89 | 90 | if (sectionState == YUFoldingSectionStateShow) { 91 | if (self.arrowPosition == YUFoldingSectionHeaderArrowPositionRight) { 92 | self.arrowImageView.transform = CGAffineTransformMakeRotation(-M_PI/2); 93 | }else{ 94 | self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 95 | } 96 | } else { 97 | if (self.arrowPosition == YUFoldingSectionHeaderArrowPositionRight) { 98 | _arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 99 | }else{ 100 | self.arrowImageView.transform = CGAffineTransformMakeRotation(0); 101 | } 102 | } 103 | 104 | } 105 | 106 | - (void)layoutSubviews 107 | { 108 | [super layoutSubviews]; 109 | 110 | CGFloat labelWidth = (self.frame.size.width - YUFoldingMargin * 2 - YUFoldingIconWidth)/2; 111 | CGFloat labelHeight = self.frame.size.height; 112 | CGRect arrowRect = CGRectMake(0, (self.frame.size.height - YUFoldingIconWidth)/2, YUFoldingIconWidth, YUFoldingIconWidth); 113 | CGRect titleRect = CGRectMake(YUFoldingMargin + YUFoldingIconWidth, 0, labelWidth, labelHeight); 114 | CGRect descriptionRect = CGRectMake(YUFoldingMargin + YUFoldingIconWidth + labelWidth, 0, labelWidth, labelHeight); 115 | if (_arrowPosition == YUFoldingSectionHeaderArrowPositionRight) { 116 | arrowRect.origin.x = YUFoldingMargin * 2 + labelWidth * 2; 117 | titleRect.origin.x = YUFoldingMargin; 118 | descriptionRect.origin.x = YUFoldingMargin + labelWidth; 119 | } 120 | [self.titleLabel setFrame:titleRect]; 121 | [self.descriptionLabel setFrame:descriptionRect]; 122 | [self.arrowImageView setFrame:arrowRect]; 123 | [self.separatorLine setPath:[self getSepertorPath].CGPath]; 124 | } 125 | 126 | 127 | // MARK: ----------------------- event 128 | 129 | - (void)shouldExpand:(BOOL)shouldExpand 130 | { 131 | 132 | [UIView animateWithDuration:0.2 animations:^{ 133 | if (shouldExpand) { 134 | if (self.arrowPosition == YUFoldingSectionHeaderArrowPositionRight) { 135 | self.arrowImageView.transform = CGAffineTransformMakeRotation(-M_PI/2); 136 | }else{ 137 | self.arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 138 | } 139 | } else { 140 | if (self.arrowPosition == YUFoldingSectionHeaderArrowPositionRight) { 141 | _arrowImageView.transform = CGAffineTransformMakeRotation(M_PI/2); 142 | }else{ 143 | self.arrowImageView.transform = CGAffineTransformMakeRotation(0); 144 | } 145 | } 146 | } completion:^(BOOL finished) { 147 | if (_autoHiddenSeperatorLine) { 148 | if (finished == YES) { 149 | self.separatorLine.hidden = shouldExpand; 150 | } 151 | } 152 | }]; 153 | } 154 | 155 | 156 | - (void)onTapped:(UITapGestureRecognizer *)gesture 157 | { 158 | [self shouldExpand:![NSNumber numberWithInteger:self.sectionState].boolValue]; 159 | if (_tapDelegate && [_tapDelegate respondsToSelector:@selector(yuFoldingSectionHeaderTappedAtIndex:)]) { 160 | self.sectionState = [NSNumber numberWithBool:(![NSNumber numberWithInteger:self.sectionState].boolValue)].integerValue; 161 | [_tapDelegate yuFoldingSectionHeaderTappedAtIndex:_sectionIndex]; 162 | } 163 | } 164 | 165 | // MARK: ----------------------- getter 166 | 167 | - (UILabel *)titleLabel 168 | { 169 | if (!_titleLabel) { 170 | _titleLabel = [[UILabel alloc]initWithFrame:CGRectZero]; 171 | _titleLabel.backgroundColor = [UIColor clearColor]; 172 | _titleLabel.textAlignment = NSTextAlignmentLeft; 173 | } 174 | return _titleLabel; 175 | } 176 | - (UILabel *)descriptionLabel 177 | { 178 | if (!_descriptionLabel) { 179 | _descriptionLabel = [[UILabel alloc]initWithFrame:CGRectZero]; 180 | _descriptionLabel.backgroundColor = [UIColor clearColor]; 181 | _descriptionLabel.textAlignment = NSTextAlignmentRight; 182 | } 183 | return _descriptionLabel; 184 | } 185 | - (UIImageView *)arrowImageView 186 | { 187 | if (!_arrowImageView) { 188 | _arrowImageView = [[UIImageView alloc]initWithFrame:CGRectZero]; 189 | _arrowImageView.backgroundColor = [UIColor clearColor]; 190 | _arrowImageView.contentMode = UIViewContentModeScaleAspectFit; 191 | } 192 | return _arrowImageView; 193 | } 194 | - (CAShapeLayer *)separatorLine 195 | { 196 | if (!_separatorLine) { 197 | _separatorLine = [CAShapeLayer layer]; 198 | _separatorLine.strokeColor = _separatorLineColor.CGColor; 199 | _separatorLine.lineWidth = YUFoldingSeperatorLineWidth; 200 | } 201 | return _separatorLine; 202 | } 203 | 204 | - (UITapGestureRecognizer *)tapGesture 205 | { 206 | if (!_tapGesture) { 207 | _tapGesture = [[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(onTapped:)]; 208 | } 209 | return _tapGesture; 210 | } 211 | 212 | - (UIBezierPath *)getSepertorPath 213 | { 214 | UIBezierPath *path = [UIBezierPath bezierPath]; 215 | [path moveToPoint:CGPointMake(0, self.frame.size.height - YUFoldingSeperatorLineWidth)]; 216 | [path addLineToPoint:CGPointMake(self.frame.size.width, self.frame.size.height - YUFoldingSeperatorLineWidth)]; 217 | return path; 218 | } 219 | 220 | @end 221 | -------------------------------------------------------------------------------- /YUFoldingTableView/YUFoldingTableView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YUFoldingTableView.h 3 | // YUFoldingTableView 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YUFoldingSectionHeader.h" 11 | 12 | @class YUFoldingTableView; 13 | 14 | @protocol YUFoldingTableViewDelegate 15 | 16 | @required 17 | /** 18 | * 返回section的个数 19 | */ 20 | - (NSInteger )numberOfSectionForYUFoldingTableView:(YUFoldingTableView *)yuTableView; 21 | /** 22 | * cell的个数 23 | */ 24 | - (NSInteger )yuFoldingTableView:(YUFoldingTableView *)yuTableView numberOfRowsInSection:(NSInteger )section; 25 | /** 26 | * header的高度 27 | */ 28 | - (CGFloat )yuFoldingTableView:(YUFoldingTableView *)yuTableView heightForHeaderInSection:(NSInteger )section; 29 | /** 30 | * cell的高度 31 | */ 32 | - (CGFloat )yuFoldingTableView:(YUFoldingTableView *)yuTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath; 33 | /** 34 | * 返回cell 35 | */ 36 | - (UITableViewCell *)yuFoldingTableView:(YUFoldingTableView *)yuTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath; 37 | 38 | @optional 39 | 40 | /** 41 | * 点击cell 42 | */ 43 | - (void )yuFoldingTableView:(YUFoldingTableView *)yuTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath; 44 | 45 | /** 46 | * 点击sectionHeaderView 47 | */ 48 | - (void )yuFoldingTableView:(YUFoldingTableView *)yuTableView didSelectHeaderViewAtSection:(NSInteger)section; 49 | 50 | /** 51 | * 返回HeaderView 52 | */ 53 | - (UIView *)yuFoldingTableView:(UITableView *)yuTableView viewForHeaderInSection:(NSInteger)section; 54 | 55 | /************* 下面是关于headerView一些属性的设置 ************/ 56 | 57 | /** 58 | * header的标题 59 | */ 60 | - (NSString *)yuFoldingTableView:(YUFoldingTableView *)yuTableView titleForHeaderInSection:(NSInteger )section; 61 | 62 | /** 63 | * 箭头的位置 64 | */ 65 | - (YUFoldingSectionHeaderArrowPosition)perferedArrowPositionForYUFoldingTableView:(YUFoldingTableView *)yuTableView; 66 | 67 | /** 68 | * 箭头图片 69 | */ 70 | - (UIImage *)yuFoldingTableView:(YUFoldingTableView *)yuTableView arrowImageForSection:(NSInteger )section; 71 | 72 | - (NSString *)yuFoldingTableView:(YUFoldingTableView *)yuTableView descriptionForHeaderInSection:(NSInteger )section; 73 | 74 | - (UIColor *)yuFoldingTableView:(YUFoldingTableView *)yuTableView backgroundColorForHeaderInSection:(NSInteger )section; 75 | 76 | - (UIFont *)yuFoldingTableView:(YUFoldingTableView *)yuTableView fontForTitleInSection:(NSInteger )section; 77 | 78 | - (UIFont *)yuFoldingTableView:(YUFoldingTableView *)yuTableView fontForDescriptionInSection:(NSInteger )section; 79 | 80 | - (UIColor *)yuFoldingTableView:(YUFoldingTableView *)yuTableView textColorForTitleInSection:(NSInteger )section; 81 | 82 | - (UIColor *)yuFoldingTableView:(YUFoldingTableView *)yuTableView textColorForDescriptionInSection:(NSInteger )section; 83 | 84 | @end 85 | 86 | @interface YUFoldingTableView : UITableView 87 | 88 | @property (nonatomic, weak) id foldingDelegate; 89 | 90 | @property (nonatomic, assign) YUFoldingSectionState foldingState; 91 | 92 | @property (nonatomic, strong, readonly) NSMutableArray *statusArray; 93 | 94 | // 控制默认section的展开状态 95 | @property (nonatomic, copy) NSArray *sectionStateArray; 96 | 97 | @end 98 | -------------------------------------------------------------------------------- /YUFoldingTableView/YUFoldingTableView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YUFoldingTableView.m 3 | // YUFoldingTableView 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "YUFoldingTableView.h" 10 | 11 | static NSString *YUFoldingSectionHeaderID = @"YUFoldingSectionHeader"; 12 | static NSInteger addTag = 100; 13 | 14 | id YUSafeObject(NSArray *array, NSInteger index) { 15 | 16 | if (![array isKindOfClass:[NSArray class]]) { 17 | return nil; 18 | } 19 | if (array.count <= index) { 20 | return nil; 21 | } 22 | 23 | return [array objectAtIndex:index]; 24 | } 25 | 26 | @interface YUFoldingTableView () 27 | 28 | @property (nonatomic, strong, readwrite) NSMutableArray *statusArray; 29 | 30 | @end 31 | 32 | @implementation YUFoldingTableView 33 | 34 | #pragma mark - 初始化 35 | 36 | - (instancetype)initWithFrame:(CGRect)frame 37 | { 38 | self = [super initWithFrame:frame]; 39 | if (self) { 40 | [self setupDelegateAndDataSource]; 41 | } 42 | return self; 43 | } 44 | 45 | 46 | - (instancetype)initWithCoder:(NSCoder *)aDecoder 47 | { 48 | self = [super initWithCoder:aDecoder]; 49 | if (self) { 50 | [self setupDelegateAndDataSource]; 51 | } 52 | return self; 53 | } 54 | 55 | - (void)dealloc 56 | { 57 | [[NSNotificationCenter defaultCenter] removeObserver:self name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 58 | } 59 | 60 | #pragma mark - 创建数据源和代理 61 | 62 | - (void)setupDelegateAndDataSource 63 | { 64 | // 适配iOS 11 65 | #ifdef __IPHONE_11_0 66 | // if ([self respondsToSelector:@selector(setContentInsetAdjustmentBehavior:)]) { 67 | // self.contentInsetAdjustmentBehavior = UIScrollViewContentInsetAdjustmentNever; 68 | // } 69 | self.estimatedRowHeight = 0; 70 | self.estimatedSectionHeaderHeight = 0; 71 | self.estimatedSectionFooterHeight = 0; 72 | #endif 73 | self.delegate = self; 74 | self.dataSource = self; 75 | if (self.style == UITableViewStylePlain) { 76 | self.tableFooterView = [[UIView alloc] init]; 77 | } 78 | 79 | [self registerClass:[YUFoldingSectionHeader class] forHeaderFooterViewReuseIdentifier:YUFoldingSectionHeaderID]; 80 | 81 | // 添加监听 82 | [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(onChangeStatusBarOrientationNotification:) name:UIApplicationDidChangeStatusBarOrientationNotification object:nil]; 83 | } 84 | 85 | - (NSMutableArray *)statusArray 86 | { 87 | if (!_statusArray) { 88 | _statusArray = [NSMutableArray array]; 89 | } 90 | 91 | if (!_foldingState) { 92 | _foldingState = YUFoldingSectionStateFlod; 93 | } 94 | 95 | if (_statusArray.count) { 96 | if (_statusArray.count > self.numberOfSections) { 97 | [_statusArray removeObjectsInRange:NSMakeRange(self.numberOfSections - 1, _statusArray.count - self.numberOfSections)]; 98 | }else if (_statusArray.count < self.numberOfSections) { 99 | for (NSInteger i = self.numberOfSections - _statusArray.count; i < self.numberOfSections; i++) { 100 | [_statusArray addObject:[NSNumber numberWithInteger:_foldingState]]; 101 | } 102 | } 103 | }else{ 104 | for (NSInteger i = 0; i < self.numberOfSections; i++) { 105 | [_statusArray addObject:[NSNumber numberWithInteger:_foldingState]]; 106 | } 107 | } 108 | 109 | if (_sectionStateArray.count) { 110 | NSMutableArray *tempStatusArrayM = [NSMutableArray array]; 111 | for (int i = 0; i < _statusArray.count; i++) { 112 | if (i < _sectionStateArray.count) { 113 | [tempStatusArrayM addObject:_sectionStateArray[i]]; 114 | } else { 115 | [tempStatusArrayM addObject:@"0"]; 116 | } 117 | } 118 | _statusArray = tempStatusArrayM; 119 | _sectionStateArray = nil; 120 | } 121 | 122 | 123 | return _statusArray; 124 | } 125 | 126 | - (void)onChangeStatusBarOrientationNotification:(NSNotification *)notification 127 | { 128 | dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(0.2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{ 129 | [self reloadData]; 130 | }); 131 | } 132 | 133 | #pragma mark - UI Configration 134 | 135 | - (YUFoldingSectionHeaderArrowPosition )perferedArrowPosition 136 | { 137 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(perferedArrowPositionForYUFoldingTableView:)]) { 138 | return [_foldingDelegate perferedArrowPositionForYUFoldingTableView:self]; 139 | } 140 | return YUFoldingSectionHeaderArrowPositionRight; 141 | } 142 | - (UIColor *)backgroundColorForSection:(NSInteger )section 143 | { 144 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:backgroundColorForHeaderInSection:)]) { 145 | return [_foldingDelegate yuFoldingTableView:self backgroundColorForHeaderInSection:section]; 146 | } 147 | return [UIColor colorWithRed:102/255.f green:102/255.f blue:255/255.f alpha:1.f]; 148 | } 149 | - (NSString *)titleForSection:(NSInteger )section 150 | { 151 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:titleForHeaderInSection:)]) { 152 | return [_foldingDelegate yuFoldingTableView:self titleForHeaderInSection:section]; 153 | } 154 | return [NSString string]; 155 | } 156 | - (UIFont *)titleFontForSection:(NSInteger )section 157 | { 158 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:fontForTitleInSection:)]) { 159 | return [_foldingDelegate yuFoldingTableView:self fontForTitleInSection:section]; 160 | } 161 | return [UIFont boldSystemFontOfSize:16]; 162 | } 163 | - (UIColor *)titleColorForSection:(NSInteger )section 164 | { 165 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:textColorForTitleInSection:)]) { 166 | return [_foldingDelegate yuFoldingTableView:self textColorForTitleInSection:section]; 167 | } 168 | return [UIColor whiteColor]; 169 | } 170 | - (NSString *)descriptionForSection:(NSInteger )section 171 | { 172 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:descriptionForHeaderInSection:)]) { 173 | return [_foldingDelegate yuFoldingTableView:self descriptionForHeaderInSection:section]; 174 | } 175 | return [NSString string]; 176 | } 177 | - (UIFont *)descriptionFontForSection:(NSInteger )section 178 | { 179 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:fontForDescriptionInSection:)]) { 180 | return [_foldingDelegate yuFoldingTableView:self fontForDescriptionInSection:section]; 181 | } 182 | return [UIFont boldSystemFontOfSize:13]; 183 | } 184 | 185 | - (UIColor *)descriptionColorForSection:(NSInteger )section 186 | { 187 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:textColorForDescriptionInSection:)]) { 188 | return [_foldingDelegate yuFoldingTableView:self textColorForDescriptionInSection:section]; 189 | } 190 | return [UIColor whiteColor]; 191 | } 192 | 193 | - (UIImage *)arrowImageForSection:(NSInteger )section 194 | { 195 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:arrowImageForSection:)]) { 196 | return [_foldingDelegate yuFoldingTableView:self arrowImageForSection:section]; 197 | } 198 | return [UIImage imageNamed:@"YUFolding_arrow"]; 199 | } 200 | 201 | #pragma mark - UITableViewDelegate / UITableViewDataSource 202 | 203 | - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView 204 | { 205 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(numberOfSectionForYUFoldingTableView:)]) { 206 | return [_foldingDelegate numberOfSectionForYUFoldingTableView:self]; 207 | }else{ 208 | return self.numberOfSections; 209 | } 210 | } 211 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 212 | { 213 | if ([YUSafeObject(self.statusArray, section) integerValue] == YUFoldingSectionStateShow) { 214 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:numberOfRowsInSection:)]) { 215 | return [_foldingDelegate yuFoldingTableView:self numberOfRowsInSection:section]; 216 | } 217 | } 218 | return 0; 219 | } 220 | - (CGFloat)tableView:(UITableView *)tableView heightForHeaderInSection:(NSInteger)section 221 | { 222 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:heightForHeaderInSection:)]) { 223 | return [_foldingDelegate yuFoldingTableView:self heightForHeaderInSection:section]; 224 | }else{ 225 | return self.sectionHeaderHeight; 226 | } 227 | } 228 | - (CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 229 | { 230 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:heightForRowAtIndexPath:)]) { 231 | return [_foldingDelegate yuFoldingTableView:self heightForRowAtIndexPath:indexPath]; 232 | }else{ 233 | return self.rowHeight; 234 | } 235 | } 236 | - (CGFloat)tableView:(UITableView *)tableView heightForFooterInSection:(NSInteger)section 237 | { 238 | if (self.style == UITableViewStylePlain) { 239 | return 0; 240 | }else{ 241 | return 0.001; 242 | } 243 | } 244 | - (UIView *)tableView:(UITableView *)tableView viewForHeaderInSection:(NSInteger)section 245 | { 246 | UIView *sectionHeaderView = nil; 247 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:viewForHeaderInSection:)]) { 248 | sectionHeaderView = [_foldingDelegate yuFoldingTableView:self viewForHeaderInSection:section]; 249 | sectionHeaderView.tag = addTag + section; 250 | UITapGestureRecognizer *tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(tapGestureAction:)]; 251 | [sectionHeaderView addGestureRecognizer:tapGesture]; 252 | } else { 253 | sectionHeaderView = [self normalHeaderViewWithTableView:tableView section:section]; 254 | } 255 | return sectionHeaderView; 256 | } 257 | 258 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 259 | { 260 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:cellForRowAtIndexPath:)]) { 261 | return [_foldingDelegate yuFoldingTableView:self cellForRowAtIndexPath:indexPath]; 262 | } 263 | return [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:@"DefaultCellIndentifier"]; 264 | } 265 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 266 | { 267 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:didSelectRowAtIndexPath:)]) { 268 | [_foldingDelegate yuFoldingTableView:self didSelectRowAtIndexPath:indexPath]; 269 | } 270 | } 271 | 272 | 273 | #pragma mark - YUFoldingSectionHeader 274 | 275 | - (UIView *)normalHeaderViewWithTableView:(UITableView *)tableView section:(NSInteger)section 276 | { 277 | YUFoldingSectionHeader *sectionHeaderView = [self dequeueReusableHeaderFooterViewWithIdentifier:YUFoldingSectionHeaderID]; 278 | [sectionHeaderView configWithBackgroundColor:[self backgroundColorForSection:section] 279 | titleString:[self titleForSection:section] 280 | titleColor:[self titleColorForSection:section] 281 | titleFont:[self titleFontForSection:section] 282 | descriptionString:[self descriptionForSection:section] 283 | descriptionColor:[self descriptionColorForSection:section] 284 | descriptionFont:[self descriptionFontForSection:section] 285 | arrowImage:[self arrowImageForSection:section] 286 | arrowPosition:[self perferedArrowPosition] 287 | sectionState:[YUSafeObject(self.statusArray, section) integerValue] 288 | sectionIndex:section]; 289 | sectionHeaderView.tapDelegate = self; 290 | return sectionHeaderView; 291 | } 292 | 293 | - (void)tapGestureAction:(UIGestureRecognizer *)gesture 294 | { 295 | [self yuFoldingSectionHeaderTappedAtIndex:gesture.view.tag - addTag]; 296 | } 297 | 298 | - (void)yuFoldingSectionHeaderTappedAtIndex:(NSInteger)index 299 | { 300 | if (self.statusArray.count <= index) { 301 | return; 302 | } 303 | BOOL currentIsOpen = [YUSafeObject(self.statusArray, index) boolValue]; 304 | 305 | [self.statusArray replaceObjectAtIndex:index withObject:[NSNumber numberWithBool:!currentIsOpen]]; 306 | 307 | NSInteger numberOfRow = [_foldingDelegate yuFoldingTableView:self numberOfRowsInSection:index]; 308 | NSMutableArray *rowArray = [NSMutableArray array]; 309 | if (numberOfRow) { 310 | for (NSInteger i = 0; i < numberOfRow; i++) { 311 | [rowArray addObject:[NSIndexPath indexPathForRow:i inSection:index]]; 312 | } 313 | } 314 | if (rowArray.count) { 315 | if (currentIsOpen) { 316 | [self deleteRowsAtIndexPaths:[NSArray arrayWithArray:rowArray] withRowAnimation:UITableViewRowAnimationTop]; 317 | }else{ 318 | [self insertRowsAtIndexPaths:[NSArray arrayWithArray:rowArray] withRowAnimation:UITableViewRowAnimationTop]; 319 | } 320 | } 321 | 322 | if (_foldingDelegate && [_foldingDelegate respondsToSelector:@selector(yuFoldingTableView:didSelectHeaderViewAtSection:)]) { 323 | [_foldingDelegate yuFoldingTableView:self didSelectHeaderViewAtSection:index]; 324 | } 325 | } 326 | 327 | 328 | 329 | @end 330 | -------------------------------------------------------------------------------- /YUFoldingTableView/YUFolding_arrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelywind/YUFoldingTableView/402b85d1b1d65bff8829b2a3e9e76579fe2d0eac/YUFoldingTableView/YUFolding_arrow.png -------------------------------------------------------------------------------- /YUFoldingTableViewDemo.xcodeproj/project.pbxproj: -------------------------------------------------------------------------------- 1 | // !$*UTF8*$! 2 | { 3 | archiveVersion = 1; 4 | classes = { 5 | }; 6 | objectVersion = 46; 7 | objects = { 8 | 9 | /* Begin PBXBuildFile section */ 10 | AEFABCBC2029A7C300AE9216 /* YUCustomHeaderView.m in Sources */ = {isa = PBXBuildFile; fileRef = AEFABCBB2029A7C200AE9216 /* YUCustomHeaderView.m */; }; 11 | AEFABCC22029ABCD00AE9216 /* YUCustomTestController.m in Sources */ = {isa = PBXBuildFile; fileRef = AEFABCC12029ABCD00AE9216 /* YUCustomTestController.m */; }; 12 | C34043111D6DA29B00D4E22F /* main.m in Sources */ = {isa = PBXBuildFile; fileRef = C34043101D6DA29B00D4E22F /* main.m */; }; 13 | C34043141D6DA29B00D4E22F /* AppDelegate.m in Sources */ = {isa = PBXBuildFile; fileRef = C34043131D6DA29B00D4E22F /* AppDelegate.m */; }; 14 | C34043171D6DA29B00D4E22F /* ViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C34043161D6DA29B00D4E22F /* ViewController.m */; }; 15 | C340431A1D6DA29B00D4E22F /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C34043181D6DA29B00D4E22F /* Main.storyboard */; }; 16 | C340431C1D6DA29B00D4E22F /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = C340431B1D6DA29B00D4E22F /* Assets.xcassets */; }; 17 | C340431F1D6DA29B00D4E22F /* LaunchScreen.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = C340431D1D6DA29B00D4E22F /* LaunchScreen.storyboard */; }; 18 | C340435A1D6DB22C00D4E22F /* YUFolding_arrow.png in Resources */ = {isa = PBXBuildFile; fileRef = C34043551D6DB22C00D4E22F /* YUFolding_arrow.png */; }; 19 | C340435B1D6DB22C00D4E22F /* YUFoldingSectionHeader.m in Sources */ = {isa = PBXBuildFile; fileRef = C34043571D6DB22C00D4E22F /* YUFoldingSectionHeader.m */; }; 20 | C340435C1D6DB22C00D4E22F /* YUFoldingTableView.m in Sources */ = {isa = PBXBuildFile; fileRef = C34043591D6DB22C00D4E22F /* YUFoldingTableView.m */; }; 21 | C357E25B1D6E848D00E47FC8 /* YUTestViewController.m in Sources */ = {isa = PBXBuildFile; fileRef = C357E25A1D6E848D00E47FC8 /* YUTestViewController.m */; }; 22 | /* End PBXBuildFile section */ 23 | 24 | /* Begin PBXFileReference section */ 25 | AEFABCBA2029A7C200AE9216 /* YUCustomHeaderView.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YUCustomHeaderView.h; sourceTree = ""; }; 26 | AEFABCBB2029A7C200AE9216 /* YUCustomHeaderView.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YUCustomHeaderView.m; sourceTree = ""; }; 27 | AEFABCC02029ABCD00AE9216 /* YUCustomTestController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = YUCustomTestController.h; sourceTree = ""; }; 28 | AEFABCC12029ABCD00AE9216 /* YUCustomTestController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = YUCustomTestController.m; sourceTree = ""; }; 29 | C340430C1D6DA29B00D4E22F /* YUFoldingTableViewDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = YUFoldingTableViewDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; 30 | C34043101D6DA29B00D4E22F /* main.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = main.m; sourceTree = ""; }; 31 | C34043121D6DA29B00D4E22F /* AppDelegate.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = AppDelegate.h; sourceTree = ""; }; 32 | C34043131D6DA29B00D4E22F /* AppDelegate.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = AppDelegate.m; sourceTree = ""; }; 33 | C34043151D6DA29B00D4E22F /* ViewController.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = ViewController.h; sourceTree = ""; }; 34 | C34043161D6DA29B00D4E22F /* ViewController.m */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.objc; path = ViewController.m; sourceTree = ""; }; 35 | C34043191D6DA29B00D4E22F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/Main.storyboard; sourceTree = ""; }; 36 | C340431B1D6DA29B00D4E22F /* Assets.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Assets.xcassets; sourceTree = ""; }; 37 | C340431E1D6DA29B00D4E22F /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.storyboard; name = Base; path = Base.lproj/LaunchScreen.storyboard; sourceTree = ""; }; 38 | C34043201D6DA29B00D4E22F /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; 39 | C34043551D6DB22C00D4E22F /* YUFolding_arrow.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = YUFolding_arrow.png; sourceTree = ""; }; 40 | C34043561D6DB22C00D4E22F /* YUFoldingSectionHeader.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YUFoldingSectionHeader.h; sourceTree = ""; }; 41 | C34043571D6DB22C00D4E22F /* YUFoldingSectionHeader.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YUFoldingSectionHeader.m; sourceTree = ""; }; 42 | C34043581D6DB22C00D4E22F /* YUFoldingTableView.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YUFoldingTableView.h; sourceTree = ""; }; 43 | C34043591D6DB22C00D4E22F /* YUFoldingTableView.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YUFoldingTableView.m; sourceTree = ""; }; 44 | C357E2591D6E848D00E47FC8 /* YUTestViewController.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = YUTestViewController.h; sourceTree = ""; }; 45 | C357E25A1D6E848D00E47FC8 /* YUTestViewController.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = YUTestViewController.m; sourceTree = ""; }; 46 | /* End PBXFileReference section */ 47 | 48 | /* Begin PBXFrameworksBuildPhase section */ 49 | C34043091D6DA29B00D4E22F /* Frameworks */ = { 50 | isa = PBXFrameworksBuildPhase; 51 | buildActionMask = 2147483647; 52 | files = ( 53 | ); 54 | runOnlyForDeploymentPostprocessing = 0; 55 | }; 56 | /* End PBXFrameworksBuildPhase section */ 57 | 58 | /* Begin PBXGroup section */ 59 | C34043031D6DA29B00D4E22F = { 60 | isa = PBXGroup; 61 | children = ( 62 | C340430E1D6DA29B00D4E22F /* YUFoldingTableViewDemo */, 63 | C340430D1D6DA29B00D4E22F /* Products */, 64 | ); 65 | sourceTree = ""; 66 | }; 67 | C340430D1D6DA29B00D4E22F /* Products */ = { 68 | isa = PBXGroup; 69 | children = ( 70 | C340430C1D6DA29B00D4E22F /* YUFoldingTableViewDemo.app */, 71 | ); 72 | name = Products; 73 | sourceTree = ""; 74 | }; 75 | C340430E1D6DA29B00D4E22F /* YUFoldingTableViewDemo */ = { 76 | isa = PBXGroup; 77 | children = ( 78 | C34043541D6DB22C00D4E22F /* YUFoldingTableView */, 79 | C34043121D6DA29B00D4E22F /* AppDelegate.h */, 80 | C34043131D6DA29B00D4E22F /* AppDelegate.m */, 81 | C34043151D6DA29B00D4E22F /* ViewController.h */, 82 | C34043161D6DA29B00D4E22F /* ViewController.m */, 83 | C357E2591D6E848D00E47FC8 /* YUTestViewController.h */, 84 | C357E25A1D6E848D00E47FC8 /* YUTestViewController.m */, 85 | AEFABCC02029ABCD00AE9216 /* YUCustomTestController.h */, 86 | AEFABCC12029ABCD00AE9216 /* YUCustomTestController.m */, 87 | AEFABCBA2029A7C200AE9216 /* YUCustomHeaderView.h */, 88 | AEFABCBB2029A7C200AE9216 /* YUCustomHeaderView.m */, 89 | C34043181D6DA29B00D4E22F /* Main.storyboard */, 90 | C340431B1D6DA29B00D4E22F /* Assets.xcassets */, 91 | C340431D1D6DA29B00D4E22F /* LaunchScreen.storyboard */, 92 | C34043201D6DA29B00D4E22F /* Info.plist */, 93 | C340430F1D6DA29B00D4E22F /* Supporting Files */, 94 | ); 95 | path = YUFoldingTableViewDemo; 96 | sourceTree = ""; 97 | }; 98 | C340430F1D6DA29B00D4E22F /* Supporting Files */ = { 99 | isa = PBXGroup; 100 | children = ( 101 | C34043101D6DA29B00D4E22F /* main.m */, 102 | ); 103 | name = "Supporting Files"; 104 | sourceTree = ""; 105 | }; 106 | C34043541D6DB22C00D4E22F /* YUFoldingTableView */ = { 107 | isa = PBXGroup; 108 | children = ( 109 | C34043551D6DB22C00D4E22F /* YUFolding_arrow.png */, 110 | C34043561D6DB22C00D4E22F /* YUFoldingSectionHeader.h */, 111 | C34043571D6DB22C00D4E22F /* YUFoldingSectionHeader.m */, 112 | C34043581D6DB22C00D4E22F /* YUFoldingTableView.h */, 113 | C34043591D6DB22C00D4E22F /* YUFoldingTableView.m */, 114 | ); 115 | path = YUFoldingTableView; 116 | sourceTree = SOURCE_ROOT; 117 | }; 118 | /* End PBXGroup section */ 119 | 120 | /* Begin PBXNativeTarget section */ 121 | C340430B1D6DA29B00D4E22F /* YUFoldingTableViewDemo */ = { 122 | isa = PBXNativeTarget; 123 | buildConfigurationList = C34043391D6DA29B00D4E22F /* Build configuration list for PBXNativeTarget "YUFoldingTableViewDemo" */; 124 | buildPhases = ( 125 | C34043081D6DA29B00D4E22F /* Sources */, 126 | C34043091D6DA29B00D4E22F /* Frameworks */, 127 | C340430A1D6DA29B00D4E22F /* Resources */, 128 | ); 129 | buildRules = ( 130 | ); 131 | dependencies = ( 132 | ); 133 | name = YUFoldingTableViewDemo; 134 | productName = YUFoldingTableViewDemo; 135 | productReference = C340430C1D6DA29B00D4E22F /* YUFoldingTableViewDemo.app */; 136 | productType = "com.apple.product-type.application"; 137 | }; 138 | /* End PBXNativeTarget section */ 139 | 140 | /* Begin PBXProject section */ 141 | C34043041D6DA29B00D4E22F /* Project object */ = { 142 | isa = PBXProject; 143 | attributes = { 144 | LastUpgradeCheck = 0730; 145 | ORGANIZATIONNAME = timelywind; 146 | TargetAttributes = { 147 | C340430B1D6DA29B00D4E22F = { 148 | CreatedOnToolsVersion = 7.3; 149 | DevelopmentTeam = BRZ859V993; 150 | ProvisioningStyle = Manual; 151 | }; 152 | }; 153 | }; 154 | buildConfigurationList = C34043071D6DA29B00D4E22F /* Build configuration list for PBXProject "YUFoldingTableViewDemo" */; 155 | compatibilityVersion = "Xcode 3.2"; 156 | developmentRegion = English; 157 | hasScannedForEncodings = 0; 158 | knownRegions = ( 159 | en, 160 | Base, 161 | ); 162 | mainGroup = C34043031D6DA29B00D4E22F; 163 | productRefGroup = C340430D1D6DA29B00D4E22F /* Products */; 164 | projectDirPath = ""; 165 | projectRoot = ""; 166 | targets = ( 167 | C340430B1D6DA29B00D4E22F /* YUFoldingTableViewDemo */, 168 | ); 169 | }; 170 | /* End PBXProject section */ 171 | 172 | /* Begin PBXResourcesBuildPhase section */ 173 | C340430A1D6DA29B00D4E22F /* Resources */ = { 174 | isa = PBXResourcesBuildPhase; 175 | buildActionMask = 2147483647; 176 | files = ( 177 | C340431F1D6DA29B00D4E22F /* LaunchScreen.storyboard in Resources */, 178 | C340431C1D6DA29B00D4E22F /* Assets.xcassets in Resources */, 179 | C340431A1D6DA29B00D4E22F /* Main.storyboard in Resources */, 180 | C340435A1D6DB22C00D4E22F /* YUFolding_arrow.png in Resources */, 181 | ); 182 | runOnlyForDeploymentPostprocessing = 0; 183 | }; 184 | /* End PBXResourcesBuildPhase section */ 185 | 186 | /* Begin PBXSourcesBuildPhase section */ 187 | C34043081D6DA29B00D4E22F /* Sources */ = { 188 | isa = PBXSourcesBuildPhase; 189 | buildActionMask = 2147483647; 190 | files = ( 191 | C340435C1D6DB22C00D4E22F /* YUFoldingTableView.m in Sources */, 192 | C34043171D6DA29B00D4E22F /* ViewController.m in Sources */, 193 | C357E25B1D6E848D00E47FC8 /* YUTestViewController.m in Sources */, 194 | C34043141D6DA29B00D4E22F /* AppDelegate.m in Sources */, 195 | C340435B1D6DB22C00D4E22F /* YUFoldingSectionHeader.m in Sources */, 196 | AEFABCC22029ABCD00AE9216 /* YUCustomTestController.m in Sources */, 197 | C34043111D6DA29B00D4E22F /* main.m in Sources */, 198 | AEFABCBC2029A7C300AE9216 /* YUCustomHeaderView.m in Sources */, 199 | ); 200 | runOnlyForDeploymentPostprocessing = 0; 201 | }; 202 | /* End PBXSourcesBuildPhase section */ 203 | 204 | /* Begin PBXVariantGroup section */ 205 | C34043181D6DA29B00D4E22F /* Main.storyboard */ = { 206 | isa = PBXVariantGroup; 207 | children = ( 208 | C34043191D6DA29B00D4E22F /* Base */, 209 | ); 210 | name = Main.storyboard; 211 | sourceTree = ""; 212 | }; 213 | C340431D1D6DA29B00D4E22F /* LaunchScreen.storyboard */ = { 214 | isa = PBXVariantGroup; 215 | children = ( 216 | C340431E1D6DA29B00D4E22F /* Base */, 217 | ); 218 | name = LaunchScreen.storyboard; 219 | sourceTree = ""; 220 | }; 221 | /* End PBXVariantGroup section */ 222 | 223 | /* Begin XCBuildConfiguration section */ 224 | C34043371D6DA29B00D4E22F /* Debug */ = { 225 | isa = XCBuildConfiguration; 226 | buildSettings = { 227 | ALWAYS_SEARCH_USER_PATHS = NO; 228 | CLANG_ANALYZER_NONNULL = YES; 229 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 230 | CLANG_CXX_LIBRARY = "libc++"; 231 | CLANG_ENABLE_MODULES = YES; 232 | CLANG_ENABLE_OBJC_ARC = YES; 233 | CLANG_WARN_BOOL_CONVERSION = YES; 234 | CLANG_WARN_CONSTANT_CONVERSION = YES; 235 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 236 | CLANG_WARN_EMPTY_BODY = YES; 237 | CLANG_WARN_ENUM_CONVERSION = YES; 238 | CLANG_WARN_INT_CONVERSION = YES; 239 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 240 | CLANG_WARN_UNREACHABLE_CODE = YES; 241 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 242 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 243 | COPY_PHASE_STRIP = NO; 244 | DEBUG_INFORMATION_FORMAT = dwarf; 245 | ENABLE_STRICT_OBJC_MSGSEND = YES; 246 | ENABLE_TESTABILITY = YES; 247 | GCC_C_LANGUAGE_STANDARD = gnu99; 248 | GCC_DYNAMIC_NO_PIC = NO; 249 | GCC_NO_COMMON_BLOCKS = YES; 250 | GCC_OPTIMIZATION_LEVEL = 0; 251 | GCC_PREPROCESSOR_DEFINITIONS = ( 252 | "DEBUG=1", 253 | "$(inherited)", 254 | ); 255 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 256 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 257 | GCC_WARN_UNDECLARED_SELECTOR = YES; 258 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 259 | GCC_WARN_UNUSED_FUNCTION = YES; 260 | GCC_WARN_UNUSED_VARIABLE = YES; 261 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 262 | MTL_ENABLE_DEBUG_INFO = YES; 263 | ONLY_ACTIVE_ARCH = YES; 264 | SDKROOT = iphoneos; 265 | TARGETED_DEVICE_FAMILY = "1,2"; 266 | }; 267 | name = Debug; 268 | }; 269 | C34043381D6DA29B00D4E22F /* Release */ = { 270 | isa = XCBuildConfiguration; 271 | buildSettings = { 272 | ALWAYS_SEARCH_USER_PATHS = NO; 273 | CLANG_ANALYZER_NONNULL = YES; 274 | CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; 275 | CLANG_CXX_LIBRARY = "libc++"; 276 | CLANG_ENABLE_MODULES = YES; 277 | CLANG_ENABLE_OBJC_ARC = YES; 278 | CLANG_WARN_BOOL_CONVERSION = YES; 279 | CLANG_WARN_CONSTANT_CONVERSION = YES; 280 | CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; 281 | CLANG_WARN_EMPTY_BODY = YES; 282 | CLANG_WARN_ENUM_CONVERSION = YES; 283 | CLANG_WARN_INT_CONVERSION = YES; 284 | CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; 285 | CLANG_WARN_UNREACHABLE_CODE = YES; 286 | CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; 287 | "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; 288 | COPY_PHASE_STRIP = NO; 289 | DEBUG_INFORMATION_FORMAT = "dwarf-with-dsym"; 290 | ENABLE_NS_ASSERTIONS = NO; 291 | ENABLE_STRICT_OBJC_MSGSEND = YES; 292 | GCC_C_LANGUAGE_STANDARD = gnu99; 293 | GCC_NO_COMMON_BLOCKS = YES; 294 | GCC_WARN_64_TO_32_BIT_CONVERSION = YES; 295 | GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; 296 | GCC_WARN_UNDECLARED_SELECTOR = YES; 297 | GCC_WARN_UNINITIALIZED_AUTOS = YES_AGGRESSIVE; 298 | GCC_WARN_UNUSED_FUNCTION = YES; 299 | GCC_WARN_UNUSED_VARIABLE = YES; 300 | IPHONEOS_DEPLOYMENT_TARGET = 9.3; 301 | MTL_ENABLE_DEBUG_INFO = NO; 302 | SDKROOT = iphoneos; 303 | TARGETED_DEVICE_FAMILY = "1,2"; 304 | VALIDATE_PRODUCT = YES; 305 | }; 306 | name = Release; 307 | }; 308 | C340433A1D6DA29B00D4E22F /* Debug */ = { 309 | isa = XCBuildConfiguration; 310 | buildSettings = { 311 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 312 | CODE_SIGN_STYLE = Manual; 313 | DEVELOPMENT_TEAM = BRZ859V993; 314 | INFOPLIST_FILE = YUFoldingTableViewDemo/Info.plist; 315 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 316 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 317 | PRODUCT_BUNDLE_IDENTIFIER = com.gaoxin.YUFoldingTableViewDemo; 318 | PRODUCT_NAME = "$(TARGET_NAME)"; 319 | PROVISIONING_PROFILE = "f1cf15d9-a7af-4f2c-8e37-21d50047054a"; 320 | PROVISIONING_PROFILE_SPECIFIER = shigaoqiangtestProfile; 321 | }; 322 | name = Debug; 323 | }; 324 | C340433B1D6DA29B00D4E22F /* Release */ = { 325 | isa = XCBuildConfiguration; 326 | buildSettings = { 327 | ASSETCATALOG_COMPILER_APPICON_NAME = AppIcon; 328 | CODE_SIGN_STYLE = Manual; 329 | DEVELOPMENT_TEAM = BRZ859V993; 330 | INFOPLIST_FILE = YUFoldingTableViewDemo/Info.plist; 331 | IPHONEOS_DEPLOYMENT_TARGET = 8.1; 332 | LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; 333 | PRODUCT_BUNDLE_IDENTIFIER = com.gaoxin.YUFoldingTableViewDemo; 334 | PRODUCT_NAME = "$(TARGET_NAME)"; 335 | PROVISIONING_PROFILE = "f1cf15d9-a7af-4f2c-8e37-21d50047054a"; 336 | PROVISIONING_PROFILE_SPECIFIER = shigaoqiangtestProfile; 337 | }; 338 | name = Release; 339 | }; 340 | /* End XCBuildConfiguration section */ 341 | 342 | /* Begin XCConfigurationList section */ 343 | C34043071D6DA29B00D4E22F /* Build configuration list for PBXProject "YUFoldingTableViewDemo" */ = { 344 | isa = XCConfigurationList; 345 | buildConfigurations = ( 346 | C34043371D6DA29B00D4E22F /* Debug */, 347 | C34043381D6DA29B00D4E22F /* Release */, 348 | ); 349 | defaultConfigurationIsVisible = 0; 350 | defaultConfigurationName = Release; 351 | }; 352 | C34043391D6DA29B00D4E22F /* Build configuration list for PBXNativeTarget "YUFoldingTableViewDemo" */ = { 353 | isa = XCConfigurationList; 354 | buildConfigurations = ( 355 | C340433A1D6DA29B00D4E22F /* Debug */, 356 | C340433B1D6DA29B00D4E22F /* Release */, 357 | ); 358 | defaultConfigurationIsVisible = 0; 359 | defaultConfigurationName = Release; 360 | }; 361 | /* End XCConfigurationList section */ 362 | }; 363 | rootObject = C34043041D6DA29B00D4E22F /* Project object */; 364 | } 365 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo.xcodeproj/project.xcworkspace/xcuserdata/administrator.xcuserdatad/UserInterfaceState.xcuserstate: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelywind/YUFoldingTableView/402b85d1b1d65bff8829b2a3e9e76579fe2d0eac/YUFoldingTableViewDemo.xcodeproj/project.xcworkspace/xcuserdata/administrator.xcuserdatad/UserInterfaceState.xcuserstate -------------------------------------------------------------------------------- /YUFoldingTableViewDemo.xcodeproj/xcuserdata/administrator.xcuserdatad/xcdebugger/Breakpoints_v2.xcbkptlist: -------------------------------------------------------------------------------- 1 | 2 | 5 | 6 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo.xcodeproj/xcuserdata/administrator.xcuserdatad/xcschemes/YUFoldingTableViewDemo.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 30 | 31 | 33 | 39 | 40 | 41 | 43 | 49 | 50 | 51 | 52 | 53 | 59 | 60 | 61 | 62 | 63 | 64 | 74 | 76 | 82 | 83 | 84 | 85 | 86 | 87 | 93 | 95 | 101 | 102 | 103 | 104 | 106 | 107 | 110 | 111 | 112 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo.xcodeproj/xcuserdata/administrator.xcuserdatad/xcschemes/xcschememanagement.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | SchemeUserState 6 | 7 | YUFoldingTableViewDemo.xcscheme 8 | 9 | orderHint 10 | 0 11 | 12 | 13 | SuppressBuildableAutocreation 14 | 15 | C340430B1D6DA29B00D4E22F 16 | 17 | primary 18 | 19 | 20 | C34043241D6DA29B00D4E22F 21 | 22 | primary 23 | 24 | 25 | C340432F1D6DA29B00D4E22F 26 | 27 | primary 28 | 29 | 30 | 31 | 32 | 33 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/AppDelegate.h: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.h 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface AppDelegate : UIResponder 12 | 13 | @property (strong, nonatomic) UIWindow *window; 14 | 15 | 16 | @end 17 | 18 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/AppDelegate.m: -------------------------------------------------------------------------------- 1 | // 2 | // AppDelegate.m 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "AppDelegate.h" 10 | 11 | @interface AppDelegate () 12 | 13 | @end 14 | 15 | @implementation AppDelegate 16 | 17 | 18 | - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions { 19 | // Override point for customization after application launch. 20 | return YES; 21 | } 22 | 23 | - (void)applicationWillResignActive:(UIApplication *)application { 24 | // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. 25 | // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. 26 | } 27 | 28 | - (void)applicationDidEnterBackground:(UIApplication *)application { 29 | // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. 30 | // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. 31 | } 32 | 33 | - (void)applicationWillEnterForeground:(UIApplication *)application { 34 | // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. 35 | } 36 | 37 | - (void)applicationDidBecomeActive:(UIApplication *)application { 38 | // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. 39 | } 40 | 41 | - (void)applicationWillTerminate:(UIApplication *)application { 42 | // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. 43 | } 44 | 45 | @end 46 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/Assets.xcassets/AppIcon.appiconset/Contents.json: -------------------------------------------------------------------------------- 1 | { 2 | "images" : [ 3 | { 4 | "idiom" : "iphone", 5 | "size" : "29x29", 6 | "scale" : "2x" 7 | }, 8 | { 9 | "idiom" : "iphone", 10 | "size" : "29x29", 11 | "scale" : "3x" 12 | }, 13 | { 14 | "idiom" : "iphone", 15 | "size" : "40x40", 16 | "scale" : "2x" 17 | }, 18 | { 19 | "idiom" : "iphone", 20 | "size" : "40x40", 21 | "scale" : "3x" 22 | }, 23 | { 24 | "idiom" : "iphone", 25 | "size" : "60x60", 26 | "scale" : "2x" 27 | }, 28 | { 29 | "idiom" : "iphone", 30 | "size" : "60x60", 31 | "scale" : "3x" 32 | }, 33 | { 34 | "idiom" : "ipad", 35 | "size" : "29x29", 36 | "scale" : "1x" 37 | }, 38 | { 39 | "idiom" : "ipad", 40 | "size" : "29x29", 41 | "scale" : "2x" 42 | }, 43 | { 44 | "idiom" : "ipad", 45 | "size" : "40x40", 46 | "scale" : "1x" 47 | }, 48 | { 49 | "idiom" : "ipad", 50 | "size" : "40x40", 51 | "scale" : "2x" 52 | }, 53 | { 54 | "idiom" : "ipad", 55 | "size" : "76x76", 56 | "scale" : "1x" 57 | }, 58 | { 59 | "idiom" : "ipad", 60 | "size" : "76x76", 61 | "scale" : "2x" 62 | } 63 | ], 64 | "info" : { 65 | "version" : 1, 66 | "author" : "xcode" 67 | } 68 | } -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/Base.lproj/LaunchScreen.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/Base.lproj/Main.storyboard: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | en 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | APPL 17 | CFBundleShortVersionString 18 | 1.0 19 | CFBundleSignature 20 | ???? 21 | CFBundleVersion 22 | 1 23 | LSRequiresIPhoneOS 24 | 25 | UILaunchStoryboardName 26 | LaunchScreen 27 | UIMainStoryboardFile 28 | Main 29 | UIRequiredDeviceCapabilities 30 | 31 | armv7 32 | 33 | UISupportedInterfaceOrientations 34 | 35 | UIInterfaceOrientationPortrait 36 | UIInterfaceOrientationLandscapeLeft 37 | UIInterfaceOrientationLandscapeRight 38 | 39 | UISupportedInterfaceOrientations~ipad 40 | 41 | UIInterfaceOrientationPortrait 42 | UIInterfaceOrientationPortraitUpsideDown 43 | UIInterfaceOrientationLandscapeLeft 44 | UIInterfaceOrientationLandscapeRight 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/ViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.h 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface ViewController : UIViewController 12 | 13 | 14 | @end 15 | 16 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/ViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // ViewController.m 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "ViewController.h" 10 | #import "YUFoldingTableView.h" 11 | #import "YUTestViewController.h" 12 | #import "YUCustomTestController.h" 13 | 14 | @interface ViewController () 15 | 16 | @property (nonatomic, weak) UITableView *tableView; 17 | 18 | @property (nonatomic, assign) YUFoldingSectionHeaderArrowPosition arrowPosition; 19 | 20 | @end 21 | 22 | @implementation ViewController 23 | 24 | - (void)viewDidLoad { 25 | [super viewDidLoad]; 26 | 27 | self.title = @"demo演示"; 28 | // 创建tableView 29 | [self setupTableView]; 30 | } 31 | 32 | // 创建tableView 33 | - (void)setupTableView 34 | { 35 | self.automaticallyAdjustsScrollViewInsets = NO; 36 | CGFloat topHeight = [[UIApplication sharedApplication] statusBarFrame].size.height + 44; 37 | UITableView *tableView = [[YUFoldingTableView alloc] initWithFrame:CGRectMake(0, topHeight, self.view.bounds.size.width, self.view.bounds.size.height - topHeight)]; 38 | _tableView = tableView; 39 | tableView.rowHeight = 50; 40 | [self.view addSubview:tableView]; 41 | tableView.delegate = self; 42 | tableView.dataSource = self; 43 | } 44 | 45 | #pragma mark - UITableViewDataSource 46 | 47 | - (NSInteger)tableView:(UITableView *)tableView numberOfRowsInSection:(NSInteger)section 48 | { 49 | return 4; 50 | } 51 | 52 | - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 53 | { 54 | static NSString *cellID = @"cellID"; 55 | UITableViewCell *cell = [tableView dequeueReusableCellWithIdentifier:cellID]; 56 | if (cell == nil) { 57 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellID]; 58 | } 59 | cell.accessoryType = UITableViewCellAccessoryDisclosureIndicator; 60 | 61 | NSString *tempStr = @"默认关闭"; 62 | switch (indexPath.row) { 63 | case 0: 64 | tempStr = @"默认关闭"; 65 | break; 66 | case 1: 67 | tempStr = @"默认展开"; 68 | break; 69 | case 2: 70 | tempStr = @"展开第一个"; 71 | break; 72 | case 3: 73 | tempStr = @"自定义 sectionHeaderView"; 74 | break; 75 | } 76 | 77 | cell.textLabel.text = [NSString stringWithFormat:@"test %ld (%@)",indexPath.row + 1, tempStr]; 78 | 79 | 80 | return cell; 81 | } 82 | 83 | - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 84 | { 85 | [tableView deselectRowAtIndexPath:indexPath animated:YES]; 86 | 87 | UITableViewCell *cell = [tableView cellForRowAtIndexPath:indexPath]; 88 | YUTestViewController *testVc = nil; 89 | if (indexPath.row < 3) { 90 | testVc = [[YUTestViewController alloc] init]; 91 | testVc.index = indexPath.row; 92 | } else { 93 | testVc = [[YUCustomTestController alloc] init]; 94 | } 95 | testVc.title = cell.textLabel.text; 96 | testVc.arrowPosition = indexPath.row; 97 | [self.navigationController pushViewController:testVc animated:YES]; 98 | } 99 | 100 | @end 101 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/YUCustomHeaderView.h: -------------------------------------------------------------------------------- 1 | // 2 | // YUCustomHeaderView.h 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by caiyi on 2018/2/6. 6 | // Copyright © 2018年 timelywind. All rights reserved. 7 | // 8 | 9 | #import 10 | 11 | @interface YUCustomHeaderView : UITableViewHeaderFooterView 12 | 13 | @property (nonatomic, copy) NSString *title; 14 | 15 | @property (nonatomic, copy) NSString *descriptionText; 16 | 17 | @end 18 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/YUCustomHeaderView.m: -------------------------------------------------------------------------------- 1 | // 2 | // YUCustomHeaderView.m 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by caiyi on 2018/2/6. 6 | // Copyright © 2018年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "YUCustomHeaderView.h" 10 | 11 | 12 | @interface YUCustomHeaderView () 13 | 14 | @property (nonatomic, weak) UILabel *titleLabel; 15 | 16 | @property (nonatomic, weak) UILabel *descriptionLabel; 17 | 18 | @end 19 | 20 | @implementation YUCustomHeaderView 21 | 22 | - (instancetype)initWithReuseIdentifier:(NSString *)reuseIdentifier 23 | { 24 | if (self = [super initWithReuseIdentifier:reuseIdentifier]) { 25 | 26 | self.contentView.backgroundColor = [UIColor whiteColor]; 27 | // 设置子视图 28 | [self setupSubViews]; 29 | 30 | } 31 | return self; 32 | } 33 | 34 | - (void)setupSubViews 35 | { 36 | // titleLabel 37 | UILabel *titleLabel = [[UILabel alloc] init]; 38 | [self.contentView addSubview:titleLabel]; 39 | _titleLabel = titleLabel; 40 | titleLabel.font = [UIFont systemFontOfSize:15]; 41 | titleLabel.textColor = [UIColor blackColor]; 42 | 43 | // descriptionLabel 44 | UILabel *descriptionLabel = [[UILabel alloc] init]; 45 | [self.contentView addSubview:descriptionLabel]; 46 | _descriptionLabel = descriptionLabel; 47 | descriptionLabel.font = [UIFont systemFontOfSize:13]; 48 | descriptionLabel.textColor = [UIColor grayColor]; 49 | } 50 | 51 | - (void)setTitle:(NSString *)title 52 | { 53 | _title = title; 54 | 55 | _titleLabel.text = title; 56 | } 57 | 58 | - (void)setDescriptionText:(NSString *)descriptionText 59 | { 60 | _descriptionText = descriptionText; 61 | 62 | _descriptionLabel.text = descriptionText; 63 | } 64 | 65 | - (void)layoutSubviews 66 | { 67 | [super layoutSubviews]; 68 | 69 | CGSize cellSize = self.bounds.size; 70 | [_titleLabel sizeToFit]; 71 | _titleLabel.frame = CGRectMake(12, (cellSize.height - _titleLabel.bounds.size.height)/2.0, _titleLabel.bounds.size.width, _titleLabel.bounds.size.height); 72 | 73 | [_descriptionLabel sizeToFit]; 74 | _descriptionLabel.frame = CGRectMake(cellSize.width - _descriptionLabel.bounds.size.width - 15, (cellSize.height - _descriptionLabel.bounds.size.height)/2.0, _descriptionLabel.bounds.size.width, _descriptionLabel.bounds.size.height); 75 | } 76 | 77 | 78 | @end 79 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/YUCustomTestController.h: -------------------------------------------------------------------------------- 1 | // 2 | // YUCustomTestController.h 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by caiyi on 2018/2/6. 6 | // Copyright © 2018年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "YUTestViewController.h" 10 | 11 | @interface YUCustomTestController : YUTestViewController 12 | 13 | @end 14 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/YUCustomTestController.m: -------------------------------------------------------------------------------- 1 | // 2 | // YUCustomTestController.m 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by caiyi on 2018/2/6. 6 | // Copyright © 2018年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "YUCustomTestController.h" 10 | #import "YUCustomHeaderView.h" 11 | 12 | @interface YUCustomTestController () 13 | 14 | @end 15 | 16 | @implementation YUCustomTestController 17 | 18 | - (void)viewDidLoad { 19 | [super viewDidLoad]; 20 | } 21 | 22 | - (UIView *)yuFoldingTableView:(YUFoldingTableView *)yuTableView viewForHeaderInSection:(NSInteger)section 23 | { 24 | static NSString *headerIdentifier = @"headerIdentifier"; 25 | YUCustomHeaderView *headerFooterView = [yuTableView dequeueReusableHeaderFooterViewWithIdentifier:headerIdentifier]; 26 | if (headerFooterView == nil) { 27 | headerFooterView = [[YUCustomHeaderView alloc] initWithReuseIdentifier:headerIdentifier]; 28 | } 29 | 30 | NSLog(@"当前状态%@", yuTableView.statusArray[section]); 31 | 32 | 33 | headerFooterView.contentView.backgroundColor = [UIColor colorWithRed:200/255.0 green:200/255.0 blue:200/255.0 alpha:0.2]; 34 | headerFooterView.title = [NSString stringWithFormat:@"标题 - %ld", section]; 35 | headerFooterView.descriptionText = [NSString stringWithFormat:@"自定义的sectionHeaderView - %ld", section]; 36 | return headerFooterView; 37 | } 38 | 39 | - (void)yuFoldingTableView:(YUFoldingTableView *)yuTableView didSelectHeaderViewAtSection:(NSInteger)section 40 | { 41 | NSLog(@"点击了headerView - %ld", section); 42 | } 43 | 44 | @end 45 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/YUTestViewController.h: -------------------------------------------------------------------------------- 1 | // 2 | // YUTestViewController.h 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/25. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "YUFoldingTableView.h" 11 | 12 | @interface YUTestViewController : UIViewController 13 | 14 | @property (nonatomic, assign) YUFoldingSectionHeaderArrowPosition arrowPosition; 15 | 16 | @property (nonatomic, assign) NSInteger index; 17 | 18 | @end 19 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/YUTestViewController.m: -------------------------------------------------------------------------------- 1 | // 2 | // YUTestViewController.m 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/25. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import "YUTestViewController.h" 10 | 11 | @interface YUTestViewController () 12 | 13 | @property (nonatomic, weak) YUFoldingTableView *foldingTableView; 14 | 15 | 16 | @end 17 | 18 | @implementation YUTestViewController 19 | 20 | - (void)viewDidLoad { 21 | [super viewDidLoad]; 22 | 23 | self.view.backgroundColor = [UIColor whiteColor]; 24 | // 创建tableView 25 | [self setupFoldingTableView]; 26 | } 27 | 28 | // 创建tableView 29 | - (void)setupFoldingTableView 30 | { 31 | self.automaticallyAdjustsScrollViewInsets = NO; 32 | CGFloat topHeight = [[UIApplication sharedApplication] statusBarFrame].size.height + 44; 33 | YUFoldingTableView *foldingTableView = [[YUFoldingTableView alloc] initWithFrame:CGRectMake(0, topHeight, self.view.bounds.size.width, self.view.bounds.size.height - topHeight)]; 34 | _foldingTableView = foldingTableView; 35 | 36 | [self.view addSubview:foldingTableView]; 37 | foldingTableView.foldingDelegate = self; 38 | 39 | if (self.arrowPosition) { 40 | foldingTableView.foldingState = YUFoldingSectionStateShow; 41 | } 42 | if (self.index == 2) { 43 | foldingTableView.sectionStateArray = @[@"1", @"0", @"0"]; 44 | } 45 | } 46 | 47 | #pragma mark - YUFoldingTableViewDelegate / required(必须实现的代理) 48 | - (NSInteger )numberOfSectionForYUFoldingTableView:(YUFoldingTableView *)yuTableView 49 | { 50 | return 6; 51 | } 52 | - (NSInteger )yuFoldingTableView:(YUFoldingTableView *)yuTableView numberOfRowsInSection:(NSInteger )section 53 | { 54 | return 3; 55 | } 56 | - (CGFloat )yuFoldingTableView:(YUFoldingTableView *)yuTableView heightForHeaderInSection:(NSInteger )section 57 | { 58 | return 50; 59 | } 60 | - (CGFloat )yuFoldingTableView:(YUFoldingTableView *)yuTableView heightForRowAtIndexPath:(NSIndexPath *)indexPath 61 | { 62 | return 50; 63 | } 64 | - (UITableViewCell *)yuFoldingTableView:(YUFoldingTableView *)yuTableView cellForRowAtIndexPath:(NSIndexPath *)indexPath 65 | { 66 | static NSString *cellIdentifier = @"cellIdentifier"; 67 | UITableViewCell *cell = [yuTableView dequeueReusableCellWithIdentifier:cellIdentifier]; 68 | if (cell == nil) { 69 | cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; 70 | } 71 | cell.textLabel.text = [NSString stringWithFormat:@"Row %ld -- section %ld", (long)indexPath.row, (long)indexPath.section]; 72 | 73 | return cell; 74 | } 75 | #pragma mark - YUFoldingTableViewDelegate / optional (可选择实现的) 76 | 77 | - (NSString *)yuFoldingTableView:(YUFoldingTableView *)yuTableView titleForHeaderInSection:(NSInteger)section 78 | { 79 | return [NSString stringWithFormat:@"Title %ld",(long)section]; 80 | } 81 | 82 | - (void )yuFoldingTableView:(YUFoldingTableView *)yuTableView didSelectRowAtIndexPath:(NSIndexPath *)indexPath 83 | { 84 | [yuTableView deselectRowAtIndexPath:indexPath animated:YES]; 85 | } 86 | 87 | // 返回箭头的位置 88 | - (YUFoldingSectionHeaderArrowPosition)perferedArrowPositionForYUFoldingTableView:(YUFoldingTableView *)yuTableView 89 | { 90 | // 没有赋值,默认箭头在左 91 | return self.arrowPosition ? :YUFoldingSectionHeaderArrowPositionLeft; 92 | } 93 | 94 | - (NSString *)yuFoldingTableView:(YUFoldingTableView *)yuTableView descriptionForHeaderInSection:(NSInteger )section 95 | { 96 | return @"detailText"; 97 | } 98 | 99 | //- (UIColor *)yuFoldingTableView:(YUFoldingTableView *)yuTableView backgroundColorForHeaderInSection:(NSInteger)section 100 | //{ 101 | // 102 | // return self.arrowPosition ? [UIColor whiteColor] : [UIColor colorWithRed:102/255.f green:102/255.f blue:255/255.f alpha:1.f]; 103 | //} 104 | // 105 | //- (UIColor *)yuFoldingTableView:(YUFoldingTableView *)yuTableView textColorForTitleInSection:(NSInteger)section 106 | //{ 107 | // return self.arrowPosition ? [UIColor redColor] : [UIColor whiteColor]; 108 | //} 109 | 110 | @end 111 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/main.m: -------------------------------------------------------------------------------- 1 | // 2 | // main.m 3 | // YUFoldingTableViewDemo 4 | // 5 | // Created by administrator on 16/8/24. 6 | // Copyright © 2016年 timelywind. All rights reserved. 7 | // 8 | 9 | #import 10 | #import "AppDelegate.h" 11 | 12 | int main(int argc, char * argv[]) { 13 | @autoreleasepool { 14 | return UIApplicationMain(argc, argv, nil, NSStringFromClass([AppDelegate class])); 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /YUFoldingTableViewDemo/效果图/效果图.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/timelywind/YUFoldingTableView/402b85d1b1d65bff8829b2a3e9e76579fe2d0eac/YUFoldingTableViewDemo/效果图/效果图.gif --------------------------------------------------------------------------------