سؤال

I have a UITableView that has two sections. Each section's datasource is a single array that uses a predicate to determine its contents. I've done this because there are other objects in the array that I don't want to display in the table but need to be able to save back out to Core Data once the user has finished playing with the table (it's interactive).

One of the interactions is tapping a switch on the cell that sets a property on the object populating that row. That particular property determines which section the object is displayed in. Here's how I do it right now:

EDIT: Added viewWillLayoutSubviews code to show how predicates are generated.

- (void)viewWillLayoutSubviews {
    // read and sort initial activities
    _activitiesSet = [_theEvent mutableSetValueForKey:@"activities"];
    _activitiesArray = [[_activitiesSet allObjects] mutableCopy];
    _predIncomplete = [NSPredicate predicateWithFormat:@"(isHidden == NO) AND (isComplete == NO)"];
    _predComplete = [NSPredicate predicateWithFormat:@"(isHidden == NO) AND (isComplete == YES)"];
}

- (IBAction)completeSwitchTapped:(id)sender {
    UIView *currentSuperview = [sender superview];
    while (![currentSuperview isKindOfClass:[UITableViewCell class]] && [currentSuperview superview] != nil) {
         currentSuperview = [currentSuperview superview];
    }
    NSIndexPath *indexPath = [self.itineraryTableView indexPathForCell:(UITableViewCell *)currentSuperview];
    switch (indexPath.section) {
        case kIncompleteActivitiesSection:
            [[[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] objectAtIndex:indexPath.row] setValue:@YES forKey:@"isComplete"];
            break;
        case kCompleteActivitiesSection:
            [[[_activitiesArray filteredArrayUsingPredicate:_predComplete] objectAtIndex:indexPath.row] setValue:@NO forKey:@"isComplete"];
            break;
        default:
            break;
    }
    [self.itineraryTableView reloadData];
}

This works just fine, but there's no animation. When I tap the switch on a row, it disappears from its section and appears in the other (due to the reloadData). This is really not very elegant.

How can I animate the row leaving the one section and sliding into the other?

I can't seem to wrap my brain around how I should formulate the deleteRowsAtIndexPaths and addRowsAtIndexPaths methods and still maintain the single, predicate filtered array in the background.

Thanks so much!!

هل كانت مفيدة؟

المحلول 2

I've been able to figure this out, mostly. Here's what I've come up with:

- (IBAction)completeSwitchTapped:(id)sender {
    UIView *currentSuperview = [sender superview];
    while (![currentSuperview isKindOfClass:[UITableViewCell class]] && [currentSuperview superview] != nil) {
        currentSuperview = [currentSuperview superview];
    }
    NSIndexPath *indexPath = [self.itineraryTableView indexPathForCell:(UITableViewCell *)currentSuperview];
    NSIndexPath *newIndexPath = [[NSIndexPath alloc] init];
    switch (indexPath.section) {
        case kIncompleteActivitiesSection: {
            Activity *theActivity = [[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] objectAtIndex:indexPath.row];
            [[[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] objectAtIndex:indexPath.row] setValue:@YES forKey:@"isComplete"];
            unsigned long newIndex = [[_activitiesArray filteredArrayUsingPredicate:_predComplete] indexOfObject:theActivity];
            newIndexPath = [NSIndexPath indexPathForRow:newIndex inSection:kCompleteActivitiesSection];
            [self.itineraryTableView beginUpdates];
            [self.itineraryTableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
            [self.itineraryTableView endUpdates];
            break;
        }
        case kCompleteActivitiesSection: {
            Activity *theActivity = [[_activitiesArray filteredArrayUsingPredicate:_predComplete] objectAtIndex:indexPath.row];
            [[[_activitiesArray filteredArrayUsingPredicate:_predComplete] objectAtIndex:indexPath.row] setValue:@NO forKey:@"isComplete"];
            unsigned long newIndex = [[_activitiesArray filteredArrayUsingPredicate:_predIncomplete] indexOfObject:theActivity];
            newIndexPath = [NSIndexPath indexPathForRow:newIndex inSection:kIncompleteActivitiesSection];
            [self.itineraryTableView beginUpdates];
            [self.itineraryTableView moveRowAtIndexPath:indexPath toIndexPath:newIndexPath];
            [self.itineraryTableView endUpdates];
            break;
        }
        default: {
            break;
        }
    }
    [[NSRunLoop currentRunLoop] runUntilDate:[NSDate dateWithTimeIntervalSinceNow:0.3]];
    [self.itineraryTableView reloadData];
}

I'm not sure if the run loop delay is a good choice, but it's the right timing and it looks great.

نصائح أخرى

Instead of sending reloadData to the table view, send it a moveRowAtIndexPath:toIndexPath: message.

مرخصة بموجب: CC-BY-SA مع الإسناد
لا تنتمي إلى StackOverflow
scroll top