Làm cách nào để phát hiện hoạt ảnh đã kết thúc trên UITableView beginUpdates / endUpdates?


116

Tôi đang chèn / xóa ô bảng bằng cách sử dụng insertRowsAtIndexPaths/deleteRowsAtIndexPathsgói trong beginUpdates/endUpdates. Tôi cũng đang sử dụng beginUpdates/endUpdateskhi điều chỉnh rowHeight. Tất cả các hoạt động này được làm động theo mặc định.

Làm cách nào để phát hiện hoạt ảnh đã kết thúc khi sử dụng beginUpdates/endUpdates?


1
FYI: Điều này cũng áp dụng cho -scrollToRowAtIndexPath:atScrollPosition:animated:.
Ben Lachman

Câu trả lời:


292

Cái này thì sao?

[CATransaction begin];

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

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

[CATransaction commit];

Điều này hoạt động vì hoạt ảnh tableView sử dụng CALayerhoạt ảnh bên trong. Đó là, họ thêm các hình ảnh động vào bất kỳ mở nào CATransaction. Nếu không có mở CATransactionnào tồn tại (trường hợp bình thường), thì một mở được bắt đầu một cách ngầm định, được kết thúc ở cuối vòng chạy hiện tại. Nhưng nếu bạn tự mình bắt đầu một cái, như đã xong ở đây, thì nó sẽ sử dụng cái đó.


7
Không làm việc cho tôi. Khối hoàn thành được gọi trong khi hoạt ảnh vẫn đang chạy.
mrvincenzo 19/02/13

2
@MrVincenzo Bạn đã đặt completionBlocktrước beginUpdatesendUpdatestương tự trong đoạn mã chưa?
Rudolf Adamkovič

2
[CATransaction commit]nên được gọi sau not before [tableView endUpdates].
Rudolf Adamkovič

6
Khối hoàn thành không bao giờ được gọi nếu một ô chứa chế độ xem có hoạt ảnh, tức là UIActivityIndicatorView.
markturnip

3
Sau tất cả thời gian tôi không bao giờ biết điều này. Vàng nguyên chất !! Không có gì tệ hơn khi thấy một hình ảnh động đẹp mắt bị giết với ác ý cần thiết của tableView.reloadData ().
DogCoffee

31

Phiên bản Swift


CATransaction.begin()

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

tableView.beginUpdates()
tableView.endUpdates()

CATransaction.commit()

6

Nếu bạn đang nhắm mục tiêu iOS 11 trở lên, bạn nên sử dụng UITableView.performBatchUpdates(_:completion:):

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

5

Một giải pháp khả thi có thể là kế thừa từ UITableView mà bạn gọi endUpdatesvà ghi đè lên nó setContentSizeMethod, vì UITableView điều chỉnh kích thước nội dung của nó để phù hợp với các hàng được thêm vào hoặc bị xóa. Cách tiếp cận này cũng sẽ hoạt động reloadData.

Để đảm bảo rằng thông báo chỉ được gửi sau khi endUpdatesđược gọi, người ta cũng có thể ghi đè endUpdatesvà đặt cờ ở đó.

// 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

Bạn có thể bao gồm (các) hoạt động của mình trong khối hoạt ảnh UIView như sau:

- (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);
    }];
}

Tín dụng cho https://stackoverflow.com/a/12905114/634940 .


4
Mã này không làm việc cho tôi. Khối hoàn thành đã được gọi sau endUpdates, nhưng trước khi các hoạt ảnh hoàn thành.
Tim Camber

1
Điều này không hiệu quả. Hoạt ảnh chế độ xem bảng đã ngừng hoạt động khi áp dụng mẫu này.
Primoz990

Hãy thử làm cho thời lượng dài hơn (như 0,3 giây) - nó sẽ hoạt động (nó hoạt động với tôi)
emem

1

Vẫn chưa tìm được giải pháp tốt (thiếu phân lớp UITableView). Tôi đã quyết định sử dụng performSelector:withObject:afterDelay:cho bây giờ. Không lý tưởng, nhưng hãy hoàn thành công việc.

CẬP NHẬT : Có vẻ như tôi có thể sử dụng scrollViewDidEndScrollingAnimation:cho mục đích này (điều này là cụ thể cho việc triển khai của tôi, xem nhận xét).


1
scrollViewDidEndScrollingAnimationchỉ gọi là để phản ứng lại setContentOffsetscrollRectToVisible
samvermette

@samvermette Vâng, trong trường hợp của tôi, khi beginUpdates / endUpdates được gọi, UITableView luôn chuyển động cuộn. Nhưng điều này dành riêng cho việc triển khai của tôi, vì vậy tôi đồng ý rằng nó không phải là câu trả lời tốt nhất nhưng nó phù hợp với tôi.
pixelfreak

Có vẻ như có thể đính kèm các bản cập nhật vào một khối hoạt ảnh UIView. Xem câu trả lời của tôi dưới đây: stackoverflow.com/a/14305039/634940 .
Zdenek

0

Bạn có thể sử dụng tableView:willDisplayCell:forRowAtIndexPath:như:

- (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];
}

Nhưng điều này cũng sẽ được gọi khi một ô đã có trong bảng di chuyển từ ngoài màn hình sang trên màn hình, vì vậy nó có thể không phải là chính xác những gì bạn đang tìm kiếm. Tôi chỉ cần nhìn qua tất cả các UITableViewUIScrollViewđại biểu phương pháp và có doesnt dường như bất cứ điều gì để xử lý ngay sau khi một tế bào được chèn hình ảnh động.


Tại sao không chỉ gọi phương thức bạn muốn được gọi khi hoạt ảnh kết thúc sau dấu 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];
    }
}

Cảm ơn, chown. Đừng nghĩ willDisplayCellsẽ hiệu quả. Tôi cần nó xảy ra sau hoạt ảnh vì tôi chỉ cần cập nhật trực quan sau khi mọi thứ ổn định.
pixelfreak

np @pixelfreak, nếu tôi nghĩ ra cách nào khác để thực hiện việc này, tôi sẽ cho bạn biết.
chown
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.