UITableView 행 애니메이션 기간 및 완료 콜백


98

UITableView 행 애니메이션의 기간을 지정하거나 애니메이션이 완료 될 때 콜백을받는 방법이 있습니까?

내가하고 싶은 것은 애니메이션이 완료된 후 스크롤 표시기를 깜박이는 것입니다. 그 전에 플래시를 사용하면 아무 일도 일어나지 않습니다. 지금까지 내가 가진 해결 방법은 0.5 초 (기본 애니메이션 기간 인 것 같음)를 지연하는 것입니다. 즉,

[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;

업데이트 클로저에서는 beginUpdates () / endUpdates 섹션과 동일한 코드를 배치합니다. 그리고 모든 애니메이션 후에 완료가 실행됩니다.


이것은 훌륭합니다. 나는이 추가를 알아 차리지 못했다.
Daniel Dickison

207

방금 이것을 발견했습니다. 방법은 다음과 같습니다.

목표 -C

[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에서 잘 작동합니다. 감사합니다!
Aron

5
setAnimationDuration삽입 / 삭제 기간에 영향을 미치지 않는 것 같습니다. iOS 6
Tom Redman 2013

2
그래도 기간을 변경하는 방법에 대한 제안이 있습니까? CATransaction setAnimationDuration : 차이가없는 것 같습니다.
Jeff Grimes

5
iOS 5.1.1, 6.1, 7.0에서도 잘 작동합니다. 그러나 애니메이션 후에 새로운 tableView.contentSize를 가져와야한다면 (제 경우처럼) [self performSelectorOnMainThread : withObject : waitUntilDone :]을 사용해야합니다. 다음 runloop에서 대리인을 호출하기 위해 setCompletionBlock에서. performSelectorOnMainThread없이 직접 대리자를 호출하면 tableView.contentSize에 대한 이전 값을 얻습니다.
slamor

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 수준에서 다르게 구현됩니다.


애니메이션 기간이 무시 된 것으로 보입니다.
Dustin

26

그것은 하나의 유용한 속임수입니다! 항상 CATransaction 항목을 작성하지 않도록 UITableView 확장을 작성했습니다.

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에서만 사용할 수있는 이유는 무엇입니까? 모든 것은 여기를 제외하고 아이폰 OS 2+입니다 setCompletionBlock4+하는 아이폰 OS는
프레데릭 다다

25

Brent의 훌륭한 대답을 줄이면 최소한 iOS 7에서는 [UIView animateWithDuration : delay : options : animations : completion :] 호출에이 모든 것을 간결하게 래핑 할 수 있습니다.

[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에서 테스트-아무도 해결책이 있습니까?
Danny

23

다음은 karwag의 답변의 Swift 버전입니다.

    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

tableView의 performBatch메서드는 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를

- (void)beginUpdates
- (void)endUpdates

거래 후 플래시를 수행하십시오.


위의 karwag의 답변을 참조하십시오. "이후"로 간주되는 문제를 해결해야합니다.
JLundell 2012
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.