8

Tôi đã có UICollectionView điển hình đang sử dụng UICollectionViewFlowLayout theo kiểu thẳng đứng. Tôi đang sử dụng API còn lại có phân trang để điền vào chế độ xem bộ sưu tập. Để kích hoạt các trang tiếp theo để tải về, Tôi đang sử dụng các đại biểu khi nó yêu cầu bố trí footer:Các vấn đề chèn vào phần UICollectionView có chứa một chân trang

- (UICollectionReusableView *)collectionView:(UICollectionView *)collectionView viewForSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath{ 
    RDLoadMoreReusableView *view = [collectionView dequeueReusableSupplementaryViewOfKind:kind withReuseIdentifier:@"RDLoadMoreReusableView" forIndexPath:indexPath]; 
    view.delegate = self; 
    [view start]; 
    [self loadNextPageOfAssets]; 
    return view; 
} 

Đây là mã đằng sau loadNextPageOfAssets tôi:

-(void)loadNextPageOfAssets{ 
    __weak RDRadiusGridViewController *weakSelf = self; 

    // Increment page and request assets. They are added to cluster.assets before the completion block is called. 
    self.cluster.pagination.page++; 
    [self.cluster requestAssetsWithCompletionBlock:^(NSArray *assets) { 

     SM_LOG_DEBUG(@"page.total: %ld assets.count: %ld", self.cluster.pagination.totalCount, (long)assets.count); 

     NSMutableArray *indexPaths = [[NSMutableArray alloc]initWithCapacity:assets.count]; 
     for(NSUInteger index = 0; index < assets.count; index++){ 
      NSIndexPath *indexPath = [NSIndexPath indexPathForItem:self.cluster.assets.count - assets.count + index inSection:0]; 
      SM_LOG_DEBUG(@"Inserting indexPath: %ld:%ld", (long)indexPath.item, (long)indexPath.section); 
      [indexPaths addObject:indexPath]; 
     } 
     [weakSelf.collectionView performBatchUpdates:^{ 
      [weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; 
     } completion:^(BOOL finished) { 

     }]; 

//   [weakSelf.collectionView reloadData]; 
    }]; 
} 

Khi tôi chạy tôi có thể truy cập ViewController của tôi và xem trang đầu tiên của nội dung được tải. Nếu tôi di chuyển xuống tôi sẽ xem xem chân (trong đó có một spinner), nhưng sau đó mã sẽ phá vỡ tại điểm hòa vốn ngoại lệ tại dòng:

[weakSelf.collectionView insertItemsAtIndexPaths:indexPaths]; 

thất bại Assertion trong - [UICollectionViewData layoutAttributesForSupplementaryElementOfKind: atIndexPath:] , /SourceCache/UIKit/UIKit-3185.20/UICollectionViewData.m:829


Sau đó, nếu tôi tiếp tục nó bị treo với lỗi:

2014/06/11 16: 39: 58,335 Radius-iOS [ 4901: 525006] * Chấm dứt ứng dụng do còn tự do ngoại lệ 'NSInternalInconsistencyException', lý do: 'không dụ UICollectionViewLayoutAttributes cho -layoutAttributesForSupplementaryElementOfKind: UICollectionElementKindSectionFooter tại đường {chiều dài = 2, đường dẫn = 0 - 0}' * Đầu tiên gọi ném stack:


này là khó hiểu để tôi. layoutAttributesForSupplementaryElementOfKind âm thanh như nó là seomthing để làm với lớp bố trí, nhưng tôi không sử dụng một bố trí dòng tùy chỉnh thay vì một mặc định cung cấp. Nghe có vẻ như mã của Apple là điên nhưng tôi cảm thấy rằng tôi đang sử dụng mọi thứ một cách chính xác.

Bây giờ nếu tôi di chuyển cuộc gọi:

[self loadNextPageOfAssets]; 

từ dequeue di động bổ sung cho teh UICollectionViewCell deque, và loại bỏ các quan điểm chân tất cả lại với nhau, sau đó chèn các công trình lớn.

Hiện tại tôi đang gọi lại tải lạiData thay vì chèn, nhưng đây là UGLY.

Tôi có thấy cái gì về chân trang không?

+0

wel .. cho người mới bắt đầu bạn có thể kiểm tra các yếu tố bổ sung loại đó được thông qua vào viewForSupplementaryElementOfKind – govi

Trả lời

8

Câu trả lời được cung cấp bởi VaporwareWolf là một chút hack. Bằng cách trả lại một kích thước nhỏ thay vì kích thước bằng không, chế độ xem bổ sung sẽ luôn tồn tại nhưng ở kích thước quá nhỏ để xem. Vì vậy, đó là lý do tại sao nó sửa chữa NSInternalInconsistencyException

Nhưng, có một giải pháp thực .

Sau thêm dữ liệu vào nguồn dữ liệu và trước gọi insertItemsAtIndexPaths, chỉ cần vô hiệu hóa việc bố trí trên collectionview để làm cho nó nhận thức được sự thay đổi này.

Objective-C

[self.collectionView.collectionViewLayout invalidateLayout] 

Swift

collectionView.collectionViewLayout.invalidateLayout() 
+0

Tôi sẽ đồng ý với bạn. Tôi đã học được rất nhiều về UICollectionView kể từ khi tôi thực hiện bài này năm trước. Thay đổi điều này thành câu trả lời được chấp nhận. – VaporwareWolf

+0

Cảm ơn câu trả lời tuyệt vời. Tôi cũng phải đối mặt với cùng một vấn đề. Sử dụng bố cục tùy chỉnh mặc định và trả lại CGSizeZero cho chế độ xem chân trang của tôi khi nguồn dữ liệu trống. Ứng dụng sẽ hỏng nếu tôi không gọi invalidateLayout trước khi chèn hoặc di chuyển các phương thức – PrimaryChicken

0

Có một bài viết lớn bằng tiếng Nga về các lỗi trong UICollectionView: http://habrahabr.ru/post/211144/.

Dưới đây là một vài phương pháp từ bài viết mà có thể giải quyết vấn đề của bạn:

@try { 
    [self.collectionView insertItemsAtIndexPaths:indexPaths]; 
} 
@catch (NSException *exception) {} 

hoặc

[self.collectionView performBatchUpdates:^{ 
     [self.collectionView reloadData]; 
    } completion:nil]; 
0

Bạn nên thực hiện cả hai phương pháp (Header và Footer). Ngay cả khi bạn muốn chỉ có một.Nhìn vào mã của tôi

-(UICollectionReusableView *) collectionView:(UICollectionView *) collectionView 
      viewForSupplementaryElementOfKind:(NSString *) kind 
           atIndexPath:(NSIndexPath *) indexPath 
{ 
    UICollectionReusableView *header = [[UICollectionReusableView alloc] init]; 

    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { 

     header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionHeader withReuseIdentifier:@"CollectionViewHeader" forIndexPath:indexPath]; 
    } 
    else { 
     header = [collectionView dequeueReusableSupplementaryViewOfKind:UICollectionElementKindSectionFooter withReuseIdentifier:@"CollectionViewHeader" forIndexPath:indexPath]; 
    } 

    return header; 
} 

