Skip to content

Commit 484c9df

Browse files
committed
Removed 'sectionsAlwaysOpen' and replaced it with a delegate method: 'canInteractWithHeaderAtSection'.
1 parent 7f97f73 commit 484c9df

File tree

4 files changed

+64
-102
lines changed

4 files changed

+64
-102
lines changed

FZAccordionTableView/FZAccordionTableView.h

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,8 @@
3232

3333
/*!
3434
@desc The section which this header view is part of.
35+
36+
Deprecated. Use sectionForHeaderView: instead.
3537
*/
3638
@property (nonatomic, readonly) NSInteger section DEPRECATED_MSG_ATTRIBUTE("Use sectionForHeaderView: instead.");
3739

@@ -57,8 +59,7 @@
5759
5860
If set to NO, all sections can be closed.
5961
60-
Note that this does NOT influence 'sectionsAlwaysOpen.' Also,
61-
use 'sectionsInitiallyOpen' to specify which section should be
62+
Use 'sectionsInitiallyOpen' to specify which section should be
6263
open at the start, otherwise, all sections will be closed at
6364
the start even if the property is set to YES.
6465
@@ -79,9 +80,9 @@
7980
The headers of these sections will not call the
8081
FZAccordionTableViewDelegate methods.
8182
82-
Must be set before any data is loaded.
83+
Deprecated. Use tableView:canInteractWithHeaderAtSection: instead.
8384
*/
84-
@property (strong, nonatomic, nullable) NSSet <NSNumber *> *sectionsAlwaysOpen;
85+
@property (strong, nonatomic, nullable) NSSet <NSNumber *> *sectionsAlwaysOpen DEPRECATED_MSG_ATTRIBUTE("Use tableView:canInteractWithHeaderAtSection: instead.");
8586

8687
/*!
8788
@desc Enables the fading of cells for the last two rows of the
@@ -123,6 +124,18 @@
123124

124125
@optional
125126

127+
/**
128+
@desc Implement to respond to which sections can be interacted with.
129+
130+
If NO is returned for a section, the section can neither be opened or closed.
131+
It stays in it's initial state no matter what.
132+
133+
Use 'initialOpenSections' to mark a section open from the start.
134+
135+
The default return value is YES.
136+
*/
137+
- (BOOL)tableView:(FZAccordionTableView * _Nonnull)tableView canInteractWithHeaderAtSection:(NSInteger)section;
138+
126139
- (void)tableView:(FZAccordionTableView * _Nonnull)tableView willOpenSection:(NSInteger)section withHeader:(UITableViewHeaderFooterView * _Nonnull)header;
127140
- (void)tableView:(FZAccordionTableView * _Nonnull)tableView didOpenSection:(NSInteger)section withHeader:(UITableViewHeaderFooterView * _Nonnull)header;
128141

FZAccordionTableView/FZAccordionTableView.m

Lines changed: 34 additions & 63 deletions
Original file line numberDiff line numberDiff line change
@@ -136,10 +136,6 @@ - (BOOL)isSectionOpen:(NSInteger)section {
136136
return [self.sectionInfos[section] isOpen];
137137
}
138138

139-
- (BOOL)isAlwaysOpenedSection:(NSInteger)section {
140-
return [self.sectionsAlwaysOpen containsObject:@(section)];
141-
}
142-
143139
- (void)markSection:(NSInteger)section open:(BOOL)open {
144140
[self.sectionInfos[section] setOpen:open];
145141
}
@@ -186,6 +182,14 @@ - (NSInteger)sectionForHeaderView:(UITableViewHeaderFooterView *)headerView {
186182
return section;
187183
}
188184

185+
- (BOOL)canInteractWithHeaderAtSection:(NSInteger)section {
186+
BOOL canInteractWithHeader = YES;
187+
if ([self.delegate respondsToSelector:@selector(tableView:canInteractWithHeaderAtSection:)]) {
188+
canInteractWithHeader = [self.subclassDelegate tableView:self canInteractWithHeaderAtSection:section];
189+
}
190+
return canInteractWithHeader;
191+
}
192+
189193
#pragma mark - UITableView Overrides -
190194

191195
- (void)setDelegate:(id<UITableViewDelegate, FZAccordionTableViewDelegate>)delegate {
@@ -207,18 +211,6 @@ - (void)deleteSections:(NSIndexSet *)sections withRowAnimation:(UITableViewRowAn
207211
}];
208212

