2012-03-31 6 views
37

Tôi không di chuyển UITableView trong một UIScrollView. Tôi đặt kích thước khung hình là UITableView thành kích thước nội dung của nó.Khi nào một contentSize của UITableView được đặt?

Khi tôi thêm hàng vào số UITableView, tôi gọi insertRowsAtIndexPaths:withRowAnimation: trên UITableView. Sau đó, tôi gọi một phương thức để thay đổi kích thước khung hình của UITableView:

- (void)resizeTableViewFrameHeight 
{ 
    // Table view does not scroll, so its frame height should be equal to its contentSize height 
    CGRect frame = self.tableView.frame; 
    frame.size = self.tableView.contentSize; 
    self.tableView.frame = frame; 
} 

Có vẻ như rằng mặc dù contentSize chưa được cập nhật tại thời điểm này. Nếu tôi tự tính toán khung trong phương thức trên dựa trên số lượng hàng và phần, thì phương thức hoạt động đúng.

Câu hỏi của tôi là, làm thế nào tôi có thể nhận được UITableView để cập nhật contentSize của mình? Tôi cho rằng tôi có thể gọi reloadData và điều đó có lẽ sẽ làm điều đó, nhưng có vẻ như không hiệu quả để tải lại toàn bộ bảng khi tôi chỉ chèn một ô.

Trả lời

61

Bạn có thể buộc các UITableView để tính toán kích thước của nội dung bằng cách gọi layoutIfNeeded trên UITableView.

Ví dụ cho một lớp con UITableViewController mà phải ở trong một cái nhìn container với kích thước biến:

- (CGSize)preferredContentSize 
{ 
    // Force the table view to calculate its height 
    [self.tableView layoutIfNeeded]; 
    return self.tableView.contentSize; 
} 

Cập nhật 2016/07/28 Đây là một ví dụ Swift chưa được kiểm tra trong những điều tương tự. Nó sẽ làm việc nhưng nếu nó không xin vui lòng để lại một bình luận. Có thể có những cách tốt hơn hoặc thành ngữ hơn để làm điều này. Thật không may tôi không quen thuộc lắm với Swift.

override var preferredContentSize: CGSize { 
    get { 
     self.tableView.layoutIfNeeded() 
     return self.tableView.contentSize 
    } 
    set {} 
} 
+0

Tôi đã thử điều này, nhưng nó không hiệu quả với tôi. Nhưng, tôi đã có thể đưa ra một giải pháp khác mà tôi đã đăng ở đây: http://stackoverflow.com/questions/17634617/when-does-uitableview-content-size-update-with-row-insert-delete-animation/18665064 # 18665064 – Daren

+1

Ồ, đây chỉ dành cho nội dung ban đầu. Số dặm của bạn có thể thay đổi đối với các trường hợp khác khi kích thước đang được thay đổi sau đó. – Farthen

+7

Lưu ý cho những người mà điều này không làm việc - tableView: estimatedHeightForRowAtIndexPath messes với contentSize, vì vậy bạn có thể có may mắn chỉ bằng cách loại bỏ việc thực hiện nó. – weienw

13

Hãy thử điều này:

- (void)resizeTableViewFrameHeight 
{ 
    UITableView *tableView = self.tableView; 
    CGRect frame = tableView.frame; 
    frame.size.height = [tableView sizeThatFits:CGSizeMake(frame.size.width, HUGE_VALF)].height; 
    tableView.frame = frame; 
} 
+1

Tôi đã thử cách này và nó đã hoạt động, cảm ơn! Nhưng mặc dù nó giải quyết vấn đề của tôi, nó không thực sự trả lời câu hỏi của tôi khi kích thước nội dung được thiết lập. – Darren

+1

Tôi nghi ngờ nó được đặt trong 'layoutSubviews', nhưng tôi không cảm thấy như xác minh rằng vào lúc này. –

19

Trong khi tôi không yêu KVO (Key-Value Observing), đó là một cách khá tốt để biết chính xác khi nào của contentSize bảng của bạn đã thay đổi (thay vì chỉ gọi phương pháp cập nhật của bạn trong một loạt các nơi ngẫu nhiên) . Nó khá đơn giản để sử dụng (mặc dù hơi khó hiểu và ngầm). Để quan sát những thay đổi trên bảng của contentSize, làm như sau:

