Có một reloadData cho một hoạt hình UITableView khi thay đổi


183

Tôi có một UITableView có hai chế độ. Khi chúng ta chuyển đổi giữa các chế độ, tôi có một số phần và ô khác nhau cho mỗi phần. Lý tưởng nhất, nó sẽ làm một số hình ảnh động mát mẻ khi bảng phát triển hoặc co lại.

Đây là mã tôi đã thử, nhưng nó không làm gì cả:

CGContextRef context = UIGraphicsGetCurrentContext(); 
[UIView beginAnimations:nil context:context]; 
[UIView setAnimationCurve:UIViewAnimationCurveEaseInOut]; 
[UIView setAnimationDuration:0.5]; 

[self.tableView reloadData];
[UIView commitAnimations];

Bất kỳ suy nghĩ về cách tôi có thể làm điều này?

Câu trả lời:


400

Thật ra, nó rất đơn giản:

[_tableView reloadSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:UITableViewRowAnimationFade];

Từ tài liệu :

Gọi phương thức này làm cho chế độ xem bảng yêu cầu nguồn dữ liệu của nó cho các ô mới cho các phần được chỉ định. Khung nhìn bảng hoạt hình việc chèn các ô mới vào vì nó hoạt hình các ô cũ ra.


13
Và chỉ đơn giản là câu trả lời tốt nhất trên trang này!
Matthias D

40
Điều này không hoàn toàn chính xác, bởi vì nó sẽ chỉ tải lại phần đầu tiên. Nếu bảng của bạn có nhiều phần, điều này sẽ không hoạt động
Nosrettap

4
Có thể bạn sẽ nhận được một ngoại lệ nếu không có dữ liệu nào thay đổi .. Xem câu trả lời
Matej

8
@Nosrettap: nếu bạn muốn có thêm hoặc tất cả các phần trong bảng của bạn tải lại, tất cả những gì bạn phải làm là mở rộng NS Indexset với tất cả các chỉ mục của phần, cũng cần được làm mới
JonPal 19/03/2015

Phiên bản Swift: _tableView.reloadSections(NSIndexSet(index: 0), withRowAnimation: .Fade)Đáng chú ý, tuy nhiên, nó chỉ cập nhật Phần 0, là phần đầu tiên, mặc định.
kbpontius 3/03/2016

260

Bạn có thể muốn sử dụng:

Mục tiêu-C

[UIView transitionWithView: self.tableView
                  duration: 0.35f
                   options: UIViewAnimationOptionTransitionCrossDissolve
                animations: ^(void)
 {
      [self.tableView reloadData];
 }
                completion: nil];

Nhanh

UIView.transitionWithView(tableView,
                          duration: 0.35,
                          options: .TransitionCrossDissolve,
                          animations:
{ () -> Void in
    self.tableView.reloadData()
},
                          completion: nil);

Swift 3, 4 & 5

UIView.transition(with: tableView,
                  duration: 0.35,
                  options: .transitionCrossDissolve,
                  animations: { self.tableView.reloadData() }) // left out the unnecessary syntax in the completion block and the optional completion parameter

Không rắc rối. : D

Bạn cũng có thể sử dụng bất kỳ thứ UIViewAnimationOptionTransitionsgì bạn muốn cho các hiệu ứng mát hơn:

  • transitionNone
  • transitionFlipFromLeft
  • transitionFlipFromRight
  • transitionCurlUp
  • transitionCurlDown
  • transitionCrossDissolve
  • transitionFlipFromTop
  • transitionFlipFromBottom

2
Điều này rất hữu ích nếu trạng thái bắt đầu / kết thúc của chế độ xem bảng của bạn sẽ rất khác nhau (và sẽ rất phức tạp khi tính toán các phần và hàng để thêm / xóa), nhưng bạn di chuyển một cái gì đó ít chói tai mà tải lại không hoạt hình.
Ben Packard

1
Đây không phải là một hình ảnh động đẹp như tải lại chế độ xem bảng bằng các phương thức được tích hợp sẵn, nhưng không giống như phương pháp được xếp hạng cao hơn được đề cập ở đây, cách này hoạt động khi bạn có nhiều phần.
Mark Bridges

1
Wow sau khi thử tất cả phần còn lại, điều này hoàn toàn phù hợp với tôi
Lucas Goossen

1
@MarkB Ink câu trả lời được xếp hạng cao hơn không hoạt động với nhiều phần :) -[_tableView reloadSections:[NSIndexSet indexSetWithIndexesInRange:NSMakeRange(0, sectionCount)] withRowAnimation:UITableViewRowAnimationFade];
lobianco

2
@Anthony Nó không hoạt động nếu trạng thái kết thúc có nhiều phần / ít hơn trạng thái bắt đầu. Sau đó, bạn phải theo dõi thủ công những phần được thêm / xóa, điều này khá rắc rối.
nikolovski

