klundberg / KRLCollectionViewGridLayout

A UICollectionViewLayout that specifies item size and location by number of columns.
MIT License
164 stars 23 forks source link

Update swift version #10

Closed NikKovIos closed 6 years ago

NikKovIos commented 6 years ago

Hi there, i'm trying to use the swift version from Swift branch, but it's outdated. Here is my updates to Swift 4, but there are no properties like headerReferenceLength. Could you please update it?

//
//  KRLCollectionViewGridLayout.swift
//  KRLCollectionViewGridLayoutDemo
//
//  Created by Kevin Lundberg on 7/13/14.
//  Copyright (c) 2014 Lundbergsoft. All rights reserved.
//

import CoreGraphics
import UIKit

class KRLCollectionViewGridLayout : UICollectionViewLayout {
    var scrollDirection: UICollectionViewScrollDirection = .vertical {
        didSet {
            if scrollDirection != oldValue {
                self.invalidateLayout()
            }
        }
    }
    var sectionInset: UIEdgeInsets = .zero {
        didSet {
            if !UIEdgeInsetsEqualToEdgeInsets(sectionInset, oldValue) {
                self.invalidateLayout()
            }
        }
    }
    var interitemSpacing: CGFloat = 10 {
        didSet {
            if interitemSpacing != oldValue {
                self.invalidateLayout()
            }
        }
    }
    var lineSpacing: CGFloat = 10 {
        didSet {
            if lineSpacing != oldValue {
                self.invalidateLayout()
            }
        }
    }
    var numberOfItemsPerLine: Int = 1 {
        didSet {
            if numberOfItemsPerLine != oldValue {
                self.invalidateLayout()
            }
        }
    }
    var aspectRatio: CGFloat = 1 {
        didSet {
            if aspectRatio != oldValue {
                self.invalidateLayout()
            }
        }
    }

    var collectionViewContentLength: CGFloat = 0;
    var attributesBySection = [[UICollectionViewLayoutAttributes]]()

    override func prepare() {
        self.collectionViewContentLength = self.contentLength()
        self.calculateLayoutAttributes()
    }

    func contentLength() -> CGFloat {
        var contentLength: CGFloat = 0.0

        for section in 0..<(self.collectionView?.numberOfSections ?? 0) {
            contentLength += self.contentLength(section)
        }

        return contentLength;
    }

    var cellSize: CGSize {
        let cellLength = self.usableSpace / CGFloat(self.numberOfItemsPerLine)

        if self.scrollDirection == .vertical {
            return CGSize(
                width: cellLength,
                height: cellLength * CGFloat(1.0 / self.aspectRatio)
            )
        } else {
            return CGSize(
                width: cellLength * CGFloat(self.aspectRatio),
                height: cellLength
            )
        }
    }

    var usableSpace: CGFloat {
        let collectionViewLength = (self.scrollDirection == .vertical
            ? self.collectionViewContentSize.width
            : self.collectionViewContentSize.height)

        return collectionViewLength - self.insetLength - self.totalItemSpacing
    }

    var insetLength: CGFloat {
        if self.scrollDirection == .vertical {
            return self.sectionInset.top + self.sectionInset.bottom
        } else {
            return self.sectionInset.left + self.sectionInset.right
        }
    }

    var totalItemSpacing: CGFloat {
        return CGFloat(self.numberOfItemsPerLine - 1) * self.interitemSpacing
    }

    func contentLength(_ section: Int) -> CGFloat {
        return self.totalLineSpacing(section) + self.insetLength + self.totalRowLength(section)
    }

    func totalLineSpacing(_ section: Int) -> CGFloat {
        return CGFloat(self.rowsInSection(section) - 1) * self.lineSpacing;
    }

    func totalRowLength(_ section: Int) -> CGFloat {
        if self.scrollDirection == .vertical {
            return self.rowsInSection(section) * self.cellSize.height
        } else {
            return self.rowsInSection(section) * self.cellSize.width
        }
    }

    func rowsInSection(_ section: Int) -> CGFloat {
        let itemsInSection = self.collectionView?.numberOfItems(inSection: section) ?? 0
        return CGFloat((itemsInSection / self.numberOfItemsPerLine) + (itemsInSection % self.numberOfItemsPerLine > 0 ? 1 : 0))
    }

    func calculateLayoutAttributes() {
        self.attributesBySection = (0..<(self.collectionView?.numberOfSections ?? 0)).map(self.layoutAttributesForItemsInSection)
    }

    func layoutAttributesForItemsInSection(section: Int) -> [UICollectionViewLayoutAttributes] {
        return self.indexPathsInSection(section: section).map { self.layoutAttributesForCellAtIndexPath($0) }
    }

    func indexPathsInSection(section: Int) -> [IndexPath] {
        return (0..<self.collectionView!.numberOfItems(inSection: section)).map {
            IndexPath(item: $0, section: section)
        }
    }

    func layoutAttributesForCellAtIndexPath(_ indexPath: IndexPath) -> UICollectionViewLayoutAttributes {
        let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
        attributes.frame = self.frameForItemAtIndexPath(indexPath)
        return attributes
    }

    func frameForItemAtIndexPath(_ indexPath: IndexPath) -> CGRect {
        let cellSize = self.cellSize
        let rowOfItem = CGFloat(indexPath.item / self.numberOfItemsPerLine)
        let locationInRowOfItem = CGFloat(indexPath.item % self.numberOfItemsPerLine)

        var origin = CGPoint()

        let sectionStart = self.startOfSection(section: indexPath.section)
        if self.scrollDirection == .vertical {
            origin.x = self.sectionInset.left + (locationInRowOfItem * cellSize.width) + (self.interitemSpacing * locationInRowOfItem)
            origin.y = sectionStart + self.sectionInset.top + (rowOfItem * cellSize.height) + (self.lineSpacing * rowOfItem)
        } else {
            origin.x = sectionStart + self.sectionInset.left + (rowOfItem * cellSize.width) + (self.lineSpacing * rowOfItem)
            origin.y = self.sectionInset.top + (locationInRowOfItem * cellSize.height) + (self.interitemSpacing * locationInRowOfItem)
        }
        return CGRect(origin: origin, size: cellSize)
    }

    func startOfSection(section: Int) -> CGFloat {
        return (0..<section).map(self.contentLength).reduce(0, +)
    }

    override var collectionViewContentSize: CGSize {
        if self.scrollDirection == .vertical {
            return CGSize(width: self.collectionView!.bounds.size.width, height: self.collectionViewContentLength)
        } else {
            return CGSize(width: self.collectionViewContentLength, height: self.collectionView!.bounds.size.height)
        }
    }

    override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
        var visibleAttributes = [UICollectionViewLayoutAttributes]()
        for sectionAttributes in self.attributesBySection {
            visibleAttributes += sectionAttributes.filter { rect.intersects($0.frame) }
        }
        return visibleAttributes
    }

    override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
        return self.attributesBySection[indexPath.section][indexPath.item]
    }

    override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
        return newBounds.size != self.collectionView!.bounds.size
    }
}
klundberg commented 6 years ago

Hi!

I forgot I had a swift branch out there still. If I recall, this branch was just to play around with swift and to see what the library would look like if it were translated. I have no plans to convert the library fully to swift though, since you can use the obj-c code from swift as is with no major changes. If you import the latest version of the library with cocoa pods or Carthage does it not let you do what you want?

On Jul 23, 2018, at 10:23 AM, Nik Kov notifications@github.com wrote:

Hi there, i'm trying to use the swift version from Swift branch, but it's outdated. Here is my updates to Swift 4, but there are no properties like headerReferenceLength. Could you please update it?

// // KRLCollectionViewGridLayout.swift // KRLCollectionViewGridLayoutDemo // // Created by Kevin Lundberg on 7/13/14. // Copyright (c) 2014 Lundbergsoft. All rights reserved. //

import CoreGraphics import UIKit

class KRLCollectionViewGridLayout : UICollectionViewLayout { var scrollDirection: UICollectionViewScrollDirection = .vertical { didSet { if scrollDirection != oldValue { self.invalidateLayout() } } } var sectionInset: UIEdgeInsets = .zero { didSet { if !UIEdgeInsetsEqualToEdgeInsets(sectionInset, oldValue) { self.invalidateLayout() } } } var interitemSpacing: CGFloat = 10 { didSet { if interitemSpacing != oldValue { self.invalidateLayout() } } } var lineSpacing: CGFloat = 10 { didSet { if lineSpacing != oldValue { self.invalidateLayout() } } } var numberOfItemsPerLine: Int = 1 { didSet { if numberOfItemsPerLine != oldValue { self.invalidateLayout() } } } var aspectRatio: CGFloat = 1 { didSet { if aspectRatio != oldValue { self.invalidateLayout() } } }

var collectionViewContentLength: CGFloat = 0;
var attributesBySection = [[UICollectionViewLayoutAttributes]]()

override func prepare() {
    self.collectionViewContentLength = self.contentLength()
    self.calculateLayoutAttributes()
}

func contentLength() -> CGFloat {
    var contentLength: CGFloat = 0.0

    for section in 0..<(self.collectionView?.numberOfSections ?? 0) {
        contentLength += self.contentLength(section)
    }

    return contentLength;
}

var cellSize: CGSize {
    let cellLength = self.usableSpace / CGFloat(self.numberOfItemsPerLine)

    if self.scrollDirection == .vertical {
        return CGSize(
            width: cellLength,
            height: cellLength * CGFloat(1.0 / self.aspectRatio)
        )
    } else {
        return CGSize(
            width: cellLength * CGFloat(self.aspectRatio),
            height: cellLength
        )
    }
}

var usableSpace: CGFloat {
    let collectionViewLength = (self.scrollDirection == .vertical
        ? self.collectionViewContentSize.width
        : self.collectionViewContentSize.height)

    return collectionViewLength - self.insetLength - self.totalItemSpacing
}

var insetLength: CGFloat {
    if self.scrollDirection == .vertical {
        return self.sectionInset.top + self.sectionInset.bottom
    } else {
        return self.sectionInset.left + self.sectionInset.right
    }
}

var totalItemSpacing: CGFloat {
    return CGFloat(self.numberOfItemsPerLine - 1) * self.interitemSpacing
}

func contentLength(_ section: Int) -> CGFloat {
    return self.totalLineSpacing(section) + self.insetLength + self.totalRowLength(section)
}

func totalLineSpacing(_ section: Int) -> CGFloat {
    return CGFloat(self.rowsInSection(section) - 1) * self.lineSpacing;
}

func totalRowLength(_ section: Int) -> CGFloat {
    if self.scrollDirection == .vertical {
        return self.rowsInSection(section) * self.cellSize.height
    } else {
        return self.rowsInSection(section) * self.cellSize.width
    }
}

func rowsInSection(_ section: Int) -> CGFloat {
    let itemsInSection = self.collectionView?.numberOfItems(inSection: section) ?? 0
    return CGFloat((itemsInSection / self.numberOfItemsPerLine) + (itemsInSection % self.numberOfItemsPerLine > 0 ? 1 : 0))
}

func calculateLayoutAttributes() {
    self.attributesBySection = (0..<(self.collectionView?.numberOfSections ?? 0)).map(self.layoutAttributesForItemsInSection)
}

func layoutAttributesForItemsInSection(section: Int) -> [UICollectionViewLayoutAttributes] {
    return self.indexPathsInSection(section: section).map { self.layoutAttributesForCellAtIndexPath($0) }
}

func indexPathsInSection(section: Int) -> [IndexPath] {
    return (0..<self.collectionView!.numberOfItems(inSection: section)).map {
        IndexPath(item: $0, section: section)
    }
}

func layoutAttributesForCellAtIndexPath(_ indexPath: IndexPath) -> UICollectionViewLayoutAttributes {
    let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
    attributes.frame = self.frameForItemAtIndexPath(indexPath)
    return attributes
}

func frameForItemAtIndexPath(_ indexPath: IndexPath) -> CGRect {
    let cellSize = self.cellSize
    let rowOfItem = CGFloat(indexPath.item / self.numberOfItemsPerLine)
    let locationInRowOfItem = CGFloat(indexPath.item % self.numberOfItemsPerLine)

    var origin = CGPoint()

    let sectionStart = self.startOfSection(section: indexPath.section)
    if self.scrollDirection == .vertical {
        origin.x = self.sectionInset.left + (locationInRowOfItem * cellSize.width) + (self.interitemSpacing * locationInRowOfItem)
        origin.y = sectionStart + self.sectionInset.top + (rowOfItem * cellSize.height) + (self.lineSpacing * rowOfItem)
    } else {
        origin.x = sectionStart + self.sectionInset.left + (rowOfItem * cellSize.width) + (self.lineSpacing * rowOfItem)
        origin.y = self.sectionInset.top + (locationInRowOfItem * cellSize.height) + (self.interitemSpacing * locationInRowOfItem)
    }
    return CGRect(origin: origin, size: cellSize)
}

func startOfSection(section: Int) -> CGFloat {
    return (0..<section).map(self.contentLength).reduce(0, +)
}

override var collectionViewContentSize: CGSize {
    if self.scrollDirection == .vertical {
        return CGSize(width: self.collectionView!.bounds.size.width, height: self.collectionViewContentLength)
    } else {
        return CGSize(width: self.collectionViewContentLength, height: self.collectionView!.bounds.size.height)
    }
}

override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
    var visibleAttributes = [UICollectionViewLayoutAttributes]()
    for sectionAttributes in self.attributesBySection {
        visibleAttributes += sectionAttributes.filter { rect.intersects($0.frame) }
    }
    return visibleAttributes
}

override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
    return self.attributesBySection[indexPath.section][indexPath.item]
}

override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
    return newBounds.size != self.collectionView!.bounds.size
}

} — You are receiving this because you are subscribed to this thread. Reply to this email directly, view it on GitHub https://github.com/klundberg/KRLCollectionViewGridLayout/issues/10, or mute the thread https://github.com/notifications/unsubscribe-auth/AA0-OpeQrMH3JG9zvDlLhlbQTXD3vwCbks5uJdxigaJpZM4VbFp_.

NikKovIos commented 6 years ago

Yes, it does. I just needed to import files manually, but now use bridging header. Thx for reply :)