reloadItemsAtIndexPaths 후 UICollectionView 애니메이션 방지


91

UICollectionView는 reloadItemsAtIndexPaths가 호출 된 후 항목을 애니메이션합니다 (애니메이션 페이드).

이 애니메이션을 피할 수있는 방법이 있습니까?

iOS 6

답변:


231

iOS 7 이상을 타겟팅하는 경우 새로운 UIView방법을 사용할 수 있습니다 performWithoutAnimation:. 나는 후드 아래에서 이것이 여기에있는 다른 답변과 거의 같은 일을하고 있다고 생각합니다 (일시적으로 비활성화UIView 애니메이션 / 핵심 애니메이션 작업 )과 거의 동일하지만 구문은 훌륭하고 깨끗합니다.

특히이 질문에 대해서는 ...

목표 -C :

[UIView performWithoutAnimation:^{
    [self.collectionView reloadItemsAtIndexPaths:indexPaths];
}];


빠른:

UIView.performWithoutAnimation {
    self.collectionView.reloadItemsAtIndexPaths(indexPaths)
}


물론이 원칙은 변경 사항이 애니메이션 되지 않도록하려는 모든 상황에 적용될 수 있습니다 .


3
이것은 iOS 7 이상에서 저에게 허용되는 답변보다 더 잘 작동했습니다.
Philippe Sabourin 2014

그것은 모든뿐만 아니라 컬렉션을보기 위해 애니메이션 비활성화
user2159978을

10
@ user2159978 맞습니다. 여기의 모든 답변은 일시적으로 UIView 애니메이션을 비활성화합니다. 애니메이션은 전달 된 블록 내에서 시작된 작업에 대해서만 비활성화됩니다.이 경우에는 컬렉션 뷰의 다시로드 만 가능합니다. 질문에 대한 완벽하게 유효한 답변이므로 반대표를받을 가치가 없다고 생각합니다.
Stuart

놀라운 솔루션. 이 대신에 animateWithDuration의 사용 : 0 방지 빠른하지만 눈에 보이는 레이아웃 결함을 전혀 itemSize으로 자체 크기 콜렉션 뷰 세포를 사용하는 경우
에단 길

1
이 솔루션은 iOS 14에서 더 이상 작동하지 않습니다.이 블록 내에서 reloadData를 사용하지만 iOS 13에서는 작동했습니다
Maray97

161

다음을 시도해 볼 수도 있습니다.

UICollectionView *collectionView;

...

[UIView setAnimationsEnabled:NO];

[collectionView performBatchUpdates:^{
    [collectionView reloadItemsAtIndexPaths:indexPaths];
} completion:^(BOOL finished) {
    [UIView setAnimationsEnabled:YES];
}];

편집하다:

또한 performBatchUpdatesUIView 애니메이션 블록으로 래핑 하면 기본 애니메이션 대신 UIView 애니메이션이 사용되므로 다음과 같이 애니메이션 기간을 0으로 설정할 수 있습니다.

[UIView animateWithDuration:0 animations:^{
    [collectionView performBatchUpdates:^{
        [collectionView reloadItemsAtIndexPaths:indexPaths];
    } completion:nil];
}];

삽입 및 삭제 중에 iOS 7 탄력있는 애니메이션을 사용하려는 경우 더욱 멋집니다!


1
감사합니다. 이것은 uicollectionview 셀에 스톱워치 타이머를 추가하는 데 매우 유용했습니다.
hatunike 2013

훌륭한! 나는 이것을 insertCells와 함께 사용하고 키보드를 위로 올려 셀이 삽입 된 후 collectionView를 새로운 오프셋으로 애니메이션화했습니다.
David H

5
Peter가 말했듯이 이것은 다른 애니메이션을 방해합니다. 대신 완료 블록 외부에서 [UIView setAnimationsEnabled : YES]를 호출해야합니다. 그렇게하면 해당 애니메이션 1 개만 방지 할 수 있습니다.
Adlai Holler 2014 년

2
똑같은 일을하는 대체 방법을 추가했습니다.
Sam

1
performBatchUpdates내부 포장 animateWithDuration은 훌륭합니다! 팁 고마워!
Robert

19

UICollectionView는 reloadItemsAtIndexPaths가 호출 된 후 항목을 애니메이션합니다 (애니메이션 페이드).

이 애니메이션을 피할 수있는 방법이 있습니까?

iOS 6

FlowLayout을 사용하고 있다고 가정합니다. 페이드 애니메이션을 제거하려고하므로 다음을 시도하십시오.

import UIKit

class NoFadeFlowLayout: UICollectionViewFlowLayout {

    override func initialLayoutAttributesForAppearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attrs = super.initialLayoutAttributesForAppearingItem(at: itemIndexPath)
        attrs?.alpha = 1.0
        return attrs
    }

    override func finalLayoutAttributesForDisappearingItem(at itemIndexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        let attrs = super.finalLayoutAttributesForDisappearingItem(at: itemIndexPath)
        attrs?.alpha = 1.0
        return attrs
    }

}