78

Có nhiều tự do hơn khi sử dụng CATransition lớp học.

Nó không bị giới hạn để mờ dần, nhưng cũng có thể thực hiện các chuyển động ..


Ví dụ:

(đừng quên nhập QuartzCore)

CATransition *transition = [CATransition animation];
transition.type = kCATransitionPush;
transition.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
transition.fillMode = kCAFillModeForwards;
transition.duration = 0.5;
transition.subtype = kCATransitionFromBottom;

[[self.tableView layer] addAnimation:transition forKey:@"UITableViewReloadDataAnimationKey"];

Thay đổi type để phù hợp với nhu cầu của bạn, như kCATransitionFadevv

Triển khai trong Swift:

let transition = CATransition()
transition.type = kCATransitionPush
transition.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
transition.fillMode = kCAFillModeForwards
transition.duration = 0.5
transition.subtype = kCATransitionFromTop
self.tableView.layer.addAnimation(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

Tài liệu tham khảo cho CATransition

Swift 5:

let transition = CATransition()
transition.type = CATransitionType.push
transition.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeInEaseOut)
transition.fillMode = CAMediaTimingFillMode.forwards
transition.duration = 0.5
transition.subtype = CATransitionSubtype.fromTop
self.tableView.layer.add(transition, forKey: "UITableViewReloadDataAnimationKey")
// Update your data source here
self.tableView.reloadData()

cái này hoạt hình toàn bộ bảng, thay vì các hàng / phần đơn lẻ.
Agos

@Agos Nó vẫn trả lời câu hỏi. Câu hỏi "Cách tải lại chỉ một hàng" có một câu trả lời hoàn toàn khác, chẳng hạn như áp dụng hình động cho thuộc layertính của a UITableViewCell.
Matej

@matejkramny Tôi dự kiến ​​bảng sẽ tạo hiệu ứng cho các hàng khác nhau (như được tham chiếu trong câu hỏi), nhưng phương thức này đẩy tất cả các bảng cùng một lúc. Có lẽ tôi đang thiếu một cái gì đó?
Agos

@Agos hmm không có nghĩa vụ phải làm điều đó. Nó không thể chỉ làm một nửa bảng vì QuartzCore điều chỉnh chế độ xem trực tiếp. Bạn có thể thử lấy các ô từ chế độ xem bảng, sau đó áp dụng hình động này cho từng ô (nhưng không chắc nó sẽ hoạt động)
Matej

2
làm việc như một cơ duyên với kCATransitionFade Cảm ơn! :)
quarezz

60

Tôi tin rằng bạn chỉ có thể cập nhật cấu trúc dữ liệu của mình, sau đó:

[tableView beginUpdates];
[tableView deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView insertSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES];
[tableView endUpdates];

Ngoài ra, "withRowAnimation" không chính xác là một kiểu boolean, mà là một kiểu hoạt hình:

UITableViewRowAnimationFade,
UITableViewRowAnimationRight,
UITableViewRowAnimationLeft,
UITableViewRowAnimationTop,
UITableViewRowAnimationBottom,
UITableViewRowAnimationNone,
UITableViewRowAnimationMiddle

Những thứ đơn giản, nhưng rất dễ dàng để truy cập trực tiếp vào StackOverflow và lấy đoạn mã bạn cần, hơn là các tài liệu lưới rà. . Cảm ơn!
Jasper Blues

24

Tất cả các câu trả lời này đều cho rằng bạn đang sử dụng UITableView chỉ với 1 phần.

Để xử lý chính xác các tình huống khi bạn có nhiều hơn 1 phần, hãy sử dụng:

NSRange range = NSMakeRange(0, myTableView.numberOfSections);
NSIndexSet *indexSet = [NSIndexSet indexSetWithIndexesInRange:range];
[myTableView reloadSections:indexSet withRowAnimation:UITableViewRowAnimationAutomatic];

(Lưu ý: bạn nên đảm bảo rằng bạn có nhiều hơn 0 phần!)

Một điều cần lưu ý là bạn có thể chạy vào NSIternalInconsistencyException nếu bạn cố cập nhật đồng thời nguồn dữ liệu của mình bằng mã này. Nếu đây là trường hợp, bạn có thể sử dụng logic tương tự như sau:

int sectionNumber = 0; //Note that your section may be different

int nextIndex = [currentItems count]; //starting index of newly added items

[myTableView beginUpdates];

for (NSObject *item in itemsToAdd) {
    //Add the item to the data source
    [currentItems addObject:item];

    //Add the item to the table view
    NSIndexPath *path = [NSIndexPath indexPathForRow:nextIndex++ inSection:sectionNumber];
    [myTableView insertRowsAtIndexPaths:[NSArray arrayWithObject:path] withRowAnimation:UITableViewRowAnimationAutomatic];
}

