diff --git a/HPReorderTableView/HPReorderTableView.h b/HPReorderTableView/HPReorderTableView.h index 01191d0..eb12596 100644 --- a/HPReorderTableView/HPReorderTableView.h +++ b/HPReorderTableView/HPReorderTableView.h @@ -21,7 +21,14 @@ @protocol HPReorderTableViewDelegate @optional +- (void)tableView:(UITableView *)tableView didCancelReorderingRowAtIndexPath:(NSIndexPath *)indexPath; - (void)tableView:(UITableView *)tableView didEndReorderingRowAtIndexPath:(NSIndexPath *)indexPath; +- (void)tableView:(UITableView *)tableView willBeginReorderingRowAtIndexPath:(NSIndexPath *)indexPath; +- (void)tableView:(UITableView *)tableView didBeginReorderingRowAtIndexPath:(NSIndexPath *)indexPath; +/** + * Can this row be allowed to be dragged. As opposed to canMoveRowAtIndexPath where determines is the row can move at all. + */ +- (BOOL)canDragRowAtIndexPath:(NSIndexPath *)indexPath; @end /** @@ -47,6 +54,11 @@ */ - (void)registerTemporaryEmptyCellClass:(Class)cellClass; +/** + Allow the caller to end any reorder that is in progress. + */ +- (void)endAnyExistingReorder; + @end /** diff --git a/HPReorderTableView/HPReorderTableView.m b/HPReorderTableView/HPReorderTableView.m index b7d3fc7..a6f44c5 100644 --- a/HPReorderTableView/HPReorderTableView.m +++ b/HPReorderTableView/HPReorderTableView.m @@ -90,6 +90,26 @@ - (void)registerTemporaryEmptyCellClass:(Class)cellClass [self registerClass:cellClass forCellReuseIdentifier:HPReorderTableViewCellReuseIdentifier]; } +- (void)endAnyExistingReorder +{ + if (_reorderCurrentIndexPath) { + // we repeat a bunch of code here that's in didEndLongPressGestureRecognizer, but we also make sure that + // but we don't call reloadRowsAtIndexPaths: on the tableview, since that might cause an out-of-bounds crash + if ([self.delegate respondsToSelector:@selector(tableView:didCancelReorderingRowAtIndexPath:)]) { + [self.delegate tableView:self didCancelReorderingRowAtIndexPath:_reorderCurrentIndexPath]; + } + [self animateShadowOpacityFromValue:_reorderDragView.layer.shadowOpacity toValue:0]; + { // Reset + [_scrollDisplayLink invalidate]; + _scrollDisplayLink = nil; + _scrollRate = 0; + _reorderCurrentIndexPath = nil; + _reorderInitialIndexPath = nil; + } + [self removeReorderDragView]; + } +} + #pragma mark - Actions - (void)recognizeLongPressGestureRecognizer:(UILongPressGestureRecognizer*)gestureRecognizer @@ -178,6 +198,13 @@ - (BOOL)canMoveRowAtIndexPath:(NSIndexPath*)indexPath return ![self.dataSource respondsToSelector:@selector(tableView:canMoveRowAtIndexPath:)] || [self.dataSource tableView:self canMoveRowAtIndexPath:indexPath]; } +- (BOOL)canDragRowAtIndexPath:(NSIndexPath *)indexPath { + if ([self.delegate respondsToSelector:@selector(canDragRowAtIndexPath:)]) { + return [self.delegate canDragRowAtIndexPath:indexPath]; + } + return YES; +} + - (BOOL)hasRows { NSInteger sectionCount = [self numberOfSections]; @@ -220,12 +247,15 @@ - (void)didBeginLongPressGestureRecognizer:(UILongPressGestureRecognizer*)gestur { const CGPoint location = [gestureRecognizer locationInView:self]; NSIndexPath *indexPath = [self indexPathForRowAtPoint:location]; - if (indexPath == nil || ![self canMoveRowAtIndexPath:indexPath]) + if (indexPath == nil || ![self canMoveRowAtIndexPath:indexPath] || ![self canDragRowAtIndexPath:indexPath]) { HPGestureRecognizerCancel(gestureRecognizer); return; } + if ([self.delegate respondsToSelector:@selector(tableView:willBeginReorderingRowAtIndexPath:)]) { + [self.delegate tableView:self willBeginReorderingRowAtIndexPath:indexPath]; + } UITableViewCell *cell = [self cellForRowAtIndexPath:indexPath]; [cell setSelected:NO animated:NO]; [cell setHighlighted:NO animated:NO]; @@ -247,6 +277,10 @@ - (void)didBeginLongPressGestureRecognizer:(UILongPressGestureRecognizer*)gestur [self animateShadowOpacityFromValue:0 toValue:_reorderDragView.layer.shadowOpacity]; [UIView animateWithDuration:HPReorderTableViewAnimationDuration animations:^{ _reorderDragView.center = CGPointMake(self.center.x, location.y); + } completion:^(BOOL finished) { + if ([self.delegate respondsToSelector:@selector(tableView:didBeginReorderingRowAtIndexPath:)]) { + [self.delegate tableView:self didBeginReorderingRowAtIndexPath:indexPath]; + } }]; [self reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; @@ -295,14 +329,16 @@ - (void)removeReorderDragView - (void)reorderCurrentRowToIndexPath:(NSIndexPath*)toIndexPath { - [self beginUpdates]; - [self moveRowAtIndexPath:toIndexPath toIndexPath:_reorderCurrentIndexPath]; // Order is important to keep the empty cell behind - if ([self.dataSource respondsToSelector:@selector(tableView:moveRowAtIndexPath:toIndexPath:)]) - { - [self.dataSource tableView:self moveRowAtIndexPath:_reorderCurrentIndexPath toIndexPath:toIndexPath]; + if ([self canMoveRowAtIndexPath:toIndexPath]) { + [self beginUpdates]; + [self moveRowAtIndexPath:toIndexPath toIndexPath:_reorderCurrentIndexPath]; // Order is important to keep the empty cell behind + if ([self.dataSource respondsToSelector:@selector(tableView:moveRowAtIndexPath:toIndexPath:)]) + { + [self.dataSource tableView:self moveRowAtIndexPath:_reorderCurrentIndexPath toIndexPath:toIndexPath]; + } + _reorderCurrentIndexPath = toIndexPath; + [self endUpdates]; } - _reorderCurrentIndexPath = toIndexPath; - [self endUpdates]; } #pragma mark Subclassing