OGeek|极客世界-中国程序员成长平台

标题: ios - 顶部固定有 SupplementaryView 的 JSQMessagesViewController [打印本页]

作者: 菜鸟教程小白    时间: 2022-12-11 16:36
标题: ios - 顶部固定有 SupplementaryView 的 JSQMessagesViewController

我已经覆盖了 collectionView:viewForSupplementaryElementOfKind:atIndexPath: 以快速显示我的 JSQMessagesViewController 子类的标题 View 。这确实很好用,但标题 View 会随着聊天滚动,我希望将其固定在顶部。

Apple 在 iOS 9 中引入了 sectionHeadersPinToVisibleBounds 属性,这应该有固定的标题 View ,但由于某种原因,这在 JSQMessagesViewController 子类中不起作用。我已经添加了 self.collectionView.collectionViewLayout.sectionHeadersPinToVisibleBounds = true 查看DidLoad()

我尝试的另一个解决方案(来自这篇文章 How to make Supplementary View float in UICollectionView as Section Headers do in UITableView plain style )是继承 JSQMessagesCollectionViewFlowLayout,这几乎奏效了。向上滑动时,标题 View 固定在顶部,聊天消息推送到标题 View 下方。但是,当我尝试向下滑动时,当应用崩溃时,我的控制台中会收到以下错误:

*** Assertion failure in -[UICollectionViewData validateLayoutInRect:], /BuildRoot/Library/Caches/com.apple.xbs/Sources/UIKit/UIKit-3512.60.12/UICollectionViewData.m:408
*** Terminating app due to uncaught exception 'NSInternalInconsistencyException', reason: 'layout attributes for supplementary item at index path (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}) changed from <JSQMessagesCollectionViewLayoutAttributes: 0x13f65a730> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 0; 414 100); zIndex = 10;  to <JSQMessagesCollectionViewLayoutAttributes: 0x13f679920> index path: (<NSIndexPath: 0xc000000000000016> {length = 2, path = 0 - 0}); element kind: (UICollectionElementKindSectionHeader); frame = (0 10; 414 100); zIndex = 1024;  without invalidating the layout'

有没有人以同样的方式为 JSQMessagesViewController 成功修复了标题 View ?

我改变的方法是 shouldInvalidateLayoutForBoundsChange: 我返回的是,

和 layoutAttributesForElementsInRect: 我改为:

- (NSArray *)layoutAttributesForElementsInRectCGRect)rect
{
    NSMutableArray *attributesInRect = [[super layoutAttributesForElementsInRect:rect] mutableCopy];

//    if (self.springinessEnabled) {
//        NSMutableArray *attributesInRectCopy = [attributesInRect mutableCopy];
//        NSArray *dynamicAttributes = [self.dynamicAnimator itemsInRect:rect];
//        
//        //  avoid duplicate attributes
//        //  use dynamic animator attribute item instead of regular item, if it exists
//        for (UICollectionViewLayoutAttributes *eachItem in attributesInRect) {
//            
//            for (UICollectionViewLayoutAttributes *eachDynamicItem in dynamicAttributes) {
//                if ([eachItem.indexPath isEqual:eachDynamicItem.indexPath]
//                    && eachItem.representedElementCategory == eachDynamicItem.representedElementCategory) {
//                    
//                    [attributesInRectCopy removeObject:eachItem];
//                    [attributesInRectCopy addObject:eachDynamicItem];
//                    continue;
//                }
//            }
//        }
//        
//        attributesInRect = attributesInRectCopy;
//    }
    UICollectionView * const cv = self.collectionView;
    CGPoint const contentOffset = cv.contentOffset;
    NSMutableIndexSet *missingSections = [NSMutableIndexSet indexSet];


    for (UICollectionViewLayoutAttributes *layoutAttributes in attributesInRect) {
        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
            [missingSections removeIndex:layoutAttributes.indexPath.section];
        }
    }

    [attributesInRect enumerateObjectsUsingBlock:^(JSQMessagesCollectionViewLayoutAttributes *attributesItem, NSUInteger idx, BOOL *stop) {
        if (attributesItem.representedElementCategory == UICollectionElementCategoryCell) {
            [self jsq_configureMessageCellLayoutAttributes:attributesItem];
            [missingSections addIndex:attributesItem.indexPath.section];
        }
        else {
            attributesItem.zIndex = -1;
        }
    }];

    [missingSections enumerateIndexesUsingBlock:^(NSUInteger idx, BOOL *stop) {
        NSIndexPath *indexPath = [NSIndexPath indexPathForItem:0 inSection:idx];
        UICollectionViewLayoutAttributes *layoutAttributes = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:indexPath];
        [attributesInRect addObject:layoutAttributes];
    }];

    for (UICollectionViewLayoutAttributes *layoutAttributes in attributesInRect)  {
        if ([layoutAttributes.representedElementKind isEqualToString:UICollectionElementKindSectionHeader]) {
            NSInteger section = layoutAttributes.indexPath.section;
            NSInteger numberOfItemsInSection = [cv numberOfItemsInSection:section];
            NSIndexPath *firstCellIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
            NSIndexPath *lastCellIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section];
            NSIndexPath *firstObjectIndexPath = [NSIndexPath indexPathForItem:0 inSection:section];
            NSIndexPath *lastObjectIndexPath = [NSIndexPath indexPathForItem:MAX(0, (numberOfItemsInSection - 1)) inSection:section];
            UICollectionViewLayoutAttributes *firstObjectAttrs;
            UICollectionViewLayoutAttributes *lastObjectAttrs;
            if (numberOfItemsInSection > 0) {
                firstObjectAttrs = [self layoutAttributesForItemAtIndexPath:firstObjectIndexPath];
                lastObjectAttrs = [self layoutAttributesForItemAtIndexPath:lastObjectIndexPath];

            } else {
                firstObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionHeader atIndexPath:firstObjectIndexPath];
                lastObjectAttrs = [self layoutAttributesForSupplementaryViewOfKind:UICollectionElementKindSectionFooter atIndexPath:lastObjectIndexPath];
            }
            CGFloat headerHeight = CGRectGetHeight(layoutAttributes.frame);
            CGPoint origin = layoutAttributes.frame.origin;
            origin.y = MIN(MAX(contentOffset.y + cv.contentInset.top, (CGRectGetMinY(firstObjectAttrs.frame) - headerHeight)), (CGRectGetMaxY(lastObjectAttrs.frame) - headerHeight));
            layoutAttributes.zIndex = 1024;
            layoutAttributes.frame = (CGRect) {
                .origin = origin, .size = layoutAttributes.frame.size
            };
        }
    }



    return attributesInRect;
}



Best Answer-推荐答案


我上面提供的代码是可以的。我认为导致崩溃的原因是我在 JSQMessagesViewController 子类中覆盖了 collectionView:collectionViewLayout:referenceSizeForHeaderInSection: 函数。我注释掉了该函数,而是在 JSQMessagesLoadEarlierHeaderView 中的 kJSQMessagesLoadEarlierHeaderViewHeight 常量中设置了高度。是的,我劫持了 LoadEarlierHeaderView 以显示我自己的自定义标题 View 。

现在,标题 View 固定在顶部,显示了我的自定义标题 View ,并且没有任何崩溃。

关于ios - 顶部固定有 SupplementaryView 的 JSQMessagesViewController,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/37499713/






欢迎光临 OGeek|极客世界-中国程序员成长平台 (https://ogeek.cn/) Powered by Discuz! X3.4