2015-08-03 18 views
7

Tôi đang cố gắng sao chép một kịch bản mà tôi có một giao diện bộ sưu tập ở phía trên cùng của hàng đầu tiên của giao diện bộ sưu tập, sau đó xem phần tiêu đề (đối với indexPath.section == 1) dính vào khung nhìn tiêu đề mà không bị chồng chéo hoặc đi bên dưới nó.UICollectionView Mục Tiêu đề Gắn vào một Y nào đó

Tôi đã triển khai bố cục tùy chỉnh để làm cho tiêu đề dính. Nhưng tôi không thể làm cho nó dính vào chế độ xem tiêu đề (vì vậy sau 'chiều cao' origin.y +), nó sẽ nằm ở đầu chế độ xem bộ sưu tập.

Dưới đây là cấu trúc của tôi IB:

enter image description here

với cách bố trí tùy chỉnh liên kết lên:

enter image description here

Đây là kịch bản lý tưởng:

Trước khi di chuyển:

012.351.

enter image description here

Sau khi di chuyển:

enter image description here

Dưới đây là mã của tôi:

@implementation LLCollectionCustomFlowLayout 

- (BOOL)shouldInvalidateLayoutForBoundsChange:(CGRect)newBounds 
{ 
    return YES; 
} 

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect { 

    NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; 

    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet]; 
    for (NSUInteger idx=0; idx<[answer count]; idx++) { 
     UICollectionViewLayoutAttributes *layoutAttributes = answer[idx]; 

     if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { 
      [missingSections addIndex:layoutAttributes.indexPath.section]; // remember that we need to layout header for this section 
     } 
     if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { 
      [answer removeObjectAtIndex:idx]; // remove layout of header done by our super, we will do it right later 
      idx--; 
     } 
    } 

    // layout all headers needed for the rect using self code 
    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 
     NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx]; 
     UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; 
     if (layoutAttributes != nil) { 
      [answer addObject:layoutAttributes]; 
     } 
    }]; 

    return answer; 
} 


- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 
    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; 
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { 
     UICollectionView * const cv = self.collectionView; 
     CGPoint const contentOffset = cv.contentOffset; 
     CGPoint nextHeaderOrigin = CGPointMake(INFINITY, INFINITY); 

     if (indexPath.section+1 < [cv numberOfSections]) { 
      UICollectionViewLayoutAttributes *nextHeaderAttributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section+1]]; 
      nextHeaderOrigin = nextHeaderAttributes.frame.origin; 
     } 

     CGRect frame = attributes.frame; 
     if (self.scrollDirection == UICollectionViewScrollDirectionVertical) { 

      frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame)); 


     } 
     else { // UICollectionViewScrollDirectionHorizontal 
      frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), nextHeaderOrigin.x - CGRectGetWidth(frame)); 
     } 
     attributes.zIndex = 1024; 
     attributes.frame = frame; 
    } 
    return attributes; 
} 

- (UICollectionViewLayoutAttributes *)initialLayoutAttributesForAppearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 
    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; 
    return attributes; 
} 
- (UICollectionViewLayoutAttributes *)finalLayoutAttributesForDisappearingSupplementaryElementOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 
    UICollectionViewLayoutAttributes *attributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; 
    return attributes; 
} 

@end 

Trả lời

3

Tôi đã giải quyết nó một cách sơ sài:

- (NSArray *) layoutAttributesForElementsInRect:(CGRect)rect { 

    NSMutableArray *answer = [[super layoutAttributesForElementsInRect:rect] mutableCopy]; 

    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet]; 
    for (NSUInteger idx=0; idx<[answer count]; idx++) { 
     UICollectionViewLayoutAttributes *layoutAttributes = answer[idx]; 

     if (layoutAttributes.representedElementCategory == UICollectionElementCategoryCell) { 
      [missingSections addIndex:layoutAttributes.indexPath.section]; // remember that we need to layout header for this section 
     } 
     if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) { 
      [answer removeObjectAtIndex:idx]; // remove layout of header done by our super, we will do it right later 
      idx--; 
     } 
    } 

    // layout all headers needed for the rect using self code 
    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) { 
     NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx]; 
     UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; 
     if (layoutAttributes != nil) { 
      [answer addObject:layoutAttributes]; 
     } 

     if (idx == 1) { 
      NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:0]; 
      UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath]; 
      if (layoutAttributes != nil) { 
       [answer addObject:layoutAttributes]; 
      } 
     } 
    }]; 

    return answer; 
} 

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 
    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; 
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { 
     UICollectionView * const cv = self.collectionView; 
     CGPoint const contentOffset = cv.contentOffset; 
     CGPoint previousHeaderOrigin = CGPointMake(INFINITY, INFINITY); 
     CGFloat previousSectionY = 0; 

     if (indexPath.section == 1) { 
      UICollectionViewLayoutAttributes *previousHeaderAttributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:0]]; 
      previousSectionY = previousHeaderAttributes.frame.origin.y; 
     } 

     CGRect frame = attributes.frame; 
     if (self.scrollDirection == UICollectionViewScrollDirectionVertical) { 

      if (indexPath.section == 0) { 
       frame.origin.y = MAX(contentOffset.y, frame.origin.y); 
      }else{ 
      frame.origin.y = MAX(previousSectionY+frame.size.height, frame.origin.y); 
      } 
     } 
     else { // UICollectionViewScrollDirectionHorizontal 
      frame.origin.x = MIN(MAX(contentOffset.x, frame.origin.x), previousHeaderOrigin.x - CGRectGetWidth(frame)); 
     } 
     attributes.zIndex = 1024; 
     attributes.frame = frame; 
    } 
    return attributes; 
} 

