当前位置: 首页 > 面试题库 >

迅速的UICollectionView粘性标头

汪阳飇
2023-03-14
问题内容

我正在尝试创建一个粘性补充标题,该标题始终保持在顶部,并且不会响应滚动事件。到目前为止,我发现的解决方案仍然可以对快速滚动进行反应,并使用自定义flowLayout进行了修复,这也可能是解决我的问题的方法。

我想要这种方式的原因是该标头在其他地方使用并且应该可重用。我希望可以通过这种方式解决此问题,而不必创建单独的视图。

当我在Swift中进行此操作时,在Swift中有一个示例将是很棒的。


问题答案:

我发现的最终解决方案是:

使用此自定义流程布局可以修复此粘性标头:

class StickyHeaderCollectionViewFlowLayout: UICollectionViewFlowLayout {

    override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {

        var superAttributes: [UICollectionViewLayoutAttributes]? = super.layoutAttributesForElementsInRect(rect) as? [UICollectionViewLayoutAttributes]

        if superAttributes == nil {
            // If superAttributes couldn't cast, return
            return super.layoutAttributesForElementsInRect(rect)
        }

        let contentOffset = collectionView!.contentOffset
        var missingSections = NSMutableIndexSet()

        for layoutAttributes in superAttributes! {
            if (layoutAttributes.representedElementCategory == .Cell) {
                if let indexPath = layoutAttributes.indexPath {
                    missingSections.addIndex(layoutAttributes.indexPath.section)
                }
            }
        }

        for layoutAttributes in superAttributes! {
            if let representedElementKind = layoutAttributes.representedElementKind {
                if representedElementKind == UICollectionElementKindSectionHeader {
                    if let indexPath = layoutAttributes.indexPath {
                        missingSections.removeIndex(indexPath.section)
                    }
                }
            }
        }

        missingSections.enumerateIndexesUsingBlock { idx, stop in
            let indexPath = NSIndexPath(forItem: 0, inSection: idx)
            if let layoutAttributes = self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: indexPath) {
                superAttributes!.append(layoutAttributes)
            }
        }

        for layoutAttributes in superAttributes! {
            if let representedElementKind = layoutAttributes.representedElementKind {
                if representedElementKind == UICollectionElementKindSectionHeader {
                    let section = layoutAttributes.indexPath!.section
                    let numberOfItemsInSection = collectionView!.numberOfItemsInSection(section)

                    let firstCellIndexPath = NSIndexPath(forItem: 0, inSection: section)!
                    let lastCellIndexPath = NSIndexPath(forItem: max(0, (numberOfItemsInSection - 1)), inSection: section)!


                    let (firstCellAttributes: UICollectionViewLayoutAttributes, lastCellAttributes: UICollectionViewLayoutAttributes) = {
                        if (self.collectionView!.numberOfItemsInSection(section) > 0) {
                            return (
                                self.layoutAttributesForItemAtIndexPath(firstCellIndexPath),
                                self.layoutAttributesForItemAtIndexPath(lastCellIndexPath))
                        } else {
                            return (
                                self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionHeader, atIndexPath: firstCellIndexPath),
                                self.layoutAttributesForSupplementaryViewOfKind(UICollectionElementKindSectionFooter, atIndexPath: lastCellIndexPath))
                        }
                        }()

                    let headerHeight = CGRectGetHeight(layoutAttributes.frame)
                    var origin = layoutAttributes.frame.origin

                    origin.y = min(contentOffset.y, (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))
                    // Uncomment this line for normal behaviour:
                    // origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttributes.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttributes.frame) - headerHeight))

                    layoutAttributes.zIndex = 1024
                    layoutAttributes.frame = CGRect(origin: origin, size: layoutAttributes.frame.size)
                }
            }
        }

        return superAttributes
    }

    override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
        return true
    }

}

要创建标题像传统标题一样粘滞的布局,请更改以下行:

origin.y = min(contentOffset.y, (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight))

到这行:

origin.y = min(max(contentOffset.y, (CGRectGetMinY(firstCellAttrs.frame) - headerHeight)), (CGRectGetMaxY(lastCellAttrs.frame) - headerHeight))

希望这对其他人有用!

更新资料

更新以修复崩溃(感谢Robert Atkins!)和对Swift 1.2的一些更新。

tvOS和iOS 9

tvOS和iOS 9引入了sectionHeadersPinToVisibleBounds可以使用的属性



 类似资料:
  • 问题内容: 注:有帐目标下用一个类似的问题在这里,但我想实现它迅速。 我有一个这样迅速宣布的课程: 现在,我想快速注册一个数组:dateDisplayLabel,nameDisplayLabel。 我该如何实现? 问题答案: 使用 这是一个纯粹的Swift解决方案,但有一些限制: 局限性: 返回Objective-C对象的空数组 将不返回计算的属性,即: 如果是类的实例(相对于结构),则不会报告其

  • 问题内容: 我想要一个数字数组上的函数(或任何可加的事物的有序集合),该函数返回长度相同的数组,其中每个元素是A中所有元素的总和, 直到一个include。 例子: 我可以使用for循环或其他方式执行此操作。还有更多功能选择吗?它有点像reduce,只是它会构建一个包含所有中间值的结果数组。 更通用的是具有可以接受任何序列并提供输入序列的总运行时间的函数。 问题答案: 您正在寻找的通用组合器通常称

  • 问题内容: 迅速有没有通过声明?例如,如果我执行以下操作 案例“一”和案例“二”是否可以执行相同的代码? 问题答案: 是。您可以按照以下方式进行操作: 另外,您可以使用关键字:

  • 我正在我的flutter应用程序中实现一个DraggableScrollableSheet,并希望有一个粘性头,即只有列表视图滚动,工作表的顶部部分始终保持不变。我的小部件如下所示: 基本功能可以工作,但是,只有在拖动/滚动列表视图项时,工作表才是可拖动和可滚动的。我需要做什么更改来使列中的其他小部件也是可滚动的。我尝试了滚动和拖动小部件没有解决方案。 感谢任何帮助。

  • 问题内容: 如何迅速地建立代表? 问题答案: 它与obj-c没什么不同。首先,您必须在类声明中指定协议,如下所示: 该实现将如下所示: 当然,您必须设置委托。例如:

  • 问题内容: 我已经设置了swift项目来使用sqlite。有时,插入时实际上并没有插入正确(或全部)的值。我知道,因为我重新启动了该应用程序,并且当我再次输入时,输入是随机错误(未插入内容)或为零。但有时是正确的。 这是我设置的位置,是的,插入之前数据正确。 您可以在中间看到注释掉的println,如果没有注释掉,则itemName有时会成为该字符串的一部分。 问题答案: 我有同样的问题。我找到了