-(CGSize) collectionView:(UICollectionView *) collectionView 
         layout:(UICollectionViewLayout *) collectionViewLayout 
referenceSizeForHeaderInSection:(NSInteger) section 
{ 
    return CGSizeMake(self.view.frame.size.width, 100); 
} 

-(CGSize) collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout *)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section { 
    return CGSizeZero; 
} 
8

Nó chỉ ra rằng tôi đã thực sự gặp một vấn đề với cách bố trí (như mô tả lỗi gợi ý)

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForFooterInSection:(NSInteger)section{ 
    if(<myDecision>){ 
     return CGSizeZero; 
    } else { 
     return CGSizeMake(320, 50); 
    } 
} 

CGSizeZero là những gì đã gây ra tai nạn. Thay vào đó sử dụng CGSizeMake (0,001, 0,001). Đó là thay đổi duy nhất cần thiết. Nó chạy như dự định bây giờ.

+1

Cảm ơn cho điều này là những gì! Bất kỳ lý do tại sao người ta không thể chỉ đơn giản là trở về CGSizeZero? Nó cực kỳ khó chịu khi phải xử lý các cơn giận dữ của bộ sưu tập xem: ( – akdsouza

+0

đó là siêu bực bội nhưng điều này được sắp xếp nó nhờ! :) – agandi

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