Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 25 additions & 0 deletions ExpandTableView/JKExpandTableView.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,9 @@

#import <UIKit/UIKit.h>
#import "JKMultiSelectSubTableViewCell.h"
#import "JKSingleSelectSubTableViewCell.h"
#import "JKParentTableViewCell.h"
#import "JKSubTableViewCellCell.h"

/*!
@protocol JKExpandTableViewDelegate
Expand All @@ -24,6 +27,9 @@
- (BOOL) shouldSupportMultipleSelectableChildrenAtParentIndex:(NSInteger) parentIndex;

@optional

- (BOOL)singleChoiceBehavior;

/*! Optional method the delegate should implement to get notified when a child is clicked on.

@param childIndex The child index in question
Expand All @@ -42,6 +48,19 @@
*/
- (void) tableView:(UITableView *)tableView didSelectParentCellAtIndex:(NSInteger) parentIndex;

/*! Optional method to override and provide your custom cell for multi selection mode.

*/
- (JKSubTableViewCellCell *)tableView:(UITableView *)tableView multiSelectCellForRowAtIndexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex;
/*! Optional method to override and provide your custom cell for single selection mode.

*/
- (JKSubTableViewCellCell *)tableView:(UITableView *)tableView singleSelectCellForRowAtIndexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex;
/*! Optional method to override and provide your custom cell for parent cells.

*/
- (JKParentTableViewCell *)tableView:(UITableView *)tableView parentCellForRowAtIndexPath:(NSIndexPath *)indexPath;

/*! Optional method to set custom foreground color.

@return UIColor
Expand Down Expand Up @@ -106,6 +125,12 @@
- (BOOL) shouldDisplaySelectedStateForCellAtChildIndex:(NSInteger) childIndex withinParentCellIndex:(NSInteger) parentIndex;

@optional
/*! Optional method
*/
- (CGFloat)heightForParentCell;
/*! Optional method
*/
- (CGFloat)heightForChildCell;

/*! Optional method

Expand Down
91 changes: 83 additions & 8 deletions ExpandTableView/JKExpandTableView.m
Original file line number Diff line number Diff line change
Expand Up @@ -7,14 +7,18 @@
//

#import "JKExpandTableView.h"
#import "JKParentTableViewCell.h"
#import "JKMultiSelectSubTableViewCell.h"
#import "JKSingleSelectSubTableViewCell.h"

@interface JKExpandTableView ()

@property (nonatomic, assign) NSInteger lastExpandedPosition;

@end

@implementation JKExpandTableView
@synthesize tableViewDelegate, expansionStates;

#define HEIGHT_FOR_CELL 44.0
#define HEIGHT_FOR_PARENT_CELL 44.0
#define HEIGHT_FOR_CHILD_CELL 44.0

- (id)initWithFrame:(CGRect)frame dataSource:dataDelegate tableViewDelegate:tableDelegate {
self = [super initWithFrame:frame style:UITableViewStylePlain];
Expand Down Expand Up @@ -52,6 +56,7 @@ - (void)insertRowsAtIndexPaths:(NSArray *)indexPaths withRowAnimation:(UITableVi
*/