[myTableView endUpdates];

3
Điểm hay về tính toán phần, nhưng tôi chỉ có một phần và mã của bạn có lỗi do một. Tôi đã phải thay đổi dòng đầu tiên của mã của bạn thành phạm vi NSRange = NSMakeRange (0, myTableView.numberOfSections);
Danyal Aytekin

18

Cách để tiếp cận điều này là yêu cầu bảngView xóa và thêm các hàng và phần với

insertRowsAtIndexPaths:withRowAnimation:,
deleteRowsAtIndexPaths:withRowAnimation:,
insertSections:withRowAnimation:
deleteSections:withRowAnimation:

phương pháp của UITableView.

Khi bạn gọi các phương thức này, bảng sẽ tạo hiệu ứng vào / ra các mục bạn yêu cầu, sau đó gọi reloadData để bạn có thể cập nhật trạng thái sau hoạt ảnh này. Phần này rất quan trọng - nếu bạn làm động mọi thứ nhưng không thay đổi dữ liệu được trả về bởi dataSource của bảng, các hàng sẽ xuất hiện lại sau khi hoạt ảnh hoàn tất.

Vì vậy, luồng ứng dụng của bạn sẽ là:

[self setTableIsInSecondState:YES];

[myTable deleteSections:[NSIndexSet indexSetWithIndex:0] withRowAnimation:YES]];

Miễn là các phương thức DataSource của bảng của bạn trả về tập hợp các phần và hàng mới chính xác bằng cách kiểm tra [self tableIsInSecondState](hoặc bất cứ thứ gì), điều này sẽ đạt được hiệu quả mà bạn đang tìm kiếm.


16

Tôi không thể nhận xét về câu trả lời hàng đầu, nhưng việc thực hiện nhanh chóng sẽ là:

self.tableView.reloadSections([0], with: UITableViewRowAnimation.fade)

bạn có thể bao gồm nhiều phần như bạn muốn cập nhật trong đối số đầu tiên cho phần tải lại.

Các hình ảnh động khác có sẵn từ các tài liệu: https://developer.apple.com/reference/uikit/uitableviewrowanimation

fade Hàng được chèn hoặc xóa hoặc hàng mờ dần vào hoặc ra khỏi chế độ xem bảng.

bên phải Hàng được chèn hoặc hàng trượt vào từ bên phải; hàng bị xóa hoặc hàng trượt ra bên phải.

bên trái Hàng được chèn hoặc hàng trượt vào từ bên trái; hàng bị xóa hoặc hàng trượt ra bên trái.

trên cùng Hàng được chèn hoặc hàng trượt vào từ trên cùng; hàng bị xóa hoặc hàng trượt ra phía trên.

dưới cùng Hàng được chèn hoặc hàng trượt vào từ dưới cùng; hàng bị xóa hoặc hàng trượt ra phía dưới.

trường hợp không Các hàng được chèn hoặc xóa sử dụng các hình ảnh động mặc định.

ở giữa Chế độ xem bảng cố gắng giữ các ô cũ và mới ở giữa trong không gian mà chúng đã hoặc sẽ chiếm. Có sẵn trong iPhone 3.2.

tự động Chế độ xem bảng chọn kiểu hoạt hình phù hợp với bạn. (Được giới thiệu trong iOS 5.0.)


1
Đối với Swift 4.2: self.tableView.reloadSections ([0], với: UITableView.RowAnimation.fade)
Reefwing

14

Phiên bản Swift 4 cho câu trả lời @dmarnel:

tableView.reloadSections(IndexSet(integer: 0), with: .automatic)

9

Thực hiện Swift:

let range = NSMakeRange(0, self.tableView!.numberOfSections())
let indexSet = NSIndexSet(indexesInRange: range)
self.tableView!.reloadSections(indexSet, withRowAnimation: UITableViewRowAnimation.Automatic)

8

Dành cho Swift 4

tableView.reloadSections([0], with: UITableView.RowAnimation.fade)

1

Trong trường hợp của tôi, tôi muốn thêm 10 hàng vào bảng xem (đối với loại chức năng "hiển thị thêm kết quả") và tôi đã làm như sau:

  NSInteger tempNumber = self.numberOfRows;
  self.numberOfRows += 10;
  NSMutableArray *arrayOfIndexPaths = [[NSMutableArray alloc] init];
  for (NSInteger i = tempNumber; i < self.numberOfRows; i++) {
    [arrayOfIndexPaths addObject:[NSIndexPath indexPathForRow:i inSection:0]];
  }
  [self.tableView beginUpdates];
  [self.tableView insertRowsAtIndexPaths:arrayOfIndexPaths withRowAnimation:UITableViewRowAnimationTop];
  [self.tableView endUpdates];

