Як виявити, що анімація закінчилася на UITableView beginUpdates / endUpdates?


116

Я вставляю / видаляю комірку таблиці, використовуючи insertRowsAtIndexPaths/deleteRowsAtIndexPathsзагорнуту beginUpdates/endUpdates. Я також використовую beginUpdates/endUpdatesдля регулювання rowHeight. Усі ці операції анімовані за замовчуванням.

Як я можу виявити, що анімація закінчилася під час використання beginUpdates/endUpdates?


1
FYI: Це стосується -scrollToRowAtIndexPath:atScrollPosition:animated:і.
Бен Лачман

Відповіді:


292

Як що до цього?

[CATransaction begin];

[CATransaction setCompletionBlock:^{
    // animation has finished
}];

[tableView beginUpdates];
// do some work
[tableView endUpdates];

[CATransaction commit];

Це працює, тому що анімації tableView використовують CALayerанімацію всередині. Тобто вони додають анімацію до будь-якого відкритого CATransaction. Якщо відкритого не CATransactionіснує (звичайний випадок), то імпліцитно починається одне, яке закінчується в кінці поточного запуску. Але якщо ви почнете його самостійно, як це робиться тут, тоді він буде використовувати це.


7
Не працювало для мене. Блок завершення викликається під час роботи анімації.
mrvincenzo

2
@MrVincenzo Ви встановили completionBlockраніше beginUpdatesі endUpdatesяк у фрагменті?
Рудольф Адамкович

2
[CATransaction commit]слід викликати не раніше [tableView endUpdates].
Рудольф Адамкович

6
Блок завершення ніколи не викликається, якщо комірка містить представлення з анімаціями, тобто UIActivityIndicatorView.
markturnip

3
Зрештою цього часу я цього ніколи не знав. Чисте золото !! Нічого гіршого, ніж побачити приємну анімацію, вбиту необхідним злом tableView.reloadData ().
DogCoffee

31

Швидка версія


CATransaction.begin()

CATransaction.setCompletionBlock({
    do.something()
})

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()

6

Якщо ви орієнтовані на iOS 11 і новіші версії, вам слід використовувати UITableView.performBatchUpdates(_:completion:):

tableView.performBatchUpdates({
    // delete some cells
    // insert some cells
}, completion: { finished in
    // animation complete
})

5

Можливим рішенням може бути успадкування від UITableView, на якому ви телефонуєте, endUpdatesі перезапис його setContentSizeMethod, оскільки UITableView регулює розмір вмісту відповідно до доданих або видалених рядків. Цей підхід також повинен працювати reloadData.

Щоб сповіщення надсилалося лише після endUpdatesвиклику, його можна було також перезаписати endUpdatesта встановити прапор.

// somewhere in header
@private BOOL endUpdatesWasCalled_;

-------------------

// in implementation file

- (void)endUpdates {
    [super endUpdates];
    endUpdatesWasCalled_ = YES;
}

- (void)setContentSize:(CGSize)contentSize {
    [super setContentSize:contentSize];

    if (endUpdatesWasCalled_) {
        [self notifyEndUpdatesFinished];
        endUpdatesWasCalled_ = NO;
    }
}

5

Ви можете долучити свої операції до блоку анімації UIView таким чином:

- (void)tableView:(UITableView *)tableView performOperation:(void(^)())operation completion:(void(^)(BOOL finished))completion
{
    [UIView animateWithDuration:0.0 animations:^{

        [tableView beginUpdates];
        if (operation)
            operation();
        [tableView endUpdates];

    } completion:^(BOOL finished) {

        if (completion)
            completion(finished);
    }];
}

Кредити на https://stackoverflow.com/a/12905114/634940 .


4
Цей код для мене не працював. Блок завершення був викликаний після endUpdates, але до того , як анімація завершилася.
Тім Камбер

1
Це не працює. При застосуванні цього зразка анімація перегляду таблиці перестала працювати.
Primoz990

Спробуйте збільшити тривалість (наприклад, 0,3 сек) - це повинно працювати (працювало на мене)
emem

1

Ще не знайшли хорошого рішення (окрім підкласи UITableView). Я вирішив використовувати performSelector:withObject:afterDelay:зараз. Не ідеально, але роботу виконує.

ОНОВЛЕННЯ : Схоже, я можу використовувати scrollViewDidEndScrollingAnimation:для цієї мети (це специфічно для моєї реалізації, див. Коментар).


1
scrollViewDidEndScrollingAnimationназивається лише у відповідь на setContentOffsetтаscrollRectToVisible
samvermette

@samvermette Ну, у моєму випадку, коли викликаються beginUpdates / endUpdates, UITableView завжди анімовує прокрутку. Але це характерно для моєї реалізації, тому я погоджуюся, що це не найкраща відповідь, але це працює на мене.
pixelfreak

Здається, можна включити оновлення до блоку анімації UIView. Дивіться мою відповідь нижче: stackoverflow.com/a/14305039/634940 .
Зденек

0

Ви можете використовувати tableView:willDisplayCell:forRowAtIndexPath::

- (void)tableView:(UITableView *)tableView willDisplayCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath *)indexPath {
    NSLog(@"tableView willDisplay Cell");
    cell.backgroundColor = [UIColor colorWithWhite:((indexPath.row % 2) ? 0.25 : 0) alpha:0.70];
}

Але це також буде викликано, коли комірка, яка вже знаходиться в таблиці, переміститься з екрана на екран, так що це може бути не саме те, що ви шукаєте. Я просто переглянув все UITableViewі UIScrollViewделегувати методи й там не з'являється , щоб бути чимось - небудь , щоб обробляти тільки після того, як клітина вставляється анімації.


Чому б просто не зателефонувати методу, який ви хочете викликати, коли анімація закінчується після endUpdates?

- (void)setDownloadedImage:(NSMutableDictionary *)d {
    NSIndexPath *indexPath = (NSIndexPath *)[d objectForKey:@"IndexPath"];
    [indexPathDelayed addObject:indexPath];
    if (!([table isDragging] || [table isDecelerating])) {
        [table beginUpdates];
        [table insertRowsAtIndexPaths:indexPathDelayed withRowAnimation:UITableViewRowAnimationFade];
        [table endUpdates];
        // --> Call Method Here <--
        loadingView.hidden = YES;
        [indexPathDelayed removeAllObjects];
    }
}

Спасибі, чоун. Не думаю willDisplayCell, що спрацює. Мені потрібно, щоб це сталося після анімації, тому що мені потрібно зробити візуальне оновлення лише після того, як все впорядкується.
pixelfreak

np @pixelfreak, якщо я думаю про будь-який інший спосіб зробити це, я дам вам знати.
човен
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.