- (void) initialize {
self.lastExpandedPosition = -1;
[self setDataSource:self];
[self setDelegate:self];
self.separatorStyle = UITableViewCellSeparatorStyleSingleLine;
Expand All @@ -69,6 +74,11 @@ - (void) setDataSourceDelegate:(id) deleg {
[self initExpansionStates];
}

- (void)reloadData {
[self initExpansionStates];
[super reloadData];
}

- (void) initExpansionStates
{
// all collapsed initially
Expand All @@ -84,10 +94,33 @@ - (void) expandForParentAtRow: (NSInteger) row {
if ([[self.expansionStates objectAtIndex:parentIndex] boolValue]) {
return;
}

// update expansionStates so backing data is ready before calling insertRowsAtIndexPaths
[self.expansionStates replaceObjectAtIndex:parentIndex withObject:@"YES"];

[self insertRowsAtIndexPaths:[NSArray arrayWithObject:[NSIndexPath indexPathForRow:(row + 1) inSection:0]] withRowAnimation:UITableViewRowAnimationFade];

[self collapsePreviousRow:row];
}

- (void)collapsePreviousRow:(NSInteger)currentExpandedRow {
// used to solve bug when the last expanded position is after current position
BOOL offset = self.lastExpandedPosition > [self parentIndexForRow:currentExpandedRow];
if ([self.tableViewDelegate respondsToSelector:@selector(singleChoiceBehavior)]
&& [self.tableViewDelegate singleChoiceBehavior]
&& self.lastExpandedPosition != -1
&& currentExpandedRow != self.lastExpandedPosition) {
NSInteger pos = offset? self.lastExpandedPosition + 1 : self.lastExpandedPosition;
[self collapseForParentAtRow:pos];

NSIndexPath *indexPath = [NSIndexPath indexPathForRow:pos inSection:0];
UITableViewCell *selectedCell = [self cellForRowAtIndexPath:indexPath];
if ([selectedCell isKindOfClass:[JKParentTableViewCell class]]) {
JKParentTableViewCell * pCell = (JKParentTableViewCell *)selectedCell;
[self animateParentCellIconExpand:NO forCell:pCell];
}
}
self.lastExpandedPosition = [self parentIndexForRow:currentExpandedRow];
}

- (void) collapseForParentAtRow: (NSInteger) row {
Expand Down Expand Up @@ -189,6 +222,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
BOOL isMultiSelect = [self.tableViewDelegate shouldSupportMultipleSelectableChildrenAtParentIndex:parentIndex];
if (isMultiSelect) {
JKMultiSelectSubTableViewCell *cell = (JKMultiSelectSubTableViewCell *)[self dequeueReusableCellWithIdentifier:CellIdentifier_MultiSelect];

if (cell == nil) {
cell = [[JKMultiSelectSubTableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:CellIdentifier_MultiSelect];
} else {
Expand All @@ -210,6 +244,7 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}

NSLog(@"cellForRowAtIndexPath MultiSelect parentIndex: %ld", (long)parentIndex);
[cell setChildCellHeight:[self heightForChildCell]];
[cell setParentIndex:parentIndex];
[cell setDelegate:self];
[cell reload];
Expand Down Expand Up @@ -242,14 +277,22 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N
}

NSLog(@"cellForRowAtIndexPath SingleSelect parentIndex: %ld", (long)parentIndex);
[cell setChildCellHeight:[self heightForChildCell]];
[cell setParentIndex:parentIndex];
[cell setDelegate:self];
[cell reload];
return cell;
}
} else {
JKParentTableViewCell *cell = nil;
if ([self.tableViewDelegate respondsToSelector:@selector(tableView:parentCellForRowAtIndexPath:)]) {
NSInteger parentRow = [self parentIndexForRow:indexPath.row];
cell = [self.tableViewDelegate tableView:tableView parentCellForRowAtIndexPath:[NSIndexPath indexPathForRow:parentRow inSection:0]];
}
// regular parent cell
JKParentTableViewCell *cell = (JKParentTableViewCell *)[self dequeueReusableCellWithIdentifier:CellIdentifier_Parent];
if (cell == nil) {
cell = (JKParentTableViewCell *)[self dequeueReusableCellWithIdentifier:CellIdentifier_Parent];
}
if (cell == nil) {
cell = [[JKParentTableViewCell alloc] initWithReuseIdentifier:CellIdentifier_Parent];
} else {
Expand Down Expand Up @@ -285,7 +328,6 @@ - (UITableViewCell *)tableView:(UITableView *)tableView cellForRowAtIndexPath:(N

[cell setParentIndex:parentIndex];
[cell selectionIndicatorState:[self hasSelectedChild:parentIndex]];
//[cell setupDisplay];

return cell;
}
Expand All @@ -300,9 +342,9 @@ -(CGFloat)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPat
if (isExpansionCell) {
NSInteger parentIndex = [self parentIndexForRow:row];
NSInteger numberOfChildren = [self.dataSourceDelegate numberOfChildCellsUnderParentIndex:parentIndex];
return HEIGHT_FOR_CELL * numberOfChildren;
return [self heightForChildCell] * numberOfChildren;
} else {
return HEIGHT_FOR_CELL;
return [self heightForParentCell];
}
}

Expand Down Expand Up @@ -332,6 +374,39 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
}

#pragma mark - JKMultiSelectSubTableViewCellDelegate

- (JKSubTableViewCellCell *)tableView:(UITableView *)tableView multiSelectCellForRowAtIndexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex {
JKSubTableViewCellCell *cell;
if ([self.tableViewDelegate respondsToSelector:@selector(tableView:multiSelectCellForRowAtIndexPath:withInParentCellIndex:)]) {
cell = [self.tableViewDelegate tableView:tableView multiSelectCellForRowAtIndexPath:indexPath withInParentCellIndex:parentIndex];
}
return cell;
}

- (JKSubTableViewCellCell *)tableView:(UITableView *)tableView singleSelectCellForRowAtIndexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex {
JKSubTableViewCellCell *cell;
if ([self.tableViewDelegate respondsToSelector:@selector(tableView:singleSelectCellForRowAtIndexPath:withInParentCellIndex:)]) {
cell = [self.tableViewDelegate tableView:tableView singleSelectCellForRowAtIndexPath:indexPath withInParentCellIndex:parentIndex];
}
return cell;
}

- (CGFloat)heightForParentCell {
CGFloat heightForParentCell = HEIGHT_FOR_PARENT_CELL;
if ([self.dataSourceDelegate respondsToSelector:@selector(heightForParentCell)]) {
heightForParentCell = [self.dataSourceDelegate heightForParentCell];
}
return heightForParentCell;
}

- (CGFloat)heightForChildCell {
CGFloat heightForChildCell = HEIGHT_FOR_CHILD_CELL;
if ([self.dataSourceDelegate respondsToSelector:@selector(heightForChildCell)]) {
heightForChildCell = [self.dataSourceDelegate heightForChildCell];
}
return heightForChildCell;
}

- (NSInteger) numberOfChildrenUnderParentIndex:(NSInteger)parentIndex {
return [self.dataSourceDelegate numberOfChildCellsUnderParentIndex:parentIndex];
}
Expand Down
11 changes: 11 additions & 0 deletions ExpandTableView/JKMultiSelectSubTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,18 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
}

[self.delegate didSelectRowAtChildIndex:indexPath.row selected:isSwitchedOn underParentIndex:self.parentIndex];

[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (JKSubTableViewCellCell *)customChildCell:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex {
JKSubTableViewCellCell *cell;
if ([self.delegate tableView:tableView multiSelectCellForRowAtIndexPath:indexPath withInParentCellIndex:parentIndex] != nil) {
cell = [self.delegate tableView:tableView multiSelectCellForRowAtIndexPath:indexPath withInParentCellIndex:parentIndex];
} else {
cell = [super customChildCell:tableView indexPath:indexPath withInParentCellIndex:parentIndex];
}
return cell;
}

@end
1 change: 1 addition & 0 deletions ExpandTableView/JKParentTableViewCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@
- (void)setCellForegroundColor:(UIColor *) foregroundColor;
- (void)setCellBackgroundColor:(UIColor *) backgroundColor;

- (UIImageView *)pIndicator;
@end
13 changes: 11 additions & 2 deletions ExpandTableView/JKParentTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -80,17 +80,21 @@ - (void)setupDisplay {
checkMarkHeight);
}

- (UIImageView *)icon {
return [self pIndicator] != nil ? [self pIndicator] : iconImage;
}

- (void)rotateIconToExpanded {
[UIView beginAnimations:@"rotateDisclosure" context:nil];
[UIView setAnimationDuration:0.2];
iconImage.transform = CGAffineTransformMakeRotation(M_PI * 2.5);
[self icon].transform = CGAffineTransformMakeRotation(M_PI * 2.5);
[UIView commitAnimations];
}

- (void)rotateIconToCollapsed {
[UIView beginAnimations:@"rotateDisclosure" context:nil];
[UIView setAnimationDuration:0.2];
iconImage.transform = CGAffineTransformMakeRotation(M_PI * 2);
[self icon].transform = CGAffineTransformMakeRotation(M_PI * 2);
[UIView commitAnimations];
}

Expand All @@ -107,6 +111,11 @@ - (void)selectionIndicatorState:(BOOL) visible {
}
}