Trong hầu hết các trường hợp, thay vì "self.numberOfRows", bạn thường sẽ sử dụng số lượng các mảng của các đối tượng cho chế độ xem bảng. Vì vậy, để đảm bảo giải pháp này hoạt động tốt cho bạn, "mảngOfIndexPaths" cần phải là một mảng chính xác của các đường dẫn chỉ mục của các hàng được chèn. Nếu hàng tồn tại cho bất kỳ đường dẫn chỉ mục này, mã có thể bị sập, vì vậy bạn nên sử dụng phương thức "reloadRowsAtIndexPaths: withRowAnimation:" cho các đường dẫn chỉ mục đó để tránh sự cố


1

Nếu bạn muốn thêm hình động tùy chỉnh của riêng mình vào các ô UITableView, hãy sử dụng

[theTableView reloadData];
[theTableView layoutSubviews];
NSArray* visibleViews = [theTableView visibleCells];

để có được một mảng các ô có thể nhìn thấy. Sau đó thêm bất kỳ hình ảnh động tùy chỉnh cho mỗi tế bào.

Kiểm tra ý chính này tôi đã đăng cho một hình ảnh động tùy chỉnh mượt mà. https://gist.github.com/floprr/1b7a58e4a18449d962bd


1

Hoạt hình mà không cần tải lạiData () trong Swift có thể được thực hiện như thế này (kể từ phiên bản 2.2):

tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
    // ...or here, if you need to add/remove the same amount of objects to/from somewhere
    indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
    numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()

trong trường hợp bạn cần gọi reloadData () sau khi hoạt ảnh kết thúc, bạn có thể chấp nhận các thay đổi trong CATransaction như thế này:

CATransaction.begin()
CATransaction.setCompletionBlock({() in self.tableview.reloadData() })
tableview.beginUpdates()
var indexPathsToDeleteForAnimation: [NSIndexPath] = []
var numOfCellsToRemove = ArrayOfItemsToRemove.count ?? 0

// Do your work here
while numOfCellsToRemove > 0 {
     // ...or here, if you need to add/remove the same amount of objects to/from somewhere
     indexPathsToDeleteForAnimation.append(NSIndexPath(forRow: selectedCellIndex+numOfCellsToRemove, inSection: 0))
     numOfCellsToRemove -= 1
}
tableview.deleteRowsAtIndexPaths(indexPathsToDeleteForAnimation, withRowAnimation: UITableViewRowAnimation.Right)
tableview.endUpdates()
CATransaction.commit()

Logic được hiển thị cho trường hợp khi bạn xóa các hàng, nhưng ý tưởng tương tự cũng hoạt động để thêm hàng. Bạn cũng có thể thay đổi hình động thành UITableViewRowAnimation.Left để làm cho gọn gàng hoặc chọn từ danh sách các hình ảnh động có sẵn khác.


1
CATransition *animation = [CATransition animation];
animation.duration = .3;
[animation setType:kCATransitionPush];
[animation setSubtype:kCATransitionFromLeft];
[animation setTimingFunction:[CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut]];
[animation setDuration:.3];

[[_elementTableView layer] addAnimation:animation forKey:@"UITableViewReloadDataAnimationKey"];

[tableView reloadData];

2
Tại sao đặt thời lượng .3hai lần?
Pang

1

Để tải lại tất cả các phần , không chỉ một phần với thời lượng tùy chỉnh .

durationTham số người dùng UIView.animateđể đặt thời lượng tùy chỉnh.

UIView.animate(withDuration: 0.4, animations: { [weak self] in
    guard let `self` = self else { return }
    let indexSet = IndexSet(integersIn: 0..<self.tableView.numberOfSections)
    self.tableView.reloadSections(indexSet, with: UITableView.RowAnimation.fade)
})

0

UITableViewHoạt hình bản địa trong Swift

Chèn và xóa tất cả các hàng cùng một lúc tableView.performBatchUpdatesđể chúng xảy ra đồng thời. Dựa trên câu trả lời từ @iKenndac, sử dụng các phương pháp như:

  • tableView.insertSections
  • tableView.insertRows
  • tableView.deleteSections
  • tableView.deleteRows

Ví dụ:

 tableView.performBatchUpdates({
   tableView.insertSections([0], with: .top)
 })

Điều này chèn một phần ở vị trí 0 với một hình ảnh động tải từ trên xuống. Điều này sẽ chạy lại cellForRowAtphương thức và kiểm tra một ô mới tại vị trí đó. Bạn có thể tải lại toàn bộ chế độ xem bảng theo cách này với các hình ảnh động cụ thể.

Re: câu hỏi OP, một cờ có điều kiện sẽ cần thiết để hiển thị các ô cho trạng thái xem bảng thay thế.

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.