Tránh hoạt ảnh của UICollectionView sau khi tải lạiItemsAtIndexPaths


91

UICollectionXem hoạt ảnh các mục sau khi reloadItemsAtIndexPaths được gọi (hoạt ảnh mờ dần).

Có cách nào để tránh hoạt ảnh này không?

hệ điều hanh 6

Câu trả lời:


231

Cần lưu ý rằng nếu bạn đang nhắm mục tiêu iOS 7 trở lên, bạn có thể sử dụng UIViewphương pháp mới performWithoutAnimation:. Tôi nghi ngờ rằng điều này thực sự giống với các câu trả lời khác ở đây (tạm thời vô hiệu hóa UIViewhoạt ảnh / hành động Core Animation), nhưng cú pháp rất đẹp và rõ ràng.

Vì vậy, đối với câu hỏi này nói riêng ...

Mục tiêu-C:

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


Nhanh:

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


Tất nhiên nguyên tắc này có thể được áp dụng cho bất kỳ trường hợp nào mà bạn muốn đảm bảo thay đổi không bị động .


3
Điều này hoạt động tốt hơn câu trả lời được chấp nhận đối với tôi trên iOS 7+.
Philippe Sabourin

Nó vô hiệu hóa tất cả các hình ảnh động không chỉ để xem bộ sưu tập
user2159978

10
@ user2159978 Đúng vậy; tất cả các câu trả lời ở đây tạm thời vô hiệu hóa hoạt ảnh UIView. Hoạt ảnh chỉ bị vô hiệu hóa đối với các hành động được bắt đầu từ bên trong khối được chuyển vào, trong trường hợp này chỉ là tải lại chế độ xem bộ sưu tập. Đó là một câu trả lời hoàn toàn hợp lệ cho câu hỏi đang được hỏi, vì vậy tôi không nghĩ nó xứng đáng bị bỏ phiếu thấp.
Stuart

Giải pháp đáng kinh ngạc. Sử dụng này thay vì animateWithDuration: 0 ngăn chặn một cách bố trí trục trặc nhanh nhưng rõ ràng khi sử dụng các tế bào xem bộ sưu tập tự định cỡ không có itemSize
Ethan Gill

1
Giải pháp này không hoạt động nữa trên iOS 14, bên trong khối này, tôi sử dụng reloadData, nhưng với iOS 13, nó đã hoạt động
Maray97

161

Bạn cũng có thể thử điều này:

UICollectionView *collectionView;

...

[UIView setAnimationsEnabled:NO];

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

Biên tập:

Tôi cũng nhận thấy rằng nếu bạn bọc performBatchUpdatestrong một khối hoạt ảnh UIView, hoạt ảnh UIView được sử dụng thay vì hoạt ảnh mặc định, vì vậy bạn chỉ có thể đặt thời lượng hoạt ảnh thành 0, như sau:

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

Điều này cực kỳ thú vị nếu bạn muốn sử dụng hình ảnh động mùa xuân của iOS 7 trong quá trình chèn và xóa!


1
Cảm ơn bạn. Điều này rất hữu ích trong việc thêm đồng hồ bấm giờ vào ô uicollectionview.
hatunike

Xuất sắc! Tôi đã sử dụng điều này với insertCells và với bàn phím hướng lên, để tạo hoạt ảnh cho collectionView thành một độ lệch mới sau khi ô được chèn.
David H

5
Như Peter nói, điều này cản trở các hoạt ảnh khác. Thay vào đó, bạn nên gọi [UIView setAnimationsEnabled: YES] bên ngoài khối hoàn thành. Bằng cách đó bạn chỉ ngăn chặn 1 hoạt ảnh đó.
Adlai Holler

2
Tôi đã thêm một phương pháp thay thế, thực hiện chính xác điều tương tự.
Sam

1
Bao bọc performBatchUpdatesbên trong animateWithDurationlà tuyệt vời! Cảm ơn vì tiền hỗ trợ!
Robert

19

UICollectionXem hoạt ảnh các mục sau khi reloadItemsAtIndexPaths được gọi (hoạt ảnh mờ dần).

Có cách nào để tránh hoạt ảnh này không?

hệ điều hanh 6

Tôi giả sử bạn đang sử dụng FlowLayout. Vì bạn đang cố gắng loại bỏ hoạt ảnh mờ dần, hãy thử cách này:

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
    }

}

Đây là một câu hỏi rất cũ, vì vậy có thể bạn không nhắm mục tiêu iOS 6 nữa. Cá nhân tôi đang làm việc trên tvOS 11 và có cùng một câu hỏi, vì vậy đây là câu hỏi dành cho bất kỳ ai gặp phải vấn đề tương tự.


1
Đã có 3 hoặc 4 nhận xét về câu trả lời này về hiệu ứng của "Chà, câu trả lời này hoạt động rất tốt!" Ai đó đã quyết định xóa các bình luận. Tôi nghĩ, thực tế, đây là cách hiện đại và không hack để đạt được điều này, và những bình luận đó là sự công nhận điều này.
Matt Mc

8

Tôi đã viết một danh mục trên UICollectionView để làm điều đó. Mẹo là vô hiệu hóa tất cả các hoạt ảnh trong khi tải lại:

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

[self reloadItemsAtIndexPaths:indexPaths];

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

Tôi cũng nhận được phản hồi từ Apple rằng điều này sẽ không tạo ra bất kỳ hoạt ảnh nào, nếu có thì đó là một lỗi. Tôi không biết mình đang làm gì sai hay là do lỗi.
Marcin

2
Bạn cũng có thể CATransaction.setDisableActions(true)viết tắt cho điều này.
CIFilter

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

đây là nhanh chóng 3 cú pháp
Amjad Tubasi

điều này hoạt động tốt, thậm chí còn tốt hơn UIView.performWithoutAnimation
Lance Samaria

5

Đây là phiên bản Swift 3 performBatchUpdateskhông có hoạt ảnh sang a UICollectionView. Tôi thấy điều này hoạt động tốt hơn cho tôi collectionView.reloadData()vì nó làm giảm sự hoán đổi ô khi các bản ghi được chèn vào.

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

Chỉ để thêm 0,02 đô la của mình, tôi đã thử cả hai phiên bản của câu trả lời đã chọn và cách ban đầu hoạt động tốt hơn cho mục đích của tôi. Tôi đang làm việc trên chế độ xem lịch cuộn vô hạn cho phép người dùng nhập lịch vào một tuần nhất định, sau đó vuốt qua lại và chọn các ngày riêng lẻ để lọc danh sách.

Trong cách triển khai của tôi, để giữ cho mọi thứ hoạt động hiệu quả trên các thiết bị cũ hơn, mảng ngày đại diện cho chế độ xem lịch phải được giữ tương đối nhỏ, có nghĩa là giữ khoảng 5 tuần giá trị ngày, với người dùng ở giữa ở tuần thứ 3. Vấn đề với việc sử dụng cách tiếp cận thứ hai là, có một bước thứ hai mà bạn phải cuộn chế độ xem bộ sưu tập trở lại giữa mà không có hoạt ảnh, điều này làm cho hình ảnh rất lởm chởm vì lý do nào đó với hoạt ảnh cơ sở bị chặn.

Mã của tôi:

[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)
    }
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.