이것은 매우 오래된 질문이므로 더 이상 iOS 6을 타겟팅하지 않을 것입니다. 나는 개인적으로 tvOS 11에서 작업하고 있었고 같은 질문이 있었기 때문에 이것은 같은 문제와 함께 오는 모든 사람들을 위해 여기에 있습니다.


1
이 답변에 대해 "와우 이거 정말 잘 작동합니다!"라는 효과에 대해 3 ~ 4 개의 댓글이있었습니다. 누군가 댓글을 삭제하기로 결정했습니다. 사실, 이것은 이것을 달성하는 현대적이고 해킹이 아닌 방법이라고 생각합니다. 그리고 그 의견은 이것을 인정한 것입니다.
Matt Mc

8

내가 쓴 UICollectionView에 범주를 그냥 할 수 있습니다. 트릭은 다시로드하는 동안 모든 애니메이션을 비활성화하는 것입니다.

if (!animated) {
    [CATransaction begin];
    [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
}

[self reloadItemsAtIndexPaths:indexPaths];

if (!animated) {
    [CATransaction commit];
}

나는 또한 이것이 버그라면 어떤 애니메이션도하지 말아야한다는 Apple의 응답을 받는다. 내가 뭘 잘못하고 있는지 버그인지 모르겠다.
Marcin 2013 년

2
CATransaction.setDisableActions(true)이것에 대한 속기처럼 할 수도 있습니다 .
CIFilter

5
extension UICollectionView {
    func reloadWithoutAnimation(){
        CATransaction.begin()
        CATransaction.setValue(kCFBooleanTrue, forKey: kCATransactionDisableActions)
        self.reloadData()
        CATransaction.commit()
    }
}

이 빠른 3 구문입니다
암 자드 Tubasi

이것은 UIView.performWithoutAnimation보다 더 잘 작동했습니다.
Lance Samaria

5

다음은 performBatchUpdates애니메이션이없는 Swift 3 버전 UICollectionView입니다. collectionView.reloadData()레코드를 삽입 할 때 셀 스와핑을 줄 였기 때문에 이것이 나에게 더 잘 작동한다는 것을 알았습니다 .

func appendCollectionView(numberOfItems count: Int){

        // calculate indexes for the items to be added
        let firstIndex = dataItems.count - count
        let lastIndex = dataItems.count - 1

        var indexPaths = [IndexPath]()
        for index in firstIndex...lastIndex {
            let indexPath = IndexPath(item: index, section: 0)
            indexPaths.append(indexPath)
        }

   UIView.performWithoutAnimation {

        self.collectionView.performBatchUpdates({ () -> Void in
            self.collectionView.insertItems(at: indexPaths)
        }, completion: { (finished) -> Void in

        })
    }
}

2
- (void)reloadCollectionViewAnimated:(BOOL)animated  {

    if (animated) {
        [self.collectionView performBatchUpdates:^{
            [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
        } completion:^(BOOL finished) {

        }];
    } else {
        [CATransaction begin];
        [CATransaction setValue:(id)kCFBooleanTrue forKey:kCATransactionDisableActions];
        [self.collectionView reloadSections:[NSIndexSet indexSetWithIndex:0]];
        [CATransaction commit];
    }

}

1

$ 0.02를 추가하기 위해 선택한 답변의 두 버전을 모두 시도했으며 원래 방법이 내 목적에 더 적합했습니다. 사용자가 주어진 주에 달력을 입력 한 다음 앞뒤로 스 와이프하고 목록을 필터링 할 개별 날짜를 선택할 수있는 무한 스크롤 달력보기를 작업 중입니다.

내 구현에서 오래된 장치에서 성능을 유지하려면 달력보기를 나타내는 날짜 배열을 상대적으로 작게 유지해야합니다. 즉, 사용자는 3 주 중간에 약 5 주 분량의 날짜를 유지해야합니다. 두 번째 접근 방식을 사용할 때의 문제는 애니메이션없이 컬렉션 뷰를 다시 가운데로 스크롤해야하는 두 번째 단계가 있으며, 이로 인해 차단 된 기본 애니메이션으로 인해 어떤 이유로 매우 들쭉날쭉 한 모양이됩니다.

내 코드 :

[UIView setAnimationsEnabled:NO];
[self.collectionView performBatchUpdates:^{
    [self.collectionView deleteItemsAtIndexPaths:indexPathDeleteArray];
    [self.collectionView insertItemsAtIndexPaths:indexPathAddArray];

} completion:NULL];
[UIView setAnimationsEnabled:YES];

NSIndexPath *newIndexPath = [NSIndexPath indexPathForItem:14 inSection:0];
[self.collectionView scrollToItemAtIndexPath:newIndexPath atScrollPosition:UICollectionViewScrollPositionLeft animated:NO];

0
 func reloadRowsWithoutAnimation(at indexPaths: [IndexPath]) {
        let contentOffset = collectionView.contentOffset
        UIView.setAnimationsEnabled(false)
        collectionView.performBatchUpdates {
            collectionView.reloadItems(at: indexPaths)
        }
        UIView.setAnimationsEnabled(true)
        collectionView.setContentOffset(contentOffset, animated: false)
    }
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.