// subclasses can implement
- (UIImageView *)pIndicator {
return nil;
}

- (void)setCellForegroundColor:(UIColor *) foregroundColor {
self.label.textColor = foregroundColor;
}
Expand Down
12 changes: 12 additions & 0 deletions ExpandTableView/JKSingleSelectSubTableViewCell.m
Original file line number Diff line number Diff line change
Expand Up @@ -42,6 +42,18 @@ - (void)tableView:(UITableView *)tableView didSelectRowAtIndexPath:(NSIndexPath
}

[self.delegate didSelectRowAtChildIndex:indexPath.row selected:isSwitchedOn underParentIndex:self.parentIndex];

[tableView deselectRowAtIndexPath:indexPath animated:YES];
}

- (JKSubTableViewCellCell *)customChildCell:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex {
JKSubTableViewCellCell *cell;
if ([self.delegate tableView:tableView singleSelectCellForRowAtIndexPath:indexPath withInParentCellIndex:parentIndex] != nil) {
cell = [self.delegate tableView:tableView singleSelectCellForRowAtIndexPath:indexPath withInParentCellIndex:parentIndex];
} else {
cell = [super customChildCell:tableView indexPath:indexPath withInParentCellIndex:parentIndex];
}
return cell;
}

@end
19 changes: 18 additions & 1 deletion ExpandTableView/JKSubTableViewCell.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

