2012-07-17 12 views
5

Tôi đã tạo một UITableview với các phần có thể nhấp được. Khi bạn bấm vào chúng,insertRowsAtIndexPaths: với scrollToRowAtIndexPath: khiến các phần UITableView bị ẩn không chính xác

  1. họ "mở rộng" để lộ các tế bào trong chúng
  2. cuộn phần nhấp lên đỉnh điểm.

tôi tính toán tất cả các indexpaths để chèn/xóa các tế bào cần thiết và sau đó chèn chúng với đoạn mã sau:

[self.tableView beginUpdates]; 
[self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation]; 
[self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation]; 
[self.tableView endUpdates]; 
[self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; 

Chỉ có một vấn đề- các phần bên dưới phần chọn được ẩn. Ảnh chụp màn hình đầu tiên cho biết cách xem bảng. Màn hình thứ hai-shot cho thấy nó trông như thế nào.

Sections Disappear

Nếu bạn di chuyển lên (do các phần ẩn là offscreen) và sau đó di chuyển xuống, các phần ẩn được đưa trở lại (một lần nữa có thể nhìn thấy). Tôi đoán là tại sao điều này xảy ra như sau:

Hoạt ảnh chèn/xóa đang diễn ra cùng lúc với scrollToRowAtIndexPath và điều này gây nhầm lẫn cho TableView. Nếu tôi đã không thực hiện scrollToRowAtIndexPath phần 3 & 4 sẽ có được offscreen - và do đó tableView bằng cách nào đó vẫn nghĩ rằng họ là offscreen. UITableview ẩn các ô/phần không có màn hình dưới dạng tối ưu hóa. Nếu tôi gọi scrollToRowAtIndexPath với số dispatch_after trong 2 giây thì các phần 3 & 4 được hiển thị chính xác.

Vì vậy, tôi nghĩ rằng tôi biết tại sao điều này xảy ra, nhưng tôi không biết cách sửa/ghi đè tối ưu hóa UITableview này. Trên thực tế, nếu tôi triển khai scrollViewDidEndScrollingAnimation và sau đó thêm điểm ngắt trong chức năng này, ứng dụng sẽ hiển thị các phần 3 & 4 chính xác (đó là cách tôi nhận được ảnh chụp màn hình đầu tiên). Nhưng một khi tiếp tục từ chức năng này, các tế bào biến mất.

Dự án đầy đủ có thể được tải về here


chi tiết thực hiện bổ sung: Phần là phần UITableView hợp pháp. Tôi đã thêm một tapGestureRecognizer mà kích hoạt một cuộc gọi lại đại biểu đến tableview. Dưới đây là toàn bộ phương pháp mở các phần.

- (void)sectionHeaderView:(SectionHeaderView *)sectionHeaderView sectionOpened:(NSInteger)sectionOpened 
{ 
    // Open 
    sectionHeaderView.numRows = DefaultNumRows; 
    sectionHeaderView.selected = YES; 
    NSMutableArray *pathsToOpen = [[NSMutableArray alloc] init]; 
    for (int i = 0; i < sectionHeaderView.numRows; i++) 
    { 
     NSIndexPath *pathToOpen = [NSIndexPath indexPathForRow:i inSection:sectionOpened]; 
     [pathsToOpen addObject:pathToOpen]; 
    } 

    // Close 
    NSMutableArray *pathsToClose = [[NSMutableArray alloc] init]; 
    if (openSectionHeader) 
    { 
     for (int i = 0; i < openSectionHeader.numRows; i++) 
     { 
      NSIndexPath *pathToClose = [NSIndexPath indexPathForRow:i inSection:openSectionHeader.section]; 
      [pathsToClose addObject:pathToClose]; 
     } 
    } 

    // Set Correct Animation if section's already open 
    UITableViewRowAnimation insertAnimation = UITableViewRowAnimationBottom; 
    UITableViewRowAnimation deleteAnimation = UITableViewRowAnimationTop; 
    if (!openSectionHeader || sectionOpened < openSectionHeader.section) 
    { 
     insertAnimation = UITableViewRowAnimationTop; 
     deleteAnimation = UITableViewRowAnimationBottom; 
    } 

    openSectionHeader.numRows = 0; 
    openSectionHeader.selected = NO; 
    openSectionHeader = sectionHeaderView; 


    [self.tableView beginUpdates]; 
    [self.tableView insertRowsAtIndexPaths:pathsToOpen withRowAnimation:insertAnimation]; 
    [self.tableView deleteRowsAtIndexPaths:pathsToClose withRowAnimation:deleteAnimation]; 
    [self.tableView endUpdates]; 
    [self.tableView scrollToRowAtIndexPath:[pathsToOpen objectAtIndex:0] atScrollPosition:UITableViewScrollPositionTop animated:YES]; 
} 
+0

Tôi nghĩ rằng bạn nên sử dụng tốt hơn MVC do Apple cung cấp. Tất cả những gì bạn phải làm là thêm/xóa dữ liệu vào nguồn dữ liệu của mình và không chạm vào hàng tableview – divol

+0

Vui lòng thêm một chút dự án của bạn vào câu hỏi, thay vì mong đợi tải xuống - ví dụ: cách bạn tính toán đường dẫn chỉ mục để thêm/xóa và các phần tiêu đề phần "Phần X" của bạn hay chúng chỉ là các ô? Nó sẽ làm cho một câu hỏi độc lập tốt hơn nếu nó không quá phụ thuộc vào tải về dự án của bạn. – jrturton

+0

Tôi nghĩ rằng đoán của bạn là đúng, là tốt. Bạn có thể thử tải lại các hàng tại phương thức ủy nhiệm đã kết thúc cuộn không? – jrturton

Trả lời

6

Từ những gì tôi có thể biết, sự cố xảy ra khi trả lại chế độ xem phần đã được sử dụng. Thay vì:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section 
{ 
    return [self.sectionHeaderViews objectAtIndex:section]; 
} 

tôi nhận được không có vấn đề nếu tôi tạo ra một cái nhìn mới mỗi lần:

- (UIView *)tableView:(UITableView*)tableView viewForHeaderInSection:(NSInteger)section{ 
    SectionHeaderView *sectionHeaderView = [self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName]; 
    sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", section]; 

    UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)]; 
    [sectionHeaderView addGestureRecognizer:tapRecognizer]; 
    sectionHeaderView.section = section; 
    sectionHeaderView.delegate = self; 
    return sectionHeaderView; 
} 

