使用自定义FlowLayout(Swift)时将HeaderView添加到CollectionView

时间:2016-03-12 03:55:50

标签: ios swift uicollectionview

我已经实现了一个自定义FlowLayout子类,这显然阻止我通过headerView添加storyboard(复选框已消失)。有没有其他方法可以使用storyboards

关于如何以编程方式添加headerView有一些答案,但它们位于objective-C,如何使用Swift添加?

以下不会产生标题视图,我无法弄清楚为什么?

 CollectionViewController {


    override func viewDidLoad() {
        super.viewDidLoad()

            // Setup Header
        self.collectionView!.registerClass(PinHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)

}
     override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
                //1
                switch kind {
                    //2
                case UICollectionElementKindSectionHeader:
                    //3
                    let headerView = collectionView.dequeueReusableSupplementaryViewOfKind(kind,withReuseIdentifier: "PinHeaderView",
                        forIndexPath: indexPath)
                        as! PinHeaderView
                    headerView.pinHeaderLabel.text = boardName
                    return headerView
                default:
                    //4
                    fatalError("Unexpected element kind")
                }
        }
    }

class PinHeaderView: UICollectionReusableView {


    @IBOutlet weak var pinHeaderLabel: UILabel!



}

我的布局课程:

import UIKit
protocol PinterestLayoutDelegate {
    // 1. Method to ask the delegate for the height of the image
    func collectionView(collectionView:UICollectionView, heightForPhotoAtIndexPath indexPath:NSIndexPath , withWidth:CGFloat) -> CGFloat
    // 2. Method to ask the delegate for the height of the annotation text
    func collectionView(collectionView: UICollectionView, heightForAnnotationAtIndexPath indexPath: NSIndexPath, withWidth width: CGFloat) -> CGFloat

    func columnsForDevice() -> Int

}

class PinterestLayoutAttributes:UICollectionViewLayoutAttributes {

    // 1. Custom attribute
    var photoHeight: CGFloat = 0.0
    var headerHeight: CGFloat = 0.0

    // 2. Override copyWithZone to conform to NSCopying protocol
    override func copyWithZone(zone: NSZone) -> AnyObject {
        let copy = super.copyWithZone(zone) as! PinterestLayoutAttributes
        copy.photoHeight = photoHeight
        return copy
    }

    // 3. Override isEqual
    override func isEqual(object: AnyObject?) -> Bool {
        if let attributtes = object as? PinterestLayoutAttributes {
            if( attributtes.photoHeight == photoHeight  ) {
                return super.isEqual(object)
            }
        }
        return false
    }
}


class PinterestLayout: UICollectionViewLayout {
    //1. Pinterest Layout Delegate
    var delegate:PinterestLayoutDelegate!

    //2. Configurable properties
    //moved numberOfColumns
    var cellPadding: CGFloat = 6.0

    //3. Array to keep a cache of attributes.
    private var cache = [PinterestLayoutAttributes]()

    //4. Content height and size
    private var contentHeight:CGFloat  = 0.0
    private var contentWidth: CGFloat {
        let insets = collectionView!.contentInset
        return CGRectGetWidth(collectionView!.bounds) - (insets.left + insets.right)
    }

    override class func layoutAttributesClass() -> AnyClass {

        return PinterestLayoutAttributes.self


    }

    override func prepareLayout() {
        // 1. Only calculate once
        //if cache.isEmpty {

            // 2. Pre-Calculates the X Offset for every column and adds an array to increment the currently max Y Offset for each column
            let numberOfColumns = delegate.columnsForDevice()
            let columnWidth = contentWidth / CGFloat(numberOfColumns)
            var xOffset = [CGFloat]()
            for column in 0 ..< numberOfColumns {
                xOffset.append(CGFloat(column) * columnWidth )
            }
            var column = 0
            var yOffset = [CGFloat](count: numberOfColumns, repeatedValue: 0)

            // 3. Iterates through the list of items in the first section
            for item in 0 ..< collectionView!.numberOfItemsInSection(0) {

                let indexPath = NSIndexPath(forItem: item, inSection: 0)

                // 4. Asks the delegate for the height of the picture and the annotation and calculates the cell frame.
                let width = columnWidth - cellPadding*2
                let photoHeight = delegate.collectionView(collectionView!, heightForPhotoAtIndexPath: indexPath , withWidth:width)
                let annotationHeight = delegate.collectionView(collectionView!, heightForAnnotationAtIndexPath: indexPath, withWidth: width)
                let height = cellPadding +  photoHeight + annotationHeight + cellPadding
                let frame = CGRect(x: xOffset[column], y: yOffset[column], width: columnWidth, height: height)
                let insetFrame = CGRectInset(frame, cellPadding, cellPadding)

                // 5. Creates an UICollectionViewLayoutItem with the frame and add it to the cache
                let attributes = PinterestLayoutAttributes(forCellWithIndexPath: indexPath)
                attributes.photoHeight = photoHeight
                attributes.frame = insetFrame
                cache.append(attributes)

                // 6. Updates the collection view content height
                contentHeight = max(contentHeight, CGRectGetMaxY(frame))
                yOffset[column] = yOffset[column] + height

                column = column >= (numberOfColumns - 1) ? 0 : ++column
            }
        //}
    }


    override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {

       let attributes = PinterestLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath)
    attributes.headerHeight = 100.0
    attributes.frame = (self.collectionView?.frame)!
    return attributes



    }


    override func collectionViewContentSize() -> CGSize {
        return CGSize(width: contentWidth, height: contentHeight)
    }

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

        var layoutAttributes = [UICollectionViewLayoutAttributes]()

        // Loop through the cache and look for items in the rect
        for attributes  in cache {
            if CGRectIntersectsRect(attributes.frame, rect ) {
                layoutAttributes.append(attributes)
            }
        }
        return layoutAttributes
    }
}

3 个答案:

答案 0 :(得分:3)

您可以在故事板中添加标题视图,拖动&#34; Collection Reusable View&#34;并将其放在collectionView中,然后在故事板中设置其classidentifier。或者,您可以按照代码中所示以编程方式注册自定义标头类。

self.collectionView!.registerClass(PinHeaderView.self, forSupplementaryViewOfKind:UICollectionElementKindSectionHeader, withReuseIdentifier: headerIdentifier)

viewForSupplementaryElementOfKind委托方法不完整,案例UICollectionElementKindSectionFooter未得到处理,对页脚视图执行与标题视图相同的操作。如果您没有看到它,请将标题视图的borderWidth图层设置为大于0的值,它可能会显示出来。

答案 1 :(得分:1)

为什么在方法PinterestLayoutAttributes(forCellWithIndexPath: indexPath)中使用layoutAttributesForSupplementaryViewOfKind

您应该使用PinterestLayoutAttributes(forSupplementaryViewOfKind elementKind: String, withIndexPath indexPath: NSIndexPath)

您正在为单元格生成布局属性,而不是为视图添加。因此,您的布局属性不包含正确的类别类型和视图类型。这就是为什么即使你为了补充视图注册类 - 集合视图也没有为它的实例布局。

答案 2 :(得分:1)

prepareForLayout函数内为标题添加一个attributes对象。您可以将其附加到缓存中,如下所示:

        // Add Attributes for section header
        let headerAtrributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionElementKindSectionHeader, with: IndexPath(item: 0, section: 0))
        headerAtrributes.frame = CGRect(x: 0, y: 0, width: self.collectionView!.bounds.size.width, height: 50)
        cache.append(headerAtrributes)