2013-08-06 34 views
8

Thực tế bực bội: Sau khi gọi tableView:moveRowAtIndexPath:toIndexPath:, tableView:cellForRowAtIndexPath: không được gọi cho hàng đó.Cách tải lại hàng đã di chuyển theo chương trình?

Gọi reloadRowsAtIndexPaths:withRowAnimation: sau hoặc trước tableView:moveRowAtIndexPath:toIndexPath: trong UITableView cập nhật cũng chặn không hoạt động: nó làm tăng Sự mâu thuẫn lỗi.

Tôi thấy 2 giải pháp thay thế: xóa + chèn thay vì di chuyển hoặc tải lại trong khối cập nhật khác.

Câu hỏi của tôi là: có cách nào khác để tải lại và di chuyển hàng của UITableView trong cùng một khối cập nhật không?

Trả lời

4

Tôi không nghĩ rằng bạn có thể thực hiện di chuyển và tải lại cùng một lúc. Tôi đã thử một số phương pháp tiếp cận và giải pháp tốt nhất tôi đã đưa ra là để làm việc tải lại ngay trước khi cập nhật hàng loạt. Tôi không hoạt ảnh reloadRows vì dường như xung đột với hoạt ảnh cập nhật hàng loạt.

[tableView reloadRowsAtIndexPaths:indexPathsToReload withRowAnimation:UITableViewRowAnimationNone]; 
[tableView beginUpdates]; 
//inserts, deletes and moves here 
[tableView endUpdates]; 

Ngoài ra, tôi thường đặt logic cấu hình di động của tôi trong một phương pháp riêng biệt như:

- (void)tableView:(UITableView *)tableView configureCell:(UITableViewCell *)cell atIndexPath:(NSIndexPath *)indexPath; 

Vì vậy mà tôi chỉ có thể gọi nó là trực tiếp và bỏ qua reloadRowsAtIndexPaths hoàn toàn. Bạn sẽ không nhận được các hình ảnh động được xây dựng theo cách này, nhưng bạn có thể làm hình ảnh động của riêng bạn.

+0

Điều này dường như là cách tốt nhất. Điều lạ lùng khi gọi 'reloadData' từ bên trong khối cập nhật sẽ hủy hoạt ảnh. – devios1

0

Tôi đã thành công với [TableView reloadData]. Đảm bảo bạn đang cập nhật nguồn dữ liệu của mình và đặt mã tải lại trong một vị trí phù hợp.

+2

Không có gì để làm với 'reloadData'. Trên thực tế, mục tiêu chính của tôi là loại bỏ 'reloadData', vì nó xấu xí (ví dụ:nhấp nháy) và ngắt người dùng. – folex

0

Khi di chuyển ô bạn cần phải nhận được tế bào trực tiếp thông qua phương pháp tableView.cellForRowAtIndexPath

Sau khi nhận được các tế bào, chỉ cần cập nhật nó bằng tay.

0
[_tableview beginUpdates]; 

// write code here to delete and move row... 

[_tableview endUpdates]; 

// now after end update call reload method to reload cell.. 

    [self.tableview reloadRowsAtIndexPaths:[NSArray arrayWithObjects: 
    [NSIndexPath indexPathForRow:_arrayForData.count-1 inSection:indexpathforSelectedRow.section], nil] withRowAnimation:UITableViewRowAnimationNone]; 
0

Tôi đã gặp sự cố tương tự khi sắp xếp theo "dateModified" nhưng tôi cũng hiển thị thuộc tính đó trên nhãn của ô. Cả hai "di chuyển" và "cập nhật" được yêu cầu. "di chuyển" chỉ được gọi để ô chính xác được đưa lên đầu danh sách, nhưng văn bản nhãn không cập nhật.

Giải pháp của tôi cho UITableViewCell đơn giản.

Trước tiên, bạn thực hiện cuộc gọi .move như bình thường. Trực tiếp sau khi bạn thực hiện cuộc gọi đến một phương pháp cấu hình tùy chỉnh - có trách nhiệm tạo hoạt ảnh cho "cập nhật" trên ô.

func controller(_ controller: NSFetchedResultsController<NSFetchRequestResult>, didChange anObject: Any, at indexPath: IndexPath?, for type: NSFetchedResultsChangeType, newIndexPath: IndexPath?) { 
    switch type { 
    case .insert: 
     tableView.insertRows(at: [newIndexPath!], with: .fade) 
    case .delete: 
     tableView.deleteRows(at: [indexPath!], with: .fade) 
    case .update: 
     tableView.reloadRows(at: [indexPath!], with: .fade) 
    case .move: 
     tableView.moveRow(at: indexPath!, to: newIndexPath!) 

     // Can't "reload" and "move" to same cell simultaneously. 

     // This is an issue because I'm sorting on date modified and also displaying it within a 
     // label in the UITableViewCell. 

     // To have it look perfect you have to manually crossfade the label text, while the UITableView 
     // does the "move" animation. 

     let cell = tableView.cellForRow(at: indexPath!)! 
     let note = fetchedResultsController.object(at: newIndexPath!) 
     configure(cell: cell, note: note, animated: true) 
    } 
} 

Phương pháp cấu hình trông như thế này (lưu ý hoạt hình là không bắt buộc):

internal func configure(cell: UITableViewCell, note: Note, animated: Bool = false) { 
    let dateFormatter = DateFormatter() 
    dateFormatter.dateStyle = .medium 
    dateFormatter.timeStyle = .medium 
    let dateString = dateFormatter.string(from: note.dateModified as Date) 

    if animated { 
     UIView.transition(with: cell.contentView, duration: 0.3, options: .transitionCrossDissolve, animations: { 
      cell.textLabel?.text = dateString 
     }, completion: nil) 
    } else { 
     cell.textLabel?.text = dateString 
    } 
} 

Tái sử dụng các phương pháp cấu hình ở đây mà không ảnh động:

override func tableView(_ tableView: UITableView, cellForRowAt indexPath: IndexPath) -> UITableViewCell { 
    let cell = tableView.dequeueReusableCell(withIdentifier: CellReuseIdentifier, for: indexPath) 
    let note = fetchedResultsController.object(at: indexPath) 

    configure(cell: cell, note: note) 

    return cell 
} 

Nếu bạn có một tế bào phức tạp hơn (subclass), bạn có thể di chuyển phương thức cấu hình tới mã lớp con. Phần quan trọng là có một phương pháp để cập nhật dữ liệu ô với hoạt ảnh tùy chọn.

Các vấn đề liên quan