Тривалість анімації рядків UITableView та зворотний виклик завершення


98

Чи є спосіб визначити тривалість анімації рядків UITableView або отримати зворотний виклик після завершення анімації?

Що я хотів би зробити - це спалах індикаторів прокрутки після завершення анімації. Виконання спалаху до цього часу нічого не робить. Поки що у мене є рішення затримати півсекунди (це здається тривалістю анімації за замовчуванням), тобто:

[self.tableView insertRowsAtIndexPaths:newRows
                      withRowAnimation:UITableViewRowAnimationFade];
[self.tableView performSelector:@selector(flashScrollIndicators)
                     withObject:nil
                     afterDelay:0.5];

Я ще не пробував себе, але, можливо, це міг би зробити, з деяким обробкою контуру:- (void)tableView:(UITableView *)tableView didEndDisplayingCell:(UITableViewCell *)cell forRowAtIndexPath:(NSIndexPath*)indexPath
Kalle

Відповіді:


3

Сьогодні, якщо ви хочете це зробити, є нова функція, починаючи з iOS 11 :

- (void)performBatchUpdates:(void (^)(void))updates 
                 completion:(void (^)(BOOL finished))completion;

У закритих оновленнях ви розміщуєте той самий код, що і в розділі startUpdates () / endUpdates. І завершення виконується після всіх анімацій.


Це чудово. Я не помітив цього доповнення.
Даніель Дікісон

207

Щойно натрапив на це. Ось як це зробити:

Ціль-С

[CATransaction begin];
[tableView beginUpdates];
[CATransaction setCompletionBlock: ^{
    // Code to be executed upon completion
}];
[tableView insertRowsAtIndexPaths: indexPaths
                 withRowAnimation: UITableViewRowAnimationAutomatic];
[tableView endUpdates];
[CATransaction commit];

Швидкий

CATransaction.begin()
tableView.beginUpdates()
CATransaction.setCompletionBlock {
    // Code to be executed upon completion
}
tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
tableView.endUpdates()
CATransaction.commit()

2
Знову ж таки тут працює бездоганно. iOS6 і все. Це належний підтримуваний SDK механізм переосмислення властивостей в анімації за замовчуванням. Можливо, у вас є додаткові, триваліші анімації всередині вашої CATransaction? Вони гніздяться, знаєте.
karwag

1
Для мене чудово працює в iOS6. Дякую за це!
Арон

5
setAnimationDurationне впливає на тривалість вставки / видалення. iOS 6
Том Редман

2
будь-які пропозиції щодо зміни тривалості? CATransaction setAnimationDuration: схоже, не має значення.
Джефф Грімс

5
Мені добре підходить і в iOS 5.1.1, 6.1, 7.0; Але, якщо вам потрібно отримати новий tableView.contentSize після анімації (як це було в моєму випадку), ви повинні використовувати [self performSelectorOnMainThread: withObject: waitUntilDone:]; у setCompletionBlock, щоб викликати свого делегата в наступному циклі запуску. якщо ви зателефонуєте своєму делегату безпосередньо, без виконанняSelectorOnMainThread, ви отримаєте старе значення для tableView.contentSize.
хитрощі

38

Розгортаючи тонку відповідь karwag , зауважте, що в iOS 7, оточуючий CATransaction з UIView Animation, можна контролювати тривалість анімації таблиці.

[UIView beginAnimations:@"myAnimationId" context:nil];

[UIView setAnimationDuration:10.0]; // Set duration here

[CATransaction begin];
[CATransaction setCompletionBlock:^{
    NSLog(@"Complete!");
}];

[myTable beginUpdates];
// my table changes
[myTable endUpdates];

[CATransaction commit];
[UIView commitAnimations];

Тривалість анімації UIView не впливає на iOS 6. Можливо, анімації таблиці iOS 7 реалізовані по-різному, на рівні UIView.


Здається, тривалість анімації ігнорується.
Дастін