Có thể điều này xảy ra bởi vì bạn đang sử dụng [self.tableView dequeueReusableCellWithIdentifier:SectionHeaderView_NibName]; để tạo tiêu đề mục và giữ cho họ trong một mảng, mà tôi không nghĩ rằng UITableViewCell được tạo ra, nhưng tôi không chắc chắn. Bạn có thể muốn xem xét đã đề cập đến UITableViewCell cho các khung nhìn phần và thay vào đó sử dụng một cái gì đó khác (có lẽ là một UIImageView với một UILabel). Hoặc bạn có thể không lưu trữ các phần xem trong một mảng ... cách bạn hiện đang có mã của bạn thiết lập, bạn không cần mảng và tạo ra một cái nhìn mới là tầm thường, đủ bạn không cần phải lo lắng về nó.

4

@ công trình câu trả lời AaronHayman của (và IMO chấp nhận và tiền thưởng nên đi với anh ta, vì nó đứng - điều này chỉ không phù hợp trong một chú thích), nhưng tôi sẽ đi xa hơn - bạn không nên sử dụng một ô ở tất cả cho tiêu đề phần, và bạn không nên sử dụng cơ chế dequeue để tải về một nib.

Chế độ xem tiêu đề của phần không được coi là ô và bạn có thể nhận được các hiệu ứng bằng cách sử dụng chúng thay cho chế độ xem thông thường, đặc biệt nếu chúng được đặt trước - bảng sẽ lưu danh sách các ô có thể tái sử dụng này khi bạn thực hiện và tái chế chúng khi chúng tắt màn hình, nhưng tiêu đề phần của bạn không thể sử dụng lại được, bạn có một phần cho mỗi phần.

Trong dự án mẫu của bạn, tôi đã thay đổi các lớp cha của SectionHeaderView là một UIView đồng bằng, và thay đổi phương pháp createSectionHeaderViews của bạn để tải trực tiếp từ ngòi có:

NSMutableArray *sectionHeaderViews = [[NSMutableArray alloc] init]; 
    UINib *headerNib = [UINib nibWithNibName:SectionHeaderView_NibName bundle:nil]; 
    for (int i = 0; i < 5; i++) 
    { 
     SectionHeaderView *sectionHeaderView = [[headerNib instantiateWithOwner:nil options:nil] objectAtIndex:0]; 
     sectionHeaderView.textLabel.text = [NSString stringWithFormat:@"Section %d", i]; 

     UITapGestureRecognizer *tapRecognizer = [[UITapGestureRecognizer alloc] initWithTarget:sectionHeaderView action:@selector(handleTap:)]; 
     [sectionHeaderView addGestureRecognizer:tapRecognizer]; 
     sectionHeaderView.section = i; 
     sectionHeaderView.delegate = self; 

     [sectionHeaderViews addObject:sectionHeaderView]; 
    } 
    self.sectionHeaderViews = sectionHeaderViews; 

Tôi cũng nhận xét ra các đăng ký cho dòng tái sử dụng từ chế độ xem của bạnDidLoad. Điều này ngăn không cho tiêu đề phần biến mất.

+0

Ý tưởng tốt cho thấy anh ta làm thế nào để nhanh chóng xem từ một Nib. Tôi thường tạo ra tất cả các quan điểm của tôi trong mã vì vậy tôi thậm chí không nghĩ về điều đó. –