#import <UIKit/UIKit.h>

@class JKSubTableViewCellCell;

@protocol JKSubTableViewCellDelegate <NSObject>
// return total number of children under this parentIndex
- (NSInteger) numberOfChildrenUnderParentIndex:(NSInteger)parentIndex;
Expand All @@ -24,9 +26,20 @@
- (NSString *) labelForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex;
// get the icon image
- (UIImage *) iconForChildIndex:(NSInteger)childIndex underParentIndex:(NSInteger)parentIndex;

@optional
/*! Optional method to override and provide your custom cell for multi selection mode.

*/
- (JKSubTableViewCellCell *)tableView:(UITableView *)tableView multiSelectCellForRowAtIndexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex;
/*! Optional method to override and provide your custom cell for single selection mode.

*/
- (JKSubTableViewCellCell *)tableView:(UITableView *)tableView singleSelectCellForRowAtIndexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger) parentIndex;

@end

@interface JKSubTableViewCell : UITableViewCell <UITableViewDataSource,UITableViewDelegate> {
@interface JKSubTableViewCell : UITableViewCell <UITableViewDataSource, UITableViewDelegate> {
UITableView *insideTableView;
__weak id delegate;
UIColor *bgColor;
Expand All @@ -38,12 +51,16 @@
@property(nonatomic,strong) UITableView *insideTableView;
@property(nonatomic,weak,getter = getDelegate, setter = setDelegate:) id<JKSubTableViewCellDelegate> delegate;
@property(nonatomic) NSInteger parentIndex;
@property(nonatomic, assign) CGFloat childCellHeight;
@property(nonatomic,strong) UIImage *selectionIndicatorImg;


@property(nonatomic,strong,getter = getSubTableForegroundColor, setter = setSubTableForegroundColor:) UIColor *fgColor;
@property(nonatomic,strong,getter = getSubTableBackgroundColor, setter = setSubTableBackgroundColor:) UIColor *bgColor;
@property(nonatomic,strong,getter = getSubTableFont, setter = setSubTableFont:) UIFont *font;

- (void)customInit;
- (JKSubTableViewCellCell *)customChildCell:(UITableView *)tableView indexPath:(NSIndexPath *)indexPath withInParentCellIndex:(NSInteger)parentIndex;
- (UIImage *) selectionIndicatorImgOrDefault;
- (void) reload;

Expand Down
Loading