diff --git a/ATV.podspec b/ATV.podspec index a6220c3..ab62850 100644 --- a/ATV.podspec +++ b/ATV.podspec @@ -4,7 +4,7 @@ Pod::Spec.new do |s| s.summary = "A pluggable table view with a different data source for each section." s.homepage = "https://github.com/pnc/ATV" - s.license = 'MIT (example)' + s.license = 'MIT' s.author = { "Phil Calvin" => "pnc1138@gmail.com" } s.source = { :git => "https://github.com/pnc/ATV.git", :branch => "master" } diff --git a/ATV/ATVArrayTableSection.h b/ATV/ATVArrayTableSection.h index 17055ab..2597988 100644 --- a/ATV/ATVArrayTableSection.h +++ b/ATV/ATVArrayTableSection.h @@ -13,4 +13,10 @@ - (void)setObjects:(NSArray*)objects; - (void)setObjects:(NSArray*)objects animated:(BOOL)animated; +#pragma mark - Overrides + +- (UITableViewRowAnimation)animationForInsertingObject:(id)object atIndex:(NSUInteger)index; +- (UITableViewRowAnimation)animationForDeletingObject:(id)object atIndex:(NSUInteger)index; +- (id)uniqueIdentifierForObject:(id)object; + @end diff --git a/ATV/ATVArrayTableSection.m b/ATV/ATVArrayTableSection.m index 278cd4f..6b30879 100644 --- a/ATV/ATVArrayTableSection.m +++ b/ATV/ATVArrayTableSection.m @@ -44,9 +44,6 @@ - (void) setObjects:(NSArray*)objects { } - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { - UITableViewRowAnimation insertAnimation = animated ? UITableViewRowAnimationTop : UITableViewRowAnimationNone; - UITableViewRowAnimation deleteAnimation = animated ? UITableViewRowAnimationBottom : UITableViewRowAnimationNone; - if (!_objects) { _objects = objects; [self reloadSectionWithRowAnimation:UITableViewRowAnimationNone]; @@ -79,17 +76,19 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { // if it's not a new entry. for (int i = 0; i < oldObjects.count; i++) { id item = [oldObjects objectAtIndex:i]; - NSMutableArray *positions = [oldIndexes objectForKey:item]; + id identifier = [self uniqueIdentifierForObject:item]; + NSMutableArray *positions = [oldIndexes objectForKey:identifier]; if (!positions) { positions = [NSMutableArray array]; } [positions addObject:@(i)]; - [oldIndexes setObject:positions forKey:item]; + [oldIndexes setObject:positions forKey:identifier]; } for (int i = 0; i < objects.count; i++) { id item = [objects objectAtIndex:i]; - NSMutableArray *positions = [oldIndexes objectForKey:item]; + id identifier = [self uniqueIdentifierForObject:item]; + NSMutableArray *positions = [oldIndexes objectForKey:identifier]; NSNumber *oldIndex = nil; if (positions.count > 0) { // Without loss of generality, assume this duplicate was the first. This @@ -97,7 +96,7 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { oldIndex = [positions objectAtIndex:0]; [positions removeObjectAtIndex:0]; } else { - [oldIndexes removeObjectForKey:item]; + [oldIndexes removeObjectForKey:identifier]; } NSNumber *newIndex = @(i); @@ -127,23 +126,44 @@ - (void) setObjects:(NSArray*)objects animated:(BOOL)animated { } } } else { + UITableViewCell *cell = [self cellAtIndex:[oldIndex unsignedIntegerValue]]; + if (cell) { + // Cell is visible, repaint it + [self configureCell:cell atIndex:[newIndex unsignedIntegerValue]]; + } [self moveRowAtIndex:[oldIndex unsignedIntegerValue] toIndex:[newIndex unsignedIntegerValue]]; } } else { + UITableViewRowAnimation insertAnimation = animated ? + [self animationForInsertingObject:item atIndex:[newIndex unsignedIntegerValue]] : UITableViewRowAnimationNone; [self insertRowsAtIndices:[NSIndexSet indexSetWithIndex:[newIndex unsignedIntegerValue]] withRowAnimation:insertAnimation]; } } - NSMutableIndexSet *deleted = [NSMutableIndexSet new]; - for (id item in oldIndexes) { - NSArray *indexes = [oldIndexes objectForKey:item]; + for (id identifier in oldIndexes) { + NSArray *indexes = [oldIndexes objectForKey:identifier]; for (NSNumber *index in indexes) { - [deleted addIndex:[index unsignedIntegerValue]]; + id item = [oldObjects objectAtIndex:[index unsignedIntegerValue]]; + UITableViewRowAnimation deleteAnimation = animated ? + [self animationForDeletingObject:item atIndex:[index unsignedIntegerValue]] : UITableViewRowAnimationNone; + [self deleteRowsAtIndices:[NSIndexSet indexSetWithIndex:[index unsignedIntegerValue]] + withRowAnimation:deleteAnimation]; } } - [self deleteRowsAtIndices:deleted withRowAnimation:deleteAnimation]; [self endUpdates]; } +- (UITableViewRowAnimation)animationForInsertingObject:(id)object atIndex:(NSUInteger)index { + return UITableViewRowAnimationTop; +} + +- (UITableViewRowAnimation)animationForDeletingObject:(id)object atIndex:(NSUInteger)index { + return UITableViewRowAnimationBottom; +} + +- (id)uniqueIdentifierForObject:(id)object { + return object; +} + #pragma mark - Cell source - (UITableViewCell*) cellForRowAtIndex:(NSUInteger)index { diff --git a/ATV/ATVTableSection.h b/ATV/ATVTableSection.h index 29722a6..174a27f 100644 --- a/ATV/ATVTableSection.h +++ b/ATV/ATVTableSection.h @@ -80,4 +80,7 @@ toIndex:(NSUInteger)newIndex; - (void) reloadSectionWithRowAnimation:(UITableViewRowAnimation)animation; +- (void)setNeedsToPerformUpdates; +- (void)performUpdatesAnimated:(BOOL)animated; + @end diff --git a/ATV/ATVTableSection.m b/ATV/ATVTableSection.m index ef5c861..0a78957 100644 --- a/ATV/ATVTableSection.m +++ b/ATV/ATVTableSection.m @@ -1,6 +1,7 @@ #import "ATVTableSection.h" #import "ATVTableSection_Private.h" #import "ATVTableView.h" +#import "ATVTableView_Private.h" @implementation ATVTableSection @@ -202,4 +203,15 @@ - (void) deselectRowAtIndex:(NSUInteger)index animated:(BOOL)animated { [self._tableView deselectRowAtIndex:index inSection:self animated:animated]; } +#pragma mark - Deferred updates + +- (void)setNeedsToPerformUpdates { + self.needsToPerformUpdates = YES; + [self._tableView setWillPerformUpdates]; +} + +- (void)performUpdatesAnimated:(BOOL)animated { + self.needsToPerformUpdates = NO; +} + @end diff --git a/ATV/ATVTableSection_Private.h b/ATV/ATVTableSection_Private.h index 7e21290..ada7b8c 100644 --- a/ATV/ATVTableSection_Private.h +++ b/ATV/ATVTableSection_Private.h @@ -15,4 +15,5 @@ @interface ATVTableSection () @property (ATV_WEAK) ATVTableView* _tableView; @property (strong) NSMutableDictionary* registeredNibs; +@property BOOL needsToPerformUpdates; @end diff --git a/ATV/ATVTableView.h b/ATV/ATVTableView.h index c03f779..497a2fd 100644 --- a/ATV/ATVTableView.h +++ b/ATV/ATVTableView.h @@ -25,6 +25,10 @@ @property (nonatomic, strong) UIView* emptyView; @property (nonatomic) BOOL emptyViewHonorsContentInset; +#pragma mark - Deferred updates + +- (void)performUpdatesAnimated:(BOOL)animated; + #pragma mark - Private - (UITableViewCell*) cellForRowAtIndex:(NSUInteger)index inSection:(ATVTableSection*)section; diff --git a/ATV/ATVTableView.m b/ATV/ATVTableView.m index 96e69ee..08fa83e 100644 --- a/ATV/ATVTableView.m +++ b/ATV/ATVTableView.m @@ -124,6 +124,43 @@ - (void) removeAllSectionsWithRowAnimation:(UITableViewRowAnimation)animation { [self updateEmptyView]; } +#pragma mark - Deferred updates + +- (void)setWillPerformUpdates { + if (self.window) { + if (!self.willPerformUpdates) { + self.willPerformUpdates = YES; + [self performSelector:@selector(performUpdates) withObject:nil afterDelay:0.0]; + } + } +} + +- (void)didMoveToWindow { + [super didMoveToWindow]; + [self performUpdatesAnimated:NO]; +} + +- (void)performUpdates { + [self performUpdatesAnimated:YES]; +} + +- (void)performUpdatesAnimated:(BOOL)animated { + NSMutableArray *toUpdate = [NSMutableArray array]; + for (ATVTableSection *section in self.sections) { + if ([section needsToPerformUpdates]) { + [toUpdate addObject:section]; + } + } + if (toUpdate.count > 0) { + [self beginUpdates]; + for (ATVTableSection *section in toUpdate) { + [section performUpdatesAnimated:animated]; + NSAssert(![section needsToPerformUpdates], @"Section %@ still needs to perform updates after updating, did you forget to call [super performUpdates]?", self); + } + [self endUpdates]; + } + self.willPerformUpdates = NO; +} #pragma mark - Table view data source diff --git a/ATV/ATVTableView_Private.h b/ATV/ATVTableView_Private.h index f1d3d7f..eb6bebf 100644 --- a/ATV/ATVTableView_Private.h +++ b/ATV/ATVTableView_Private.h @@ -5,4 +5,7 @@ @property (strong) NSMutableArray* sections; @property UITableViewCellSeparatorStyle desiredSeparatorStyle; +@property BOOL willPerformUpdates; +- (void)setWillPerformUpdates; + @end