1) Trở thành một người quan sát tài sản contentSize của bảng của bạn như sau:

[self.tableView addObserver:self forKeyPath:@"contentSize" options:NSKeyValueObservingOptionNew context:NULL]; 

này thường được thực hiện trong điều khiển xem chứa tableView (như ví dụ: viewDidLoad:).

2) Thực hiện KVO phương pháp quan sát và thực hiện những thay đổi bạn cần:

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSString *,id> *)change context:(void *)context { 
    if(object == self.tableView && [keyPath isEqualToString:@"contentSize"]) { 
     // perform your updates here 
    } 
} 

3) Di chuyển điều khiển xem của bạn khi một người quan sát tại một số điểm hợp lý (tôi gọi nó trong dealloc).Bạn làm điều này như sau:

- (void)dealloc { 
    [self.tableView removeObserver:self forKeyPath:@"contentSize"]; 
} 
+1

Cảm ơn bạn đã nhắc nhở tôi về người đàn ông KVO. Tôi thấy đây là giải pháp duy nhất hoạt động trên bố cục khá phức tạp của tôi. – preams

+0

Hãy để tôi ghi chú ở đây. Tôi sử dụng để sử dụng KVO để di chuyển như bạn đã đề cập. Tuy nhiên, nó sẽ không hoạt động bình thường sau iOS 11 nếu bạn đang sử dụng beginUpdates và endUpdates. Trong iOS 11, contentSize thay đổi trong các bản cập nhật, tức là nếu bạn cuộn ngay sau khi contentSize thay đổi, bạn sẽ thay đổi vị trí của chế độ xem bảng trong khi cập nhật, điều này sẽ đưa bạn đến các lỗi rất lạ. Kiểm tra câu hỏi của tôi [ở đây] (https://stackoverflow.com/questions/46587878/uitableview-header-not-disappearing/46854828#46854828), bằng cách sử dụng KVO là lý do cho lỗi của tôi. –

+0

Ở đây cần thông báo: sử dụng Runloop để tránh đệ quy chạy ngoại lệ ném xấu hàng đầu. – 0xDatou

0

này đã làm việc cho tôi, khi giải quyết các vấn đề của tableview nhận được kích thước phù hợp sau khi thêm/loại bỏ hàng

Sử dụng

tableView.layoutIfNeeded() 

và thiết

tableView.estimatedRowHeight = UITableViewAutomaticDimension 
3
  1. Thêm quan sát viên (trong mẫu của tôi trong viewDidLoad

    tableView.addObserver(self, forKeyPath: "contentSize", options: .new, context: nil) 
    
  2. Quan sát giá trị

    override func observeValue(forKeyPath keyPath: String?, of object: Any?, change: [NSKeyValueChangeKey : Any]?, context: UnsafeMutableRawPointer?) { 
        if let obj = object as? UITableView { 
         if obj == self.tableView && keyPath == "contentSize" { 
          if let newSize = change?[NSKeyValueChangeKey.newKey] as? CGSize { 
           //do stuff here 
          } 
         } 
        } 
    } 
    
  3. Di quan sát khi không cần

    deinit { 
        self.tableView.removeObserver(self, forKeyPath: "contentSize") 
    } 
    
0

Bạn có thể thay đổi khung của chân. Tôi gọi trước khi hoạt hình xuất hiện chân trang.

if self.newTableView.contentSize.height < self.newTableView.frame.height { 
     let additionalHeight: CGFloat = self.newTableView.frame.height - self.newTableView.contentSize.height 

     let tableFooterView = self.newTableView.tableFooterView! 

     let x = tableFooterView.frame.origin.x 
     let y = tableFooterView.frame.origin.y + additionalHeight 
     let width = tableFooterView.frame.width 
     let height = tableFooterView.frame.height 

     tableFooterView.frame = CGRect(x: x, y: y, width: width, height: height) 
    }