Ngoài ra, trong tập tin mà tôi có collectionView:

- (UIEdgeInsets)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout insetForSectionAtIndex:(NSInteger)section{ 

    if (section == 0) { 
     return UIEdgeInsetsMake(-kHEIGHT_TOP_VIEW, 0, 0, 0); 
    }else 
     return UIEdgeInsetsMake(0, 0, 0, 0); 

} 

- (CGSize)collectionView:(UICollectionView *)collectionView layout:(UICollectionViewLayout*)collectionViewLayout referenceSizeForHeaderInSection:(NSInteger)section 
{ 

     return CGSizeMake(self.collectionView.frame.size.width, -kHEIGHT_TOP_VIEW); 
} 

Nếu bạn có câu trả lời hay hơn, hãy cho tôi biết để tôi có thể chấp nhận và trao cho bạn tiền thưởng.

4

Vấn đề là ở đây:

frame.origin.y = MIN(MAX(contentOffset.y, frame.origin.y), nextHeaderOrigin.y - CGRectGetHeight(frame)); 

Khi tiêu đề là tiêu đề cuối cùng, nextHeaderOrigin = CGPointMake(INFINITY, INFINITY). Đó là lý do tại sao frame.origin.y sẽ là MAX(contentOffset.y, frame.origin.y) và dính vào đầu chế độ xem bộ sưu tập. Bạn nên cập nhật layoutAttributesForSupplementaryViewOfKind trong cách tiếp theo:

- (UICollectionViewLayoutAttributes *)layoutAttributesForSupplementaryViewOfKind:(NSString *)kind atIndexPath:(NSIndexPath *)indexPath { 
    UICollectionViewLayoutAttributes *attributes = [super layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:indexPath]; 
    if ([kind isEqualToString:UICollectionElementKindSectionHeader]) { 
     // for the header in the section #0, we have "sticky" behaviour by default 
     if (indexPath.section == 0) { 
      return attributes; 
     } 
     CGPoint contentOffset = self.collectionView.contentOffset; 
     UICollectionViewLayoutAttributes *prevHeaderAttributes = [self layoutAttributesForSupplementaryViewOfKind:kind atIndexPath:[NSIndexPath indexPathForItem:0 inSection:indexPath.section - 1]]; 
     CGFloat prevHeaderMaxY = CGRectGetMaxY(prevHeaderAttributes.frame); // The maximum Y value from the previous header should be the position we use to "stick" the current one 
     CGFloat prevHeaderMaxX = CGRectGetMaxX(prevHeaderAttributes.frame); 
     CGRect frame = attributes.frame; 
     if (self.scrollDirection == UICollectionViewScrollDirectionVertical) { 
      frame.origin.y = MAX(frame.origin.y, prevHeaderMaxY); 
     } 
     else { // UICollectionViewScrollDirectionHorizontal 
      frame.origin.x = MAX(frame.origin.x, prevHeaderMaxX); 
     } 
     attributes.frame = frame; 
    } 
    return attributes; 
} 
+0

Cảm ơn câu trả lời của bạn. Nó không hoạt động mặc dù. Sau khi sửa hai cảnh báo trình biên dịch (prevHeaderMaxY và prevHeaderMaxX nên là CGFloats), tiêu đề không dính vào đầu nữa. Tôi tin rằng điều này là do sự vắng mặt của một phần [0] tiêu đề. Vì nó là nil, nó không thể tìm thấy điểm gắn bó. – jonypz

+0

Tôi đã đặt tiêu đề đầu tiên trở lại và nó vẫn không hoạt động. Bây giờ tiêu đề không còn dính nữa. – jonypz

+0

Cố gắng sử dụng 'UICollectionViewLayoutAttributes * prevHeaderAttributes = [self layoutAttributesFor ...' thay vì 'UICollectionViewLayoutAttributes * prevHeaderAttributes = [super ...'. Cuộc gọi siêu sẽ không trả về các thuộc tính chính xác của giá trị cũ. tiêu đề – sgl0v

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