209213
[super deleteSections:sections withRowAnimation:animation];
210-
211-
// Re-open any sections that were closed by deletion, but
212-
// must be always open.
213-
if (self.sectionsAlwaysOpen.count > 0) {
214-
[sections enumerateIndexesWithOptions:NSEnumerationReverse usingBlock:^(NSUInteger section, BOOL * _Nonnull stop) {
215-
if ([self.sectionsAlwaysOpen containsObject:@(section)] && ![self isSectionOpen:section]) {
216-
FZAccordionTableViewHeaderView *sectionHeaderView = (FZAccordionTableViewHeaderView *)[self headerViewForSection:section];
217-
NSArray *indexPathsToModify = [self getIndexPathsForSection:section];
218-
[self openSection:section withHeaderView:sectionHeaderView andIndexPaths:indexPathsToModify];
219-
}
220-
}];
221-
}
222214
}
223215

224216
- (void)insertRowsAtIndexPaths:(NSArray<NSIndexPath *> *)indexPaths withRowAnimation:(UITableViewRowAnimation)animation {
@@ -253,23 +245,17 @@ - (void)setInitialOpenSections:(NSSet *)initialOpenedSections {
253245
_mutableInitialOpenSections = [initialOpenedSections mutableCopy];
254246
}
255247

256-
- (void)setSectionsAlwaysOpen:(NSSet<NSNumber *> *)sectionsAlwaysOpen {
257-
NSAssert(self.sectionInfos.count == 0, @"'sectionsAlwaysOpen' MUST be set before the tableView has started loading data.");
258-
_sectionsAlwaysOpen = sectionsAlwaysOpen;
259-
}
260-
261248
#pragma mark - FZAccordionTableViewHeaderViewDelegate -
262249

263250
- (void)tappedHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView {
264251
NSParameterAssert(sectionHeaderView);
265252

266253
NSInteger section = [self sectionForHeaderView:sectionHeaderView];
267254

268-
// Do not interact with sections that are always opened
269-
if ([self isAlwaysOpenedSection:section]) {
255+
if (![self canInteractWithHeaderAtSection:section]) {
270256
return;
271257
}
272-
258+
273259
// Keep at least one section open
274260
if (self.keepOneSectionOpen) {
275261
NSInteger countOfOpenSections = 0;
@@ -279,31 +265,22 @@ - (void)tappedHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView {
279265
countOfOpenSections++;
280266
}
281267
}
282-
283-
if (self.sectionsAlwaysOpen.count > 0) {
284-
// 'sectionsAlwaysOpen' does not have an influence
285-
// on 'keepOneSectionOpen'
286-
countOfOpenSections -= self.sectionsAlwaysOpen.count;
287-
}
288-
268+
289269
if (countOfOpenSections == 1 && [self isSectionOpen:section]) {
290270
return;
291271
}
292272
}
293273

294274
BOOL openSection = [self isSectionOpen:section];
295275

296-
// Create an array of index paths that will be inserted/removed
297-
NSArray *indexPathsToModify = [self getIndexPathsForSection:section];
298-
299276
[self beginUpdates];
300277

301278
// Insert/remove rows to simulate opening/closing of a header
302279
if (!openSection) {
303-
[self openSection:section withHeaderView:sectionHeaderView andIndexPaths:indexPathsToModify];
280+
[self openSection:section withHeaderView:sectionHeaderView];
304281
}
305282
else { // The section is currently open
306-
[self closeSection:section withHeaderView:sectionHeaderView andIndexPaths:indexPathsToModify];
283+
[self closeSection:section withHeaderView:sectionHeaderView];
307284
}
308285

309286
// Auto-collapse the rest of the opened sections
@@ -314,7 +291,11 @@ - (void)tappedHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView {
314291
[self endUpdates];
315292
}
316293

317-
- (void)openSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView andIndexPaths:(NSArray *)indexPathsToModify {
294+
- (void)openSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView {
295+
if (![self canInteractWithHeaderAtSection:section]) {
296+
return;
297+
}
298+
318299
if ([self.subclassDelegate respondsToSelector:@selector(tableView:willOpenSection:withHeader:)]) {
319300
[self.subclassDelegate tableView:self willOpenSection:section withHeader:sectionHeaderView];
320301
}
@@ -337,6 +318,7 @@ - (void)openSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeade
337318
}
338319
}
339320

321+
NSArray *indexPathsToModify = [self getIndexPathsForSection:section];
340322
[self markSection:section open:YES];
341323
[self beginUpdates];
342324
[CATransaction setCompletionBlock:^{
@@ -348,11 +330,19 @@ - (void)openSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeade
348330
[self endUpdates];
349331
}
350332

351-
- (void)closeSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView andIndexPaths:(NSArray *)indexPathsToModify {
333+
- (void)closeSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView {
334+
[self closeSection:section withHeaderView:sectionHeaderView rowAnimation:UITableViewRowAnimationTop];
335+
}
336+
337+
- (void)closeSection:(NSInteger)section withHeaderView:(FZAccordionTableViewHeaderView *)sectionHeaderView rowAnimation:(UITableViewRowAnimation)rowAnimation {
338+
if (![self canInteractWithHeaderAtSection:section]) {
339+
return;
340+
}
341+
352342
if ([self.subclassDelegate respondsToSelector:@selector(tableView:willCloseSection:withHeader:)]) {
353343
[self.subclassDelegate tableView:self willCloseSection:section withHeader:sectionHeaderView];
354344
}
355-
345+
NSArray *indexPathsToModify = [self getIndexPathsForSection:section];
356346
[self markSection:section open:NO];
357347
[self beginUpdates];
358348
[CATransaction setCompletionBlock: ^{
@@ -369,18 +359,14 @@ - (void)autoCollapseAllSectionsExceptSection:(NSInteger)section {
369359
NSMutableSet *sectionsToClose = [[NSMutableSet alloc] init];
370360
for (NSInteger i = 0; i < self.numberOfSections; i++) {
371361
FZAccordionTableViewSectionInfo *sectionInfo = self.sectionInfos[i];
372-
if (section != i && sectionInfo.isOpen && ![self isAlwaysOpenedSection:i]) {
362+
if (section != i && sectionInfo.isOpen) {
373363
[sectionsToClose addObject:@(i)];
374364
}
375365
}
376366

377367
// Close the found sections
378368
for (NSNumber *sectionToClose in sectionsToClose) {
379-
380-
if ([self.subclassDelegate respondsToSelector:@selector(tableView:willCloseSection:withHeader:)]) {
381-
[self.subclassDelegate tableView:self willCloseSection:sectionToClose.integerValue withHeader:[self headerViewForSection:sectionToClose.integerValue]];
382-
}
383-
369+
384370
// Change animations based off which sections are closed
385371
UITableViewRowAnimation closeAnimation = UITableViewRowAnimationTop;
386372
if (section < sectionToClose.integerValue) {
@@ -390,22 +376,11 @@ - (void)autoCollapseAllSectionsExceptSection:(NSInteger)section {
390376
if (!self.allowsMultipleSelection &&
391377
(sectionToClose.integerValue == self.sectionInfos.count - 1 ||
392378
sectionToClose.integerValue == self.sectionInfos.count - 2)) {
393-
closeAnimation = UITableViewRowAnimationFade;
394-
}
379+
closeAnimation = UITableViewRowAnimationFade;
380+
}
395381
}
396382

397-
// Delete the cells for section that is closing
398-
NSArray *indexPathsToDelete = [self getIndexPathsForSection:sectionToClose.integerValue];
399-
[self markSection:sectionToClose.integerValue open:NO];
400-
401-
[self beginUpdates];
402-
[CATransaction setCompletionBlock:^{
403-
if ([self.subclassDelegate respondsToSelector:@selector(tableView:didCloseSection:withHeader:)]) {
404-
[self.subclassDelegate tableView:self didCloseSection:sectionToClose.integerValue withHeader:[self headerViewForSection:sectionToClose.integerValue]];
405-
}
406-
}];
407-
[self deleteRowsAtIndexPaths:indexPathsToDelete withRowAnimation:closeAnimation];
408-
[self endUpdates];
383+
[self closeSection:sectionToClose.integerValue withHeaderView:(FZAccordionTableViewHeaderView *)[self headerViewForSection:sectionToClose.integerValue] rowAnimation:closeAnimation];
409384
}
410385
}
411386

@@ -429,10 +404,6 @@ - (NSInteger)numberOfSectionsInTableView:(UITableView *)tableView {
429404
section.open = YES;
430405
[self.mutableInitialOpenSections removeObject:@(i)];
431406
}
432-
// Account for sections that are always open
433-
else {
434-
section.open = [self.sectionsAlwaysOpen containsObject:@(i)];
435-
}
436407

437408
[self.sectionInfos addObject:section];
438409
}

Tests/Testing_Example/FZAccordionTableViewTestApp/MainViewController.m

Lines changed: 13 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
static NSString *const kTableViewCellReuseIdentifier = @"TableViewCellReuseIdentifier";
1414

15-
@interface MainViewController () <UITableViewDataSource, UITableViewDelegate>
15+
@interface MainViewController () <UITableViewDataSource, UITableViewDelegate, FZAccordionTableViewDelegate>
1616

1717
@end
1818

@@ -24,6 +24,7 @@ - (void)viewDidLoad {
2424
[super viewDidLoad];
2525
[self setupData];
2626
[self setupTableView];
27+
// [self executeTestMethods];
2728
}
2829

2930
- (void)setupData {
@@ -45,22 +46,21 @@ - (void)setupTableView {
4546
*/
4647
- (void)executeTestMethods {
4748
[self connectTableView];
48-
// [self testSettingProperties];
49+
[self testSettingProperties];
4950
// [self testAddingSection];
5051
// [self testDeletingMultipleSectionsAtTheSameTime];
5152
}
5253

5354
- (void)connectTableView {
54-
5555
self.tableView.delegate = self;
5656
self.tableView.dataSource = self;
5757
}
5858

5959
- (void)testSettingProperties {
60-
// self.tableView.allowsMultipleSelectionDuringEditing = NO;
60+
self.tableView.allowsMultipleSelectionDuringEditing = NO;
6161
// self.tableView.allowMultipleSectionsOpen = NO;
62-
// self.tableView.keepOneSectionOpen = YES;
63-
// self.tableView.initialOpenSections = [NSSet setWithObjects:@(1), nil];
62+
// self.tableView.keepOneSectionOpen = YES;
63+
self.tableView.initialOpenSections = [NSSet setWithObjects:@(4), @(6), nil];
6464
}
6565

6666
- (void)testAddingSection {
@@ -72,7 +72,6 @@ - (void)testAddingSection {
7272
}
7373

7474
- (void)testDeletingMultipleSectionsAtTheSameTime {
75-
self.tableView.sectionsAlwaysOpen =[NSSet setWithObjects:@(0), @(2), nil];
7675
dispatch_after(dispatch_time(DISPATCH_TIME_NOW, (int64_t)(2 * NSEC_PER_SEC)), dispatch_get_main_queue(), ^{
7776
NSMutableIndexSet *indexSet = [NSMutableIndexSet new];
7877
[indexSet addIndex:0];
@@ -166,4 +165,11 @@ - (void)tableView:(FZAccordionTableView *)tableView didCloseSection:(NSInteger)s
166165
[self.delegate tableView:tableView didCloseSection:section withHeader:header];
167166
}
168167

168+
- (BOOL)tableView:(FZAccordionTableView *)tableView canInteractWithHeaderAtSection:(NSInteger)section {
169+
if ([self.delegate respondsToSelector:@selector(tableView:canInteractWithHeaderAtSection:)]) {
170+
return [self.delegate tableView:tableView canInteractWithHeaderAtSection:section];
171+
}
172+
return YES;
173+
}
174+
169175
@end

Tests/Testing_Example/FZAccordionTableViewUnitTests/FZAccordionTableViewInitializationTests.m

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -52,32 +52,4 @@ - (void)testInitialOpenSections {
5252
}
5353
}
5454

55-
#pragma mark - Property 'sectionsAlwaysOpen' Tests -
56-
57-
- (void)testSectionsAlwaysOpen {
58-
NSMutableArray *sectionsAlwaysOpen = [NSMutableArray new];
59-
for (NSInteger i = 0; i < self.mainViewController.sections.count; i++) {
60-
[sectionsAlwaysOpen addObject:@(i)];
61-
}
62-
self.tableView.sectionsAlwaysOpen = [NSSet setWithArray:sectionsAlwaysOpen];
63-
64-
[self.mainViewController connectTableView];
65-
66-
// Test that no matter which way you toggle the section, the section remains open.
67-
for (NSInteger i = 0; i < self.tableView.numberOfSections; i++) {
68-
69-
[self waitForHeaderViewInSection:i];
70-
[self.tableView toggleSection:i];
71-
72-
XCTAssert([self.tableView isSectionOpen:i], @"Section %d should be open.", (int)i);
73-
}
74-
for (NSInteger i = 0; i < self.tableView.numberOfSections; i++) {
75-
76-
[self waitForHeaderViewInSection:i];
77-
[self.tableView toggleSection:i];
78-
79-
XCTAssert([self.tableView isSectionOpen:i], @"Section %d should be open.", (int)i);
80-
}
81-
}
82-
8355
@end

0 commit comments

Comments
 (0)