26

Оце одне пекло корисного трюку! Я написав розширення UITableView, щоб весь час писати речі CATransaction.

import UIKit

extension UITableView {

    /// Perform a series of method calls that insert, delete, or select rows and sections of the table view.
    /// This is equivalent to a beginUpdates() / endUpdates() sequence, 
    /// with a completion closure when the animation is finished.
    /// Parameter update: the update operation to perform on the tableView.
    /// Parameter completion: the completion closure to be executed when the animation is completed.

    func performUpdate(_ update: ()->Void, completion: (()->Void)?) {

        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)

        // Table View update on row / section
        beginUpdates()
        update()
        endUpdates()

        CATransaction.commit()
    }

}

Це використовується так:

// Insert in the tableView the section we just added in sections
self.tableView.performUpdate({
            self.tableView.insertSections([newSectionIndex], with: UITableViewRowAnimation.top)

        }, completion: {
            // Scroll to next section
            let nextSectionIndexPath = IndexPath(row: 0, section: newSectionIndex)
            self.tableView.scrollToRow(at: nextSectionIndexPath, at: .top, animated: true)
        })

Дивовижна відповідь! це одна з причин, що я люблю Свіфта
Джанні Карло

@GianniCarlo ви можете це зробити і в ObjC
CyberMew

@CyberMew так, але створення Категорії завжди було таким болем, особливо через довгі назви зайвих файлів
Джанні Карло

він доступний лише в ios 11, як його використовувати в ios 10?
kemdo

@kemdo Чому, на вашу думку, він доступний лише в iOS 11? Тут все на iOS 2+, окрім setCompletionBlockяких iOS 4+
Frédéric Adda

25

Скорочення тонкої відповіді Брента , принаймні для iOS 7 ви можете все це загортати в [UIView animateWithDuration: delay: options: animations: завершення:] call:

[UIView animateWithDuration:10 delay:0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
  [self.tableView beginUpdates];
  [self.tableView endUpdates];
} completion:^(BOOL finished) {
  // completion code
}];

однак, я не можу перекрити криву анімації за замовчуванням з іншого, крім EaseInOut.


2
Роблячи вставку рядка таким чином, або спосіб @ Brent, хоча тривалість дотримується, UITableViewRowAnimation, здається, не дотримується, і завжди видається анімацією зверху вниз, навіть коли я вказую, наприклад UITableViewRowAnimationLeft. Тестування на iOS 8.4 - хтось має рішення?
Денні

23

Ось швидка версія відповіді karwag

    CATransaction.begin()
    tableView.beginUpdates()
    CATransaction.setCompletionBlock { () -> Void in
        // your code here
    }
    tableView.insertRowsAtIndexPaths(indexArray, withRowAnimation: .Top)
    tableView.endUpdates()
    CATransaction.commit()

6

Для мене мені це було потрібно для collectionView. Я зробив просте розширення, щоб вирішити це:

extension UICollectionView {

    func reloadSections(sections: NSIndexSet, completion: () -> Void){
        CATransaction.begin()
        CATransaction.setCompletionBlock(completion)

        self.reloadSections(sections)

        CATransaction.commit()
    }

}

1

Оскільки performBatchметод tableView доступний, починаючи лише з iOS 11 , ви можете використовувати таке розширення:

extension UITableView {
func performUpdates(_ updates: @escaping () -> Void, completion: @escaping (Bool) -> Void) {
        if #available(iOS 11.0, *) {
            self.performBatchUpdates({
                updates()
            }, completion: completion)
        } else {
            CATransaction.begin()
            beginUpdates()
            CATransaction.setCompletionBlock {
                completion(true)
            }
            updates()
            endUpdates()
            CATransaction.commit()
        }
    }
}

-8

Ви можете спробувати обернути insertRowsAtIndexPath в a

- (void)beginUpdates
- (void)endUpdates

транзакції, після чого виконайте спалах.


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