diff --git a/CHTCollectionViewWaterfallLayout.podspec b/CHTCollectionViewWaterfallLayout.podspec index 7dc3ec5..829e125 100644 --- a/CHTCollectionViewWaterfallLayout.podspec +++ b/CHTCollectionViewWaterfallLayout.podspec @@ -19,6 +19,7 @@ Pod::Spec.new do |s| ss.source_files = '*.{h,m}' end + s.swift_version = '4.2' s.subspec 'Swift' do |ss| ss.ios.deployment_target = '8.0' ss.source_files = '*.swift' diff --git a/CHTCollectionViewWaterfallLayout.swift b/CHTCollectionViewWaterfallLayout.swift index fbc0342..635eee4 100755 --- a/CHTCollectionViewWaterfallLayout.swift +++ b/CHTCollectionViewWaterfallLayout.swift @@ -6,9 +6,9 @@ // Copyright (c) 2014 Nicholas Tau. All rights reserved. // -import Foundation import UIKit -fileprivate func < (lhs: T?, rhs: T?) -> Bool { + +private func < (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l < r @@ -19,7 +19,7 @@ fileprivate func < (lhs: T?, rhs: T?) -> Bool { } } -fileprivate func > (lhs: T?, rhs: T?) -> Bool { +private func > (lhs: T?, rhs: T?) -> Bool { switch (lhs, rhs) { case let (l?, r?): return l > r @@ -30,295 +30,308 @@ fileprivate func > (lhs: T?, rhs: T?) -> Bool { @objc public protocol CHTCollectionViewDelegateWaterfallLayout: UICollectionViewDelegate { + func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + sizeForItemAt indexPath: IndexPath) -> CGSize + + @objc optional func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + heightForHeaderIn section: Int) -> CGFloat + + @objc optional func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + heightForFooterIn section: Int) -> CGFloat + + @objc optional func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + insetsFor section: Int) -> UIEdgeInsets + + @objc optional func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + minimumInteritemSpacingFor section: Int) -> CGFloat + + @objc optional func collectionView(_ collectionView: UICollectionView, + layout collectionViewLayout: UICollectionViewLayout, + columnCountFor section: Int) -> Int - func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, + @available(*, unavailable, renamed: "collectionView(_:layout:sizeForItemAt:)") + @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: IndexPath) -> CGSize + @available(*, unavailable, renamed: "collectionView(_:layout:heightForHeaderIn:)") @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, heightForHeaderInSection section: Int) -> CGFloat + @available(*, unavailable, renamed: "collectionView(_:layout:heightForFooterIn:)") @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, heightForFooterInSection section: Int) -> CGFloat + @available(*, unavailable, renamed: "collectionView(_:layout:insetsFor:)") @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, insetForSectionAtIndex section: Int) -> UIEdgeInsets + @available(*, unavailable, renamed: "collectionView(_:layout:minimumInteritemSpacingFor:)") @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, minimumInteritemSpacingForSectionAtIndex section: Int) -> CGFloat + @available(*, unavailable, renamed: "collectionView(_:layout:columnCountFor:)") @objc optional func collectionView (_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, columnCountForSection section: Int) -> Int } -public enum CHTCollectionViewWaterfallLayoutItemRenderDirection: Int { - case chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst - case chtCollectionViewWaterfallLayoutItemRenderDirectionLeftToRight - case chtCollectionViewWaterfallLayoutItemRenderDirectionRightToLeft +@available(*, unavailable, renamed: "CHTCollectionViewWaterfallLayout.ItemRenderDirection") +public enum CHTCollectionViewWaterfallLayoutItemRenderDirection { } + +public extension CHTCollectionViewWaterfallLayout.ItemRenderDirection { + @available(*, unavailable, renamed: "shortestFirst") + static let chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst = 0 + @available(*, unavailable, renamed: "leftToRight") + static let chtCollectionViewWaterfallLayoutItemRenderDirectionLeftToRight = 1 + @available(*, unavailable, renamed: "rightToLeft") + static let chtCollectionViewWaterfallLayoutItemRenderDirectionRightToLeft = 2 +} + +extension CHTCollectionViewWaterfallLayout { + public enum ItemRenderDirection: Int { + case shortestFirst + case leftToRight + case rightToLeft + } + + public enum SectionInsetReference { + case fromContentInset + case fromLayoutMargins + @available(iOS 11, *) + case fromSafeArea + } } -public let CHTCollectionElementKindSectionHeader = "CHTCollectionElementKindSectionHeader" -public let CHTCollectionElementKindSectionFooter = "CHTCollectionElementKindSectionFooter" +@available(*, unavailable, renamed: "UICollectionView.elementKindSectionHeader") +public let CHTCollectionElementKindSectionHeader = "CHTCollectionElementKindSectionHeader" +@available(*, unavailable, renamed: "UICollectionView.elementKindSectionFooter") +public let CHTCollectionElementKindSectionFooter = "CHTCollectionElementKindSectionFooter" public class CHTCollectionViewWaterfallLayout: UICollectionViewLayout { - public var columnCount: Int { + public var columnCount: Int = 2 { didSet { invalidateLayout() - }} + } + } - public var minimumColumnSpacing: CGFloat { + public var minimumColumnSpacing: CGFloat = 10 { didSet { invalidateLayout() - }} + } + } - public var minimumInteritemSpacing: CGFloat { + public var minimumInteritemSpacing: CGFloat = 10 { didSet { invalidateLayout() - }} + } + } - public var headerHeight: CGFloat { + public var headerHeight: CGFloat = 0 { didSet { invalidateLayout() - }} + } + } - public var footerHeight: CGFloat { + public var footerHeight: CGFloat = 0 { didSet { invalidateLayout() - }} + } + } - public var sectionInset: UIEdgeInsets { + public var sectionInset: UIEdgeInsets = .zero { didSet { invalidateLayout() - }} - + } + } - public var itemRenderDirection: CHTCollectionViewWaterfallLayoutItemRenderDirection { + public var itemRenderDirection: ItemRenderDirection = .shortestFirst { didSet { invalidateLayout() } } + public var sectionInsetReference: SectionInsetReference = .fromContentInset { + didSet { + invalidateLayout() + } + } - // private property and method above. - public weak var delegate: CHTCollectionViewDelegateWaterfallLayout? { + public var delegate: CHTCollectionViewDelegateWaterfallLayout? { get { - return self.collectionView!.delegate as? CHTCollectionViewDelegateWaterfallLayout + return collectionView!.delegate as? CHTCollectionViewDelegateWaterfallLayout } } - public var columnHeights: [[CGFloat]] - public var sectionItemAttributes: [[UICollectionViewLayoutAttributes]] - public var allItemAttributes: [UICollectionViewLayoutAttributes] - public var headersAttributes: [Int: UICollectionViewLayoutAttributes] - public var footersAttributes: [Int: UICollectionViewLayoutAttributes] - public var unionRects: [NSValue] - public let unionSize = 20 - - override public init() { - self.headerHeight = 0.0 - self.footerHeight = 0.0 - self.columnCount = 2 - self.minimumInteritemSpacing = 10 - self.minimumColumnSpacing = 10 - self.sectionInset = UIEdgeInsets.zero - self.itemRenderDirection = - CHTCollectionViewWaterfallLayoutItemRenderDirection.chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst - headersAttributes = [:] - footersAttributes = [:] - unionRects = [] - columnHeights = [] - allItemAttributes = [] - sectionItemAttributes = [] + private var columnHeights: [[CGFloat]] = [] + private var sectionItemAttributes: [[UICollectionViewLayoutAttributes]] = [] + private var allItemAttributes: [UICollectionViewLayoutAttributes] = [] + private var headersAttributes: [Int: UICollectionViewLayoutAttributes] = [:] + private var footersAttributes: [Int: UICollectionViewLayoutAttributes] = [:] + private var unionRects: [CGRect] = [] + private let unionSize = 20 - super.init() + private func columnCount(forSection section: Int) -> Int { + return delegate?.collectionView?(collectionView!, layout: self, columnCountFor: section) ?? columnCount } - required public init?(coder aDecoder: NSCoder) { - fatalError("init(coder:) has not been implemented") + private var collectionViewContentWidth: CGFloat { + let insets: UIEdgeInsets + switch sectionInsetReference { + case .fromContentInset: + insets = collectionView!.contentInset + case .fromSafeArea: + if #available(iOS 11.0, *) { + insets = collectionView!.safeAreaInsets + } else { + insets = .zero + } + case .fromLayoutMargins: + insets = collectionView!.layoutMargins + } + return collectionView!.bounds.size.width - insets.left - insets.right } - public func columnCountForSection (_ section: Int) -> Int { - if let columnCount = self.delegate?.collectionView?(self.collectionView!, layout: self, columnCountForSection: section) { - return columnCount - } else { - return self.columnCount - } + private func collectionViewContentWidth(ofSection section: Int) -> CGFloat { + let insets = delegate?.collectionView?(collectionView!, layout: self, insetsFor: section) ?? sectionInset + return collectionViewContentWidth - insets.left - insets.right + } + + @available(*, unavailable, renamed: "itemWidth(inSection:)") + public func itemWidthInSectionAtIndex(_ section: Int) -> CGFloat { + return itemWidth(inSection: section) } - public func itemWidthInSectionAtIndex (_ section: Int) -> CGFloat { - var insets: UIEdgeInsets - if let sectionInsets = self.delegate?.collectionView?(self.collectionView!, layout: self, insetForSectionAtIndex: section) { - insets = sectionInsets - } else { - insets = self.sectionInset - } - let width: CGFloat = self.collectionView!.bounds.size.width - insets.left - insets.right - let columnCount = self.columnCountForSection(section) - let spaceColumCount: CGFloat = CGFloat(columnCount - 1) - return floor((width - (spaceColumCount * self.minimumColumnSpacing)) / CGFloat(columnCount)) + public func itemWidth(inSection section: Int) -> CGFloat { + let columnCount = self.columnCount(forSection: section) + let spaceColumCount = CGFloat(columnCount - 1) + let width = collectionViewContentWidth(ofSection: section) + return floor((width - (spaceColumCount * minimumColumnSpacing)) / CGFloat(columnCount)) } override public func prepare() { super.prepare() - let numberOfSections = self.collectionView!.numberOfSections + let numberOfSections = collectionView!.numberOfSections if numberOfSections == 0 { return } - self.headersAttributes = [:] - self.footersAttributes = [:] - self.unionRects = [] - self.columnHeights = [] - self.allItemAttributes = [] - self.sectionItemAttributes = [] - - for section in 0 ..< numberOfSections { - let columnCount = self.columnCountForSection(section) - var sectionColumnHeights: [CGFloat] = [] - for idx in 0 ..< columnCount { - sectionColumnHeights.append(CGFloat(idx)) - } - self.columnHeights.append(sectionColumnHeights) + headersAttributes = [:] + footersAttributes = [:] + unionRects = [] + allItemAttributes = [] + sectionItemAttributes = [] + columnHeights = (0 ..< numberOfSections).map { section in + let columnCount = self.columnCount(forSection: section) + let sectionColumnHeights = (0 ..< columnCount).map { CGFloat($0) } + return sectionColumnHeights } var top: CGFloat = 0.0 var attributes = UICollectionViewLayoutAttributes() for section in 0 ..< numberOfSections { - /* - * 1. Get section-specific metrics (minimumInteritemSpacing, sectionInset) - */ - var minimumInteritemSpacing: CGFloat - if let miniumSpaceing = self.delegate?.collectionView?(self.collectionView!, layout: self, minimumInteritemSpacingForSectionAtIndex: section) { - minimumInteritemSpacing = miniumSpaceing - } else { - minimumInteritemSpacing = self.minimumColumnSpacing - } - - var sectionInsets: UIEdgeInsets - if let insets = self.delegate?.collectionView?(self.collectionView!, layout: self, insetForSectionAtIndex: section) { - sectionInsets = insets - } else { - sectionInsets = self.sectionInset - } - - let width = self.collectionView!.bounds.size.width - sectionInsets.left - sectionInsets.right - let columnCount = self.columnCountForSection(section) - let spaceColumCount = CGFloat(columnCount - 1) - let itemWidth = floor((width - (spaceColumCount * self.minimumColumnSpacing)) / CGFloat(columnCount)) - - /* - * 2. Section header - */ - var heightHeader: CGFloat - if let height = self.delegate?.collectionView?(self.collectionView!, layout: self, heightForHeaderInSection: section) { - heightHeader = height - } else { - heightHeader = self.headerHeight - } - + // MARK: 1. Get section-specific metrics (minimumInteritemSpacing, sectionInset) + let minimumInteritemSpacing = delegate?.collectionView?(collectionView!, layout: self, minimumInteritemSpacingFor: section) + ?? self.minimumInteritemSpacing + let sectionInsets = delegate?.collectionView?(collectionView!, layout: self, insetsFor: section) ?? self.sectionInset + let columnCount = columnHeights[section].count + let itemWidth = self.itemWidth(inSection: section) + + // MARK: 2. Section header + let heightHeader = delegate?.collectionView?(collectionView!, layout: self, heightForHeaderIn: section) + ?? self.headerHeight if heightHeader > 0 { - attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: CHTCollectionElementKindSectionHeader, with: IndexPath(row: 0, section: section)) - attributes.frame = CGRect(x: 0, y: top, width: self.collectionView!.bounds.size.width, height: heightHeader) - self.headersAttributes[section] = attributes - self.allItemAttributes.append(attributes) + attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionView.elementKindSectionHeader, with: IndexPath(row: 0, section: section)) + attributes.frame = CGRect(x: 0, y: top, width: collectionView!.bounds.size.width, height: heightHeader) + headersAttributes[section] = attributes + allItemAttributes.append(attributes) top = attributes.frame.maxY } top += sectionInsets.top - for idx in 0 ..< columnCount { - self.columnHeights[section][idx]=top - } + columnHeights[section] = [CGFloat](repeating: top, count: columnCount) - /* - * 3. Section items - */ - let itemCount = self.collectionView!.numberOfItems(inSection: section) + // MARK: 3. Section items + let itemCount = collectionView!.numberOfItems(inSection: section) var itemAttributes: [UICollectionViewLayoutAttributes] = [] // Item will be put into shortest column. for idx in 0 ..< itemCount { let indexPath = IndexPath(item: idx, section: section) - let columnIndex = self.nextColumnIndexForItem(idx, section: section) - let xOffset = sectionInsets.left + (itemWidth + self.minimumColumnSpacing) * CGFloat(columnIndex) + let columnIndex = nextColumnIndexForItem(idx, inSection: section) + let xOffset = sectionInsets.left + (itemWidth + minimumColumnSpacing) * CGFloat(columnIndex) - let yOffset = ((self.columnHeights[section] as AnyObject).object (at: columnIndex) as AnyObject).doubleValue - let itemSize = self.delegate?.collectionView(self.collectionView!, layout: self, sizeForItemAtIndexPath: indexPath) + let yOffset = columnHeights[section][columnIndex] var itemHeight: CGFloat = 0.0 - if itemSize?.height > 0 && itemSize?.width > 0 { - itemHeight = floor(itemSize!.height * itemWidth / itemSize!.width) + if let itemSize = delegate?.collectionView(collectionView!, layout: self, sizeForItemAt: indexPath), + itemSize.height > 0 { + itemHeight = itemSize.height + if itemSize.width > 0 { + itemHeight = floor(itemHeight * itemWidth / itemSize.width) + } // else use default item width based on other parameters } attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath) - attributes.frame = CGRect(x: xOffset, y: CGFloat(yOffset!), width: itemWidth, height: itemHeight) + attributes.frame = CGRect(x: xOffset, y: yOffset, width: itemWidth, height: itemHeight) itemAttributes.append(attributes) - self.allItemAttributes.append(attributes) - - self.columnHeights[section][columnIndex] = attributes.frame.maxY + minimumInteritemSpacing - + allItemAttributes.append(attributes) + columnHeights[section][columnIndex] = attributes.frame.maxY + minimumInteritemSpacing } - self.sectionItemAttributes.append(itemAttributes) + sectionItemAttributes.append(itemAttributes) - /* - * 4. Section footer - */ - var footerHeight: CGFloat = 0.0 - let columnIndex = self.longestColumnIndexInSection(section) - top = self.columnHeights[section][columnIndex] - minimumInteritemSpacing + sectionInsets.bottom - - if let height = self.delegate?.collectionView?(self.collectionView!, layout: self, heightForFooterInSection: section) { - footerHeight = height - } else { - footerHeight = self.footerHeight - } + // MARK: 4. Section footer + let columnIndex = longestColumnIndex(inSection: section) + top = columnHeights[section][columnIndex] - minimumInteritemSpacing + sectionInsets.bottom + let footerHeight = delegate?.collectionView?(collectionView!, layout: self, heightForFooterIn: section) ?? self.footerHeight if footerHeight > 0 { - attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: CHTCollectionElementKindSectionFooter, with: IndexPath(item: 0, section: section)) - attributes.frame = CGRect(x: 0, y: top, width: self.collectionView!.bounds.size.width, height: footerHeight) - self.footersAttributes[section] = attributes - self.allItemAttributes.append(attributes) + attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: UICollectionView.elementKindSectionFooter, with: IndexPath(item: 0, section: section)) + attributes.frame = CGRect(x: 0, y: top, width: collectionView!.bounds.size.width, height: footerHeight) + footersAttributes[section] = attributes + allItemAttributes.append(attributes) top = attributes.frame.maxY } - for idx in 0 ..< columnCount { - self.columnHeights[section][idx] = top - } + columnHeights[section] = [CGFloat](repeating: top, count: columnCount) } var idx = 0 - let itemCounts = self.allItemAttributes.count + let itemCounts = allItemAttributes.count while idx < itemCounts { - let rect1 = self.allItemAttributes[idx].frame + let rect1 = allItemAttributes[idx].frame idx = min(idx + unionSize, itemCounts) - 1 - let rect2 = self.allItemAttributes[idx].frame - self.unionRects.append(NSValue(cgRect:rect1.union(rect2))) + let rect2 = allItemAttributes[idx].frame + unionRects.append(rect1.union(rect2)) idx += 1 } } override public var collectionViewContentSize: CGSize { - let numberOfSections = self.collectionView!.numberOfSections - if numberOfSections == 0 { - return CGSize.zero + if collectionView!.numberOfSections == 0 { + return .zero } - var contentSize = self.collectionView!.bounds.size as CGSize + var contentSize = collectionView!.bounds.size + contentSize.width = collectionViewContentWidth - if columnHeights.count > 0 { - if let height = self.columnHeights[columnHeights.count - 1].first { - contentSize.height = height - return contentSize - } + if let height = columnHeights.last?.first { + contentSize.height = height + return contentSize } - return CGSize.zero + return .zero } override public func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? { - if (indexPath as NSIndexPath).section >= self.sectionItemAttributes.count { + if indexPath.section >= sectionItemAttributes.count { return nil } - let list = self.sectionItemAttributes[indexPath.section] - if (indexPath as NSIndexPath).item >= list.count { + let list = sectionItemAttributes[indexPath.section] + if indexPath.item >= list.count { return nil } return list[indexPath.item] @@ -326,105 +339,61 @@ public class CHTCollectionViewWaterfallLayout: UICollectionViewLayout { override public func layoutAttributesForSupplementaryView(ofKind elementKind: String, at indexPath: IndexPath) -> UICollectionViewLayoutAttributes { var attribute: UICollectionViewLayoutAttributes? - if elementKind == CHTCollectionElementKindSectionHeader { - attribute = self.headersAttributes[indexPath.section] - } else if elementKind == CHTCollectionElementKindSectionFooter { - attribute = self.footersAttributes[indexPath.section] + if elementKind == UICollectionView.elementKindSectionHeader { + attribute = headersAttributes[indexPath.section] + } else if elementKind == UICollectionView.elementKindSectionFooter { + attribute = footersAttributes[indexPath.section] } - guard let returnAttribute = attribute else { - return UICollectionViewLayoutAttributes() - } - return returnAttribute + return attribute ?? UICollectionViewLayoutAttributes() } override public func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? { - var begin = 0, end = self.unionRects.count - var attrs: [UICollectionViewLayoutAttributes] = [] - - for i in 0 ..< end { - let unionRect = self.unionRects[i] - if rect.intersects(unionRect.cgRectValue) { - begin = i * unionSize - break - } - } - for i in (0 ..< self.unionRects.count).reversed() { - let unionRect = self.unionRects[i] - if rect.intersects(unionRect.cgRectValue) { - end = min((i + 1) * unionSize, self.allItemAttributes.count) - break - } + var begin = 0, end = unionRects.count + + if let i = unionRects.firstIndex(where: { rect.intersects($0) }) { + begin = i * unionSize } - for i in begin ..< end { - let attr = self.allItemAttributes[i] - if rect.intersects(attr.frame) { - attrs.append(attr) - } + if let i = unionRects.lastIndex(where: { rect.intersects($0) }) { + end = min((i + 1) * unionSize, allItemAttributes.count) } - - return attrs + return allItemAttributes[begin.. Bool { - let oldBounds = self.collectionView!.bounds - if newBounds.width != oldBounds.width { - return true - } - return false + override public func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool { + return newBounds.width != collectionView?.bounds.width } - - /** - * Find the shortest column. - * - * @return index for the shortest column - */ - public func shortestColumnIndexInSection (_ section: Int) -> Int { - var index = 0 - var shorestHeight = CGFloat.greatestFiniteMagnitude - for (idx, height) in self.columnHeights[section].enumerated() { - if height < shorestHeight { - shorestHeight = height - index = idx - } - } - return index + /// Find the shortest column. + /// + /// - Returns: index for the shortest column + private func shortestColumnIndex(inSection section: Int) -> Int { + return columnHeights[section].enumerated() + .min(by: { $0.element < $1.element })? + .offset ?? 0 } - /** - * Find the longest column. - * - * @return index for the longest column - */ - - public func longestColumnIndexInSection (_ section: Int) -> Int { - var index = 0 - var longestHeight: CGFloat = 0.0 - - for (idx, height) in self.columnHeights[section].enumerated() { - if height > longestHeight { - longestHeight = height - index = idx - } - } - return index - + /// Find the longest column. + /// + /// - Returns: index for the longest column + private func longestColumnIndex(inSection section: Int) -> Int { + return columnHeights[section].enumerated() + .max(by: { $0.element < $1.element })? + .offset ?? 0 } - /** - * Find the index for the next column. - * - * @return index for the next column - */ - public func nextColumnIndexForItem (_ item: Int, section: Int) -> Int { + /// Find the index for the next column. + /// + /// - Returns: index for the next column + private func nextColumnIndexForItem(_ item: Int, inSection section: Int) -> Int { var index = 0 - let columnCount = self.columnCountForSection(section) - switch self.itemRenderDirection { - case .chtCollectionViewWaterfallLayoutItemRenderDirectionShortestFirst : - index = self.shortestColumnIndexInSection(section) - case .chtCollectionViewWaterfallLayoutItemRenderDirectionLeftToRight : - index = (item%columnCount) - case .chtCollectionViewWaterfallLayoutItemRenderDirectionRightToLeft: + let columnCount = self.columnCount(forSection: section) + switch itemRenderDirection { + case .shortestFirst : + index = shortestColumnIndex(inSection: section) + case .leftToRight : + index = item % columnCount + case .rightToLeft: index = (columnCount - 1) - (item % columnCount) } return index diff --git a/Demo/Swift/CHTWaterfallSwiftDemo.xcodeproj/project.pbxproj b/Demo/Swift/CHTWaterfallSwiftDemo.xcodeproj/project.pbxproj index e5efd8d..ed2a37f 100644 --- a/Demo/Swift/CHTWaterfallSwiftDemo.xcodeproj/project.pbxproj +++ b/Demo/Swift/CHTWaterfallSwiftDemo.xcodeproj/project.pbxproj @@ -11,7 +11,6 @@ 62C26FDF1ABE01840027F8D4 /* AppDelegate.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C26FDE1ABE01840027F8D4 /* AppDelegate.swift */; }; 62C26FE61ABE01840027F8D4 /* Images.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 62C26FE51ABE01840027F8D4 /* Images.xcassets */; }; 62C26FE91ABE01840027F8D4 /* LaunchScreen.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62C26FE71ABE01840027F8D4 /* LaunchScreen.xib */; }; - 62C26FF51ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C26FF41ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.swift */; }; 62C26FFF1ABE01B20027F8D4 /* Main.storyboard in Resources */ = {isa = PBXBuildFile; fileRef = 62C26FFE1ABE01B20027F8D4 /* Main.storyboard */; }; 62C270011ABE01BA0027F8D4 /* ViewController.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C270001ABE01BA0027F8D4 /* ViewController.swift */; }; 62C270031ABE01D70027F8D4 /* Model.swift in Sources */ = {isa = PBXBuildFile; fileRef = 62C270021ABE01D70027F8D4 /* Model.swift */; }; @@ -19,16 +18,6 @@ 62C270071ABE01E70027F8D4 /* ImageUICollectionViewCell.xib in Resources */ = {isa = PBXBuildFile; fileRef = 62C270051ABE01E70027F8D4 /* ImageUICollectionViewCell.xib */; }; /* End PBXBuildFile section */ -/* Begin PBXContainerItemProxy section */ - 62C26FEF1ABE01850027F8D4 /* PBXContainerItemProxy */ = { - isa = PBXContainerItemProxy; - containerPortal = 62C26FD11ABE01840027F8D4 /* Project object */; - proxyType = 1; - remoteGlobalIDString = 62C26FD81ABE01840027F8D4; - remoteInfo = CHTWaterfallSwiftDemo; - }; -/* End PBXContainerItemProxy section */ - /* Begin PBXFileReference section */ 52FADF3C1CB650DC0097FB12 /* CHTCollectionViewWaterfallLayout.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; name = CHTCollectionViewWaterfallLayout.swift; path = ../../../CHTCollectionViewWaterfallLayout.swift; sourceTree = ""; }; 62C26FD91ABE01840027F8D4 /* CHTWaterfallSwiftDemo.app */ = {isa = PBXFileReference; explicitFileType = wrapper.application; includeInIndex = 0; path = CHTWaterfallSwiftDemo.app; sourceTree = BUILT_PRODUCTS_DIR; }; @@ -36,9 +25,6 @@ 62C26FDE1ABE01840027F8D4 /* AppDelegate.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppDelegate.swift; sourceTree = ""; }; 62C26FE51ABE01840027F8D4 /* Images.xcassets */ = {isa = PBXFileReference; lastKnownFileType = folder.assetcatalog; path = Images.xcassets; sourceTree = ""; }; 62C26FE81ABE01840027F8D4 /* Base */ = {isa = PBXFileReference; lastKnownFileType = file.xib; name = Base; path = Base.lproj/LaunchScreen.xib; sourceTree = ""; }; - 62C26FEE1ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.xctest */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = CHTWaterfallSwiftDemoTests.xctest; sourceTree = BUILT_PRODUCTS_DIR; }; - 62C26FF31ABE01850027F8D4 /* Info.plist */ = {isa = PBXFileReference; lastKnownFileType = text.plist.xml; path = Info.plist; sourceTree = ""; }; - 62C26FF41ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = CHTWaterfallSwiftDemoTests.swift; sourceTree = ""; }; 62C26FFE1ABE01B20027F8D4 /* Main.storyboard */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = file.storyboard; path = Main.storyboard; sourceTree = ""; }; 62C270001ABE01BA0027F8D4 /* ViewController.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = ViewController.swift; sourceTree = ""; }; 62C270021ABE01D70027F8D4 /* Model.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = Model.swift; sourceTree = ""; }; @@ -54,13 +40,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 62C26FEB1ABE01850027F8D4 /* Frameworks */ = { - isa = PBXFrameworksBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXFrameworksBuildPhase section */ /* Begin PBXGroup section */ @@ -76,7 +55,6 @@ isa = PBXGroup; children = ( 62C26FDB1ABE01840027F8D4 /* CHTWaterfallSwiftDemo */, - 62C26FF11ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests */, 62C26FDA1ABE01840027F8D4 /* Products */, ); sourceTree = ""; @@ -85,7 +63,6 @@ isa = PBXGroup; children = ( 62C26FD91ABE01840027F8D4 /* CHTWaterfallSwiftDemo.app */, - 62C26FEE1ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.xctest */, ); name = Products; sourceTree = ""; @@ -115,23 +92,6 @@ name = "Supporting Files"; sourceTree = ""; }; - 62C26FF11ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests */ = { - isa = PBXGroup; - children = ( - 62C26FF41ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.swift */, - 62C26FF21ABE01850027F8D4 /* Supporting Files */, - ); - path = CHTWaterfallSwiftDemoTests; - sourceTree = ""; - }; - 62C26FF21ABE01850027F8D4 /* Supporting Files */ = { - isa = PBXGroup; - children = ( - 62C26FF31ABE01850027F8D4 /* Info.plist */, - ); - name = "Supporting Files"; - sourceTree = ""; - }; /* End PBXGroup section */ /* Begin PBXNativeTarget section */ @@ -152,24 +112,6 @@ productReference = 62C26FD91ABE01840027F8D4 /* CHTWaterfallSwiftDemo.app */; productType = "com.apple.product-type.application"; }; - 62C26FED1ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests */ = { - isa = PBXNativeTarget; - buildConfigurationList = 62C26FFB1ABE01850027F8D4 /* Build configuration list for PBXNativeTarget "CHTWaterfallSwiftDemoTests" */; - buildPhases = ( - 62C26FEA1ABE01850027F8D4 /* Sources */, - 62C26FEB1ABE01850027F8D4 /* Frameworks */, - 62C26FEC1ABE01850027F8D4 /* Resources */, - ); - buildRules = ( - ); - dependencies = ( - 62C26FF01ABE01850027F8D4 /* PBXTargetDependency */, - ); - name = CHTWaterfallSwiftDemoTests; - productName = CHTWaterfallSwiftDemoTests; - productReference = 62C26FEE1ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.xctest */; - productType = "com.apple.product-type.bundle.unit-test"; - }; /* End PBXNativeTarget section */ /* Begin PBXProject section */ @@ -178,21 +120,18 @@ attributes = { LastSwiftMigration = 0730; LastSwiftUpdateCheck = 0730; - LastUpgradeCheck = 0730; + LastUpgradeCheck = 1020; ORGANIZATIONNAME = "Sophie Fader"; TargetAttributes = { 62C26FD81ABE01840027F8D4 = { CreatedOnToolsVersion = 6.1.1; - }; - 62C26FED1ABE01850027F8D4 = { - CreatedOnToolsVersion = 6.1.1; - TestTargetID = 62C26FD81ABE01840027F8D4; + DevelopmentTeam = KZ7D8X3PRK; }; }; }; buildConfigurationList = 62C26FD41ABE01840027F8D4 /* Build configuration list for PBXProject "CHTWaterfallSwiftDemo" */; compatibilityVersion = "Xcode 3.2"; - developmentRegion = English; + developmentRegion = en; hasScannedForEncodings = 0; knownRegions = ( en, @@ -204,7 +143,6 @@ projectRoot = ""; targets = ( 62C26FD81ABE01840027F8D4 /* CHTWaterfallSwiftDemo */, - 62C26FED1ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests */, ); }; /* End PBXProject section */ @@ -221,13 +159,6 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 62C26FEC1ABE01850027F8D4 /* Resources */ = { - isa = PBXResourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXResourcesBuildPhase section */ /* Begin PBXSourcesBuildPhase section */ @@ -243,24 +174,8 @@ ); runOnlyForDeploymentPostprocessing = 0; }; - 62C26FEA1ABE01850027F8D4 /* Sources */ = { - isa = PBXSourcesBuildPhase; - buildActionMask = 2147483647; - files = ( - 62C26FF51ABE01850027F8D4 /* CHTWaterfallSwiftDemoTests.swift in Sources */, - ); - runOnlyForDeploymentPostprocessing = 0; - }; /* End PBXSourcesBuildPhase section */ -/* Begin PBXTargetDependency section */ - 62C26FF01ABE01850027F8D4 /* PBXTargetDependency */ = { - isa = PBXTargetDependency; - target = 62C26FD81ABE01840027F8D4 /* CHTWaterfallSwiftDemo */; - targetProxy = 62C26FEF1ABE01850027F8D4 /* PBXContainerItemProxy */; - }; -/* End PBXTargetDependency section */ - /* Begin PBXVariantGroup section */ 62C26FE71ABE01840027F8D4 /* LaunchScreen.xib */ = { isa = PBXVariantGroup; @@ -277,17 +192,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -296,6 +222,7 @@ ENABLE_TESTABILITY = YES; GCC_C_LANGUAGE_STANDARD = gnu99; GCC_DYNAMIC_NO_PIC = NO; + GCC_NO_COMMON_BLOCKS = YES; GCC_OPTIMIZATION_LEVEL = 0; GCC_PREPROCESSOR_DEFINITIONS = ( "DEBUG=1", @@ -321,17 +248,28 @@ isa = XCBuildConfiguration; buildSettings = { ALWAYS_SEARCH_USER_PATHS = NO; + CLANG_ANALYZER_LOCALIZABILITY_NONLOCALIZED = YES; CLANG_CXX_LANGUAGE_STANDARD = "gnu++0x"; CLANG_CXX_LIBRARY = "libc++"; CLANG_ENABLE_MODULES = YES; CLANG_ENABLE_OBJC_ARC = YES; + CLANG_WARN_BLOCK_CAPTURE_AUTORELEASING = YES; CLANG_WARN_BOOL_CONVERSION = YES; + CLANG_WARN_COMMA = YES; CLANG_WARN_CONSTANT_CONVERSION = YES; + CLANG_WARN_DEPRECATED_OBJC_IMPLEMENTATIONS = YES; CLANG_WARN_DIRECT_OBJC_ISA_USAGE = YES_ERROR; CLANG_WARN_EMPTY_BODY = YES; CLANG_WARN_ENUM_CONVERSION = YES; + CLANG_WARN_INFINITE_RECURSION = YES; CLANG_WARN_INT_CONVERSION = YES; + CLANG_WARN_NON_LITERAL_NULL_CONVERSION = YES; + CLANG_WARN_OBJC_IMPLICIT_RETAIN_SELF = YES; + CLANG_WARN_OBJC_LITERAL_CONVERSION = YES; CLANG_WARN_OBJC_ROOT_CLASS = YES_ERROR; + CLANG_WARN_RANGE_LOOP_ANALYSIS = YES; + CLANG_WARN_STRICT_PROTOTYPES = YES; + CLANG_WARN_SUSPICIOUS_MOVE = YES; CLANG_WARN_UNREACHABLE_CODE = YES; CLANG_WARN__DUPLICATE_METHOD_MATCH = YES; "CODE_SIGN_IDENTITY[sdk=iphoneos*]" = "iPhone Developer"; @@ -339,6 +277,7 @@ ENABLE_NS_ASSERTIONS = NO; ENABLE_STRICT_OBJC_MSGSEND = YES; GCC_C_LANGUAGE_STANDARD = gnu99; + GCC_NO_COMMON_BLOCKS = YES; GCC_WARN_64_TO_32_BIT_CONVERSION = YES; GCC_WARN_ABOUT_RETURN_TYPE = YES_ERROR; GCC_WARN_UNDECLARED_SELECTOR = YES; @@ -348,6 +287,7 @@ IPHONEOS_DEPLOYMENT_TARGET = 8.1; MTL_ENABLE_DEBUG_INFO = NO; SDKROOT = iphoneos; + SWIFT_COMPILATION_MODE = wholemodule; TARGETED_DEVICE_FAMILY = "1,2"; VALIDATE_PRODUCT = YES; }; @@ -362,8 +302,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.sophiefader.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = ""; - SWIFT_OPTIMIZATION_LEVEL = "-Onone"; + SWIFT_VERSION = 5.0; }; name = Debug; }; @@ -376,43 +315,7 @@ LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks"; PRODUCT_BUNDLE_IDENTIFIER = "com.sophiefader.$(PRODUCT_NAME:rfc1034identifier)"; PRODUCT_NAME = "$(TARGET_NAME)"; - SWIFT_OBJC_BRIDGING_HEADER = ""; - }; - name = Release; - }; - 62C26FFC1ABE01850027F8D4 /* Debug */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); - GCC_PREPROCESSOR_DEFINITIONS = ( - "DEBUG=1", - "$(inherited)", - ); - INFOPLIST_FILE = CHTWaterfallSwiftDemoTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.sophiefader.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CHTWaterfallSwiftDemo.app/CHTWaterfallSwiftDemo"; - }; - name = Debug; - }; - 62C26FFD1ABE01850027F8D4 /* Release */ = { - isa = XCBuildConfiguration; - buildSettings = { - BUNDLE_LOADER = "$(TEST_HOST)"; - FRAMEWORK_SEARCH_PATHS = ( - "$(SDKROOT)/Developer/Library/Frameworks", - "$(inherited)", - ); - INFOPLIST_FILE = CHTWaterfallSwiftDemoTests/Info.plist; - LD_RUNPATH_SEARCH_PATHS = "$(inherited) @executable_path/Frameworks @loader_path/Frameworks"; - PRODUCT_BUNDLE_IDENTIFIER = "com.sophiefader.$(PRODUCT_NAME:rfc1034identifier)"; - PRODUCT_NAME = "$(TARGET_NAME)"; - TEST_HOST = "$(BUILT_PRODUCTS_DIR)/CHTWaterfallSwiftDemo.app/CHTWaterfallSwiftDemo"; + SWIFT_VERSION = 5.0; }; name = Release; }; @@ -437,15 +340,6 @@ defaultConfigurationIsVisible = 0; defaultConfigurationName = Release; }; - 62C26FFB1ABE01850027F8D4 /* Build configuration list for PBXNativeTarget "CHTWaterfallSwiftDemoTests" */ = { - isa = XCConfigurationList; - buildConfigurations = ( - 62C26FFC1ABE01850027F8D4 /* Debug */, - 62C26FFD1ABE01850027F8D4 /* Release */, - ); - defaultConfigurationIsVisible = 0; - defaultConfigurationName = Release; - }; /* End XCConfigurationList section */ }; rootObject = 62C26FD11ABE01840027F8D4 /* Project object */; diff --git a/Demo/Swift/CHTWaterfallSwiftDemo/AppDelegate.swift b/Demo/Swift/CHTWaterfallSwiftDemo/AppDelegate.swift index 28a7007..af29d6a 100644 --- a/Demo/Swift/CHTWaterfallSwiftDemo/AppDelegate.swift +++ b/Demo/Swift/CHTWaterfallSwiftDemo/AppDelegate.swift @@ -14,30 +14,30 @@ class AppDelegate: UIResponder, UIApplicationDelegate { var window: UIWindow? - func application(application: UIApplication, didFinishLaunchingWithOptions launchOptions: [NSObject: AnyObject]?) -> Bool { + func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey : Any]? = nil) -> Bool { // Override point for customization after application launch. return true } - func applicationWillResignActive(application: UIApplication) { + func applicationWillResignActive(_ application: UIApplication) { // Sent when the application is about to move from active to inactive state. This can occur for certain types of temporary interruptions (such as an incoming phone call or SMS message) or when the user quits the application and it begins the transition to the background state. // Use this method to pause ongoing tasks, disable timers, and throttle down OpenGL ES frame rates. Games should use this method to pause the game. } - func applicationDidEnterBackground(application: UIApplication) { + func applicationDidEnterBackground(_ application: UIApplication) { // Use this method to release shared resources, save user data, invalidate timers, and store enough application state information to restore your application to its current state in case it is terminated later. // If your application supports background execution, this method is called instead of applicationWillTerminate: when the user quits. } - func applicationWillEnterForeground(application: UIApplication) { + func applicationWillEnterForeground(_ application: UIApplication) { // Called as part of the transition from the background to the inactive state; here you can undo many of the changes made on entering the background. } - func applicationDidBecomeActive(application: UIApplication) { + func applicationDidBecomeActive(_ application: UIApplication) { // Restart any tasks that were paused (or not yet started) while the application was inactive. If the application was previously in the background, optionally refresh the user interface. } - func applicationWillTerminate(application: UIApplication) { + func applicationWillTerminate(_ application: UIApplication) { // Called when the application is about to terminate. Save data if appropriate. See also applicationDidEnterBackground:. } diff --git a/Demo/Swift/CHTWaterfallSwiftDemo/Model.swift b/Demo/Swift/CHTWaterfallSwiftDemo/Model.swift index b649c0a..32a020d 100644 --- a/Demo/Swift/CHTWaterfallSwiftDemo/Model.swift +++ b/Demo/Swift/CHTWaterfallSwiftDemo/Model.swift @@ -12,28 +12,9 @@ class Model: NSObject { var images : [UIImage] = [] - // Assemble an array of images to use for sample content for the collectionView func buildDataSource(){ - - let image1 = UIImage(named: "image1") - let image2 = UIImage(named: "image2") - let image3 = UIImage(named: "image3") - let image4 = UIImage(named: "image4") - let image5 = UIImage(named: "image5") - let image6 = UIImage(named: "image6") - let image7 = UIImage(named: "image7") - - images.append(image1!) - images.append(image2!) - images.append(image3!) - images.append(image4!) - images.append(image5!) - images.append(image6!) - images.append(image7!) - - + images = (1...7).map { UIImage(named: "image\($0)")! } } - } diff --git a/Demo/Swift/CHTWaterfallSwiftDemo/ViewController.swift b/Demo/Swift/CHTWaterfallSwiftDemo/ViewController.swift index 879e7fb..eb9539c 100644 --- a/Demo/Swift/CHTWaterfallSwiftDemo/ViewController.swift +++ b/Demo/Swift/CHTWaterfallSwiftDemo/ViewController.swift @@ -22,8 +22,8 @@ class ViewController: UIViewController, UICollectionViewDelegate, UICollectionVi // Attach datasource and delegate - self.collectionView.dataSource = self - self.collectionView.delegate = self + collectionView.dataSource = self + collectionView.delegate = self //Layout setup setupCollectionView() @@ -48,11 +48,11 @@ class ViewController: UIViewController, UICollectionViewDelegate, UICollectionVi layout.minimumInteritemSpacing = 1.0 // Collection view attributes - self.collectionView.autoresizingMask = [UIViewAutoresizing.FlexibleHeight, UIViewAutoresizing.FlexibleWidth] - self.collectionView.alwaysBounceVertical = true + collectionView.autoresizingMask = [.flexibleHeight, .flexibleWidth] + collectionView.alwaysBounceVertical = true // Add the waterfall layout to your collection view - self.collectionView.collectionViewLayout = layout + collectionView.collectionViewLayout = layout } // Register CollectionView Nibs @@ -60,7 +60,7 @@ class ViewController: UIViewController, UICollectionViewDelegate, UICollectionVi // attach the UI nib file for the ImageUICollectionViewCell to the collectionview let viewNib = UINib(nibName: "ImageUICollectionViewCell", bundle: nil) - collectionView.registerNib(viewNib, forCellWithReuseIdentifier: "cell") + collectionView.register(viewNib, forCellWithReuseIdentifier: "cell") } @@ -69,16 +69,16 @@ class ViewController: UIViewController, UICollectionViewDelegate, UICollectionVi //MARK: - CollectionView Delegate Methods //** Number of Cells in the CollectionView */ - func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { + func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int { return model.images.count } //** Create a basic CollectionView Cell */ - func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell { + func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell { // Create the cell and return the cell - let cell = collectionView.dequeueReusableCellWithReuseIdentifier("cell", forIndexPath: indexPath) as! ImageUICollectionViewCell + let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "cell", for: indexPath) as! ImageUICollectionViewCell // Add image to cell cell.image.image = model.images[indexPath.row] @@ -89,7 +89,7 @@ class ViewController: UIViewController, UICollectionViewDelegate, UICollectionVi //MARK: - CollectionView Waterfall Layout Delegate Methods (Required) //** Size for the cells in the Waterfall Layout */ - func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize { + func collectionView(_ collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAt indexPath: IndexPath) -> CGSize { // create a cell size from the image size, and return the size let imageSize = model.images[indexPath.row].size diff --git a/Demo/Swift/CHTWaterfallSwiftDemoTests/CHTWaterfallSwiftDemoTests.swift b/Demo/Swift/CHTWaterfallSwiftDemoTests/CHTWaterfallSwiftDemoTests.swift deleted file mode 100644 index 98ecd36..0000000 --- a/Demo/Swift/CHTWaterfallSwiftDemoTests/CHTWaterfallSwiftDemoTests.swift +++ /dev/null @@ -1,36 +0,0 @@ -// -// CHTWaterfallSwiftDemoTests.swift -// CHTWaterfallSwiftDemoTests -// -// Created by Sophie Fader on 3/21/15. -// Copyright (c) 2015 Sophie Fader. All rights reserved. -// - -import UIKit -import XCTest - -class CHTWaterfallSwiftDemoTests: XCTestCase { - - override func setUp() { - super.setUp() - // Put setup code here. This method is called before the invocation of each test method in the class. - } - - override func tearDown() { - // Put teardown code here. This method is called after the invocation of each test method in the class. - super.tearDown() - } - - func testExample() { - // This is an example of a functional test case. - XCTAssert(true, "Pass") - } - - func testPerformanceExample() { - // This is an example of a performance test case. - self.measureBlock() { - // Put the code you want to measure the time of here. - } - } - -} diff --git a/Demo/Swift/CHTWaterfallSwiftDemoTests/Info.plist b/Demo/Swift/CHTWaterfallSwiftDemoTests/Info.plist deleted file mode 100644 index ba72822..0000000 --- a/Demo/Swift/CHTWaterfallSwiftDemoTests/Info.plist +++ /dev/null @@ -1,24 +0,0 @@ - - - - - CFBundleDevelopmentRegion - en - CFBundleExecutable - $(EXECUTABLE_NAME) - CFBundleIdentifier - $(PRODUCT_BUNDLE_IDENTIFIER) - CFBundleInfoDictionaryVersion - 6.0 - CFBundleName - $(PRODUCT_NAME) - CFBundlePackageType - BNDL - CFBundleShortVersionString - 1.0 - CFBundleSignature - ???? - CFBundleVersion - 1 - -