CollectionView not displaying cells - ios

I'm trying to add UIDynamics springy-ness to a Horizontal UICollectionViewFlowLayout in Swift.
My view controller is pretty basic, just shows 30 stock items that are green:
import Foundation
import UIKit
class MainViewController: UIViewController {
private var collectionView: UICollectionView?
private let cellIdentifier = "Cell"
init() {
super.init(nibName: nil, bundle: nil)
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func viewDidLoad() {
super.viewDidLoad()
let layout = SpringyCollectionViewLayout()
let collectionView = UICollectionView(frame: view.frame, collectionViewLayout: layout)
collectionView.dataSource = self
collectionView.delegate = self
collectionView.backgroundColor = UIColor.whiteColor()
collectionView.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: cellIdentifier)
collectionView.decelerationRate = 0.9
view.addSubview(collectionView)
self.collectionView = collectionView
view.backgroundColor = UIColor.whiteColor()
}
override func prefersStatusBarHidden() -> Bool {
return true
}
}
extension MainViewController : UICollectionViewDataSource {
func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return 1
}
func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return 30
}
func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(cellIdentifier, forIndexPath: indexPath)
cell.clipsToBounds = true
cell.backgroundColor = UIColor.greenColor()
return cell
}
}
extension MainViewController : UICollectionViewDelegate {
}
My layout subclass looks like this:
import Foundation
import UIKit
let kLength = 0.3
let kDamping = 5.5
let kFrequence = 1.3
let kResistence = 1000
class SpringyCollectionViewLayout: UICollectionViewFlowLayout {
var dynamicAnimator: UIDynamicAnimator!
var visibleIndexPathsSet: NSMutableSet!
var latestDelta = CGFloat()
override init() {
super.init()
sectionInset = UIEdgeInsetsMake(0, 20, 0, 20)
itemSize = CGSizeMake(UIScreen.mainScreen().bounds.width * 0.5, UIScreen.mainScreen().bounds.height * 0.8)
minimumLineSpacing = 20
scrollDirection = .Horizontal
self.dynamicAnimator = UIDynamicAnimator(collectionViewLayout: self)
self.visibleIndexPathsSet = NSMutableSet()
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func prepareLayout() {
super.prepareLayout()
// Need to overflow our actual visible rect slightly to avoid flickering.
let visibleRect = CGRectInset(self.collectionView!.bounds, -100, -100)
let itemsInVisibleRectArray: NSArray = super.layoutAttributesForElementsInRect(visibleRect)!
let itemsIndexPathsInVisibleRectSet: NSSet = NSSet(array: itemsInVisibleRectArray.valueForKey("indexPath") as! [AnyObject])
// Step 1: Remove any behaviours that are no longer visible.
let noLongerVisibleBehaviours = (self.dynamicAnimator.behaviors as NSArray).filteredArrayUsingPredicate(NSPredicate(block: {behaviour, bindings in
let currentlyVisible: Bool = itemsIndexPathsInVisibleRectSet.member((behaviour as! UIAttachmentBehavior).items.first!
) != nil
return !currentlyVisible
}))
for (_, obj) in noLongerVisibleBehaviours.enumerate() {
self.dynamicAnimator.removeBehavior(obj as! UIDynamicBehavior)
self.visibleIndexPathsSet.removeObject((obj as! UIAttachmentBehavior).items.first!)
}
// Step 2: Add any newly visible behaviours.
// A "newly visible" item is one that is in the itemsInVisibleRect(Set|Array) but not in the visibleIndexPathsSet
let newlyVisibleItems = itemsInVisibleRectArray.filteredArrayUsingPredicate(NSPredicate(block: {item, bindings in
let currentlyVisible: Bool = self.visibleIndexPathsSet.member(item.indexPath) != nil
return !currentlyVisible
}))
let touchLocation: CGPoint = self.collectionView!.panGestureRecognizer.locationInView(self.collectionView)
for (_, item) in newlyVisibleItems.enumerate() {
let springBehaviour: UIAttachmentBehavior = UIAttachmentBehavior(item: item as! UIDynamicItem, attachedToAnchor: item.center)
springBehaviour.length = CGFloat(kLength)
springBehaviour.damping = CGFloat(kDamping)
springBehaviour.frequency = CGFloat(kFrequence)
// If our touchLocation is not (0,0), we'll need to adjust our item's center "in flight"
if (!CGPointEqualToPoint(CGPointZero, touchLocation)) {
let yDistanceFromTouch = fabsf(Float(touchLocation.y - springBehaviour.anchorPoint.y))
let xDistanceFromTouch = fabsf(Float(touchLocation.x - springBehaviour.anchorPoint.x))
let scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / Float(kResistence)
let item = springBehaviour.items.first as! UICollectionViewLayoutAttributes
var center = item.center
if self.latestDelta < 0 {
center.x += max(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
} else {
center.x += min(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
}
item.center = center
}
self.dynamicAnimator.addBehavior(springBehaviour)
self.visibleIndexPathsSet.addObject(item.indexPath)
}
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return self.dynamicAnimator.itemsInRect(rect) as? [UICollectionViewLayoutAttributes]
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
return self.dynamicAnimator.layoutAttributesForCellAtIndexPath(indexPath)
}
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
let scrollView = self.collectionView!
let delta: CGFloat = newBounds.origin.x - scrollView.bounds.origin.x
self.latestDelta = delta
let touchLocation: CGPoint = self.collectionView!.panGestureRecognizer.locationInView(self.collectionView)
for (_, springBehaviour) in self.dynamicAnimator.behaviors.enumerate() {
let springBehav = (springBehaviour as! UIAttachmentBehavior)
let yDistanceFromTouch = fabsf(Float(touchLocation.y - springBehav.anchorPoint.y))
let xDistanceFromTouch = fabsf(Float(touchLocation.x - springBehav.anchorPoint.x))
let scrollResistance = (yDistanceFromTouch + xDistanceFromTouch) / Float(kResistence)
let item = springBehav.items.first as! UICollectionViewLayoutAttributes
var center = item.center
if self.latestDelta < 0 {
center.x += max(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
} else {
center.x += min(self.latestDelta, self.latestDelta * CGFloat(scrollResistance))
}
item.center = center;
self.dynamicAnimator.updateItemUsingCurrentState(item)
}
return false
}
override func targetContentOffsetForProposedContentOffset(proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
var offsetAdjustment = CGFloat(MAXFLOAT)
let center = proposedContentOffset.x + (CGRectGetWidth(self.collectionView!.bounds) / 2.0)
let proposedRect = CGRectMake(proposedContentOffset.x, 0.0, self.collectionView!.bounds.size.width, self.collectionView!.bounds.size.height)
let array:NSArray = self.layoutAttributesForElementsInRect(proposedRect)!
for layoutAttributes : AnyObject in array {
if let _layoutAttributes = layoutAttributes as? UICollectionViewLayoutAttributes {
if _layoutAttributes.representedElementCategory != UICollectionElementCategory.Cell {
continue
}
let itemVerticalCenter:CGFloat = layoutAttributes.center.x
let _center = fabsf(Float(itemVerticalCenter) - Float(center))
let _offsetAdjustment = fabsf(Float(offsetAdjustment))
if (_center < _offsetAdjustment) {
offsetAdjustment = (itemVerticalCenter - center)
}
}
}
return CGPointMake(proposedContentOffset.x + offsetAdjustment, proposedContentOffset.y)
}
}
The collection view renders with the correct contentSize, but the cells are not there:
If I remove the override of layoutAttributesForElementsInRect that returns the result of itemsInRect from the UIDynamicAnimator, the cells will display - although without the dynamic behaviors:
Any idea of what I'm missing? I've done the same thing before in Objective-C and iOS 8 - when I compare the code it looks similar.
I've debugged prepareLayout and it does find cells in the visible rect, and behaviors are indeed added to the animator.

Related

pinch zoom in collection view

I am trying to add a pinch gesture zoom in my collection view so what is happening is the zoom is happening each time from the start it is not preserving the previous scale state and the max and min scale limit is also not working
since I am new to to swift I am struggling with this, thanks for the help in advance
here is my collection view controller class
import UIKit
class BookViewController: UIViewController, UICollectionViewDataSource, UICollectionViewDelegate {
#IBOutlet weak var seatMapCollection: UICollectionView!
#IBAction func pinchGesture(_ sender: UIPinchGestureRecognizer) {
}
var dateValue = ["1","2","3","4","10","6","7","8","9","5"]
var dayValue = ["Mon","Tue","Wed","Thu","Thu","Thu","Thu","Thu","Thu","Thu"]
var month = ["jan","feb","mar","apr","Thu","Thu","Thu","Thu","Thu","Thu"]
override func viewDidLoad() {
super.viewDidLoad()
self.seatMapCollection.dataSource = self
self.seatMapCollection.delegate = self
self.seatMapCollection.maximumZoomScale = 2
self.seatMapCollection.minimumZoomScale = 0.50
let pinchGesture = UIPinchGestureRecognizer(target: self, action: #selector(pinchAction(sender:)))
seatMapCollection.addGestureRecognizer(pinchGesture)
self.view.sendSubview(toBack: seatMapCollection)
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
//return seatmapCollection.numberOfItems(inSection: 150)
return 15
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "SeatMapCollectionViewCell", for: indexPath) as! SeatMapCollectionViewCell
return cell
}
#objc func pinchAction(sender:UIPinchGestureRecognizer){
var scaleValue: CGFloat!
if sender.state == .changed || sender.state == .began {
if scaleValue == nil{
seatMapCollection.transform = CGAffineTransform.init(scaleX: sender.scale, y: sender.scale)
scaleValue = sender.scale
}else{
seatMapCollection.transform = CGAffineTransform.init(scaleX: scaleValue, y: scaleValue)
}
}
}
}
and here is my custom collection view layout class
import UIKit
class CustomCollectionViewLayout: UICollectionViewLayout {
let CELL_HEIGHT = 35.0
let CELL_WIDTH = 35.0
let STATUS_BAR = UIApplication.shared.statusBarFrame.height
var cache = [UICollectionViewLayoutAttributes]()
var contentSize = CGSize.zero
var cellAttrsDictionary = [UICollectionViewLayoutAttributes]()
var cellPadding = 5.0
override var collectionViewContentSize: CGSize {
return self.contentSize
}
var interItemsSpacing: CGFloat = 8
// 5
var contentInsets: UIEdgeInsets {
return collectionView!.contentInset
}
override func prepare() {
// Cycle through each section of the data source.
if collectionView!.numberOfSections > 0 {
for section in 0...collectionView!.numberOfSections-1 {
// Cycle through each item in the section.
if collectionView!.numberOfItems(inSection: section) > 0 {
for item in 0...collectionView!.numberOfItems(inSection: section)-1 {
// Build the UICollectionVieLayoutAttributes for the cell.
let cellIndex = NSIndexPath(item: item, section: section)
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT
let frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)
let cellFinalAttribute = frame.insetBy(dx:CGFloat(cellPadding) ,dy:CGFloat(cellPadding))
let cellAttributes = UICollectionViewLayoutAttributes(forCellWith: cellIndex as IndexPath)
cellAttributes.frame = cellFinalAttribute
cellAttrsDictionary.append(cellAttributes)
// Determine zIndex based on cell type.
/* if section == 0 && item == 0 {
cellAttributes.zIndex = 4
} else if section == 0 {
cellAttributes.zIndex = 3
} else if item == 0 {
cellAttributes.zIndex = 2
} else {
cellAttributes.zIndex = 1
}*/
// Save the attributes.
//cellAttrsDictionary[cellIndex] = cellAttributes
}
}
}
}
// Update content size.
let contentWidth = Double(collectionView!.numberOfItems(inSection: 0)) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Create an array to hold all elements found in our current view.
var attributesInRect = [UICollectionViewLayoutAttributes]()
// Check each element to see if it should be returned.
for cellAttributes in cellAttrsDictionary {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
// Return list of elements.
return attributesInRect
}
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return false
}
}
here is my custom cell class
import UIKit
class SeatMapCollectionViewCell: UICollectionViewCell {
#IBOutlet weak var seatDetail: UILabel!
required init(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)!
setup()
}
override init(frame: CGRect) {
super.init(frame: frame)
setup()
}
func setup() {
self.layer.borderWidth = 1.0
self.layer.borderColor = UIColor.gray.cgColor
self.layer.cornerRadius = 5.0
}
}

UICollectionViewLayout and NavigationBar - wrong y position

I found this nice UICollectionViewLayout ExpandingCollectionView
The Problem is: as soon as I add a Navigation bar to the ViewController (with searchbar and scropebar) the collection view will slip underneath.
import Foundation
import UIKit
/* The heights are declared as constants outside of the class so they can be easily referenced elsewhere */
struct UltravisualLayoutConstants {
struct Cell {
/* The height of the non-featured cell */
static let standardHeight: CGFloat = 100
/* The height of the first visible cell */
static let featuredHeight: CGFloat = 280
}
}
class UltravisualLayout:UICollectionViewLayout{
// MARK: Properties and Variables
/* The amount the user needs to scroll before the featured cell changes */
let dragOffset: CGFloat = 180.0
var cache = [UICollectionViewLayoutAttributes]()
/* Returns the item index of the currently featured cell */
var featuredItemIndex: Int {
get {
/* Use max to make sure the featureItemIndex is never < 0 */
return max(0, Int(collectionView!.contentOffset.y / dragOffset))
}
}
/* Returns a value between 0 and 1 that represents how close the next cell is to becoming the featured cell */
var nextItemPercentageOffset: CGFloat {
get {
return (collectionView!.contentOffset.y / dragOffset) - CGFloat(featuredItemIndex)
}
}
/* Returns the width of the collection view */
var width: CGFloat {
get {
return collectionView!.bounds.width
}
}
/* Returns the height of the collection view */
var height: CGFloat {
get {
return collectionView!.bounds.height
}
}
/* Returns the number of items in the collection view */
var numberOfItems: Int {
get {
return collectionView!.numberOfItems(inSection: 0)
}
}
// MARK: UICollectionViewLayout
/* Return the size of all the content in the collection view */
override var collectionViewContentSize: CGSize{
let contentHeight = (CGFloat(numberOfItems) * dragOffset) + (height - dragOffset)
return CGSize(width: width, height: contentHeight)
}
override func prepare() {
cache.removeAll(keepingCapacity: false)
let standardHeight = UltravisualLayoutConstants.Cell.standardHeight
let featuredHeight = UltravisualLayoutConstants.Cell.featuredHeight
var frame = CGRect.zero
var y: CGFloat = 0
for item in 0..<numberOfItems {
// 1
let indexPath = IndexPath(item:item, section:0)
let attributes = UICollectionViewLayoutAttributes(forCellWith: indexPath)
// 2
attributes.zIndex = item
var height = standardHeight
// 3
if indexPath.item == featuredItemIndex {
// 4
let yOffset = standardHeight * nextItemPercentageOffset
y = collectionView!.contentOffset.y - yOffset
height = featuredHeight
} else if indexPath.item == (featuredItemIndex + 1) && indexPath.item != numberOfItems {
// 5
let maxY = y + standardHeight
height = standardHeight + max((featuredHeight - standardHeight) * nextItemPercentageOffset, 0)
y = maxY - height
}
// 6
frame = CGRect(x: 0, y: y, width: width, height: height)
attributes.frame = frame
cache.append(attributes)
y = frame.maxY
}
}
/* Return all attributes in the cache whose frame intersects with the rect passed to the method */
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
for attributes in cache {
if attributes.frame.intersects(rect) {
layoutAttributes.append(attributes)
}
}
return layoutAttributes
}
/* Return true so that the layout is continuously invalidated as the user scrolls */
override func shouldInvalidateLayout(forBoundsChange newBounds: CGRect) -> Bool {
return true
}
override func targetContentOffset(forProposedContentOffset proposedContentOffset: CGPoint, withScrollingVelocity velocity: CGPoint) -> CGPoint {
let itemIndex = round(proposedContentOffset.y / dragOffset)
let yOffset = itemIndex * dragOffset
return CGPoint(x: 0, y: yOffset)
}
}
Can anyone tell me, where I need to adjust the code? I've really no idea but I have to implement this code untill tomorrow :O
Many Thanks!
Here is the UICollectionViewController:
import UIKit
private let reuseIdentifier = "Cell"
class InspirationsViewController: UICollectionViewController {
let inspirations = Inspiration.allInspirations()
override func viewDidLoad() {
super.viewDidLoad()
if let patternImage = UIImage(named: "Pattern") {
view.backgroundColor = UIColor(patternImage: patternImage)
}
collectionView!.backgroundColor = UIColor.clear
collectionView!.decelerationRate = UIScrollViewDecelerationRateFast
let searchController = UISearchController(searchResultsController: nil)
searchController.searchBar.scopeButtonTitles = ["All", "Chocolate", "Hard", "Other"]
navigationItem.searchController = searchController
navigationItem.hidesSearchBarWhenScrolling = true
definesPresentationContext = true
self.definesPresentationContext = true
}
}
extension InspirationsViewController {
override func numberOfSections(in collectionView: UICollectionView) -> Int {
return 1
}
override func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return inspirations.count
}
override func collectionView(_ collectionView: UICollectionView, cellForItemAt indexPath: IndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCell(withReuseIdentifier: "InspirationCell", for: indexPath) as! InspirationCell
cell.inspiration = inspirations[indexPath.item]
return cell
}
override func collectionView(_ collectionView: UICollectionView, didSelectItemAt indexPath: IndexPath) {
let layout = collectionViewLayout as! UltravisualLayout
let offset = layout.dragOffset * CGFloat(indexPath.item)
if collectionView.contentOffset.y != offset {
collectionView.setContentOffset(CGPoint(x: 0, y: offset), animated: true)
}
}
}
When laying out the collectionView, use safe area guides:
NSLayoutConstraint.activate([
collectionView.topAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.topAnchor),
collectionView.leftAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.leftAnchor),
collectionView.rightAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.rightAnchor),
collectionView.bottomAnchor.constraint(equalTo: self.view.safeAreaLayoutGuide.bottomAnchor),
])
Or perhaps you can use UICollectionViewController (if you are not using it), and it should take care of it implicitly.

iOS: in Swift3, in my collectionView, when I scroll downstair, the collectionView comes automatically at the top. How to stop it?

I would like my collectionView to stop in the cell. The problem is that when I scroll downstair, if I release it, it comes automatically at the first position...
I tried with collection.alwaysBounceVertical = true without success...
Here is my code:
override func viewDidLoad() {
super.viewDidLoad()
let layout = OrganiserLayout()
let frameCollection = CGRect(x: self.view.frame.origin.x, y: self.view.frame.origin.y, width: self.view.frame.width, height: self.view.frame.height + 1000)
let collection = UICollectionView(frame: frameCollection, collectionViewLayout: layout)
collection.delegate = self
collection.dataSource = self
collection.backgroundColor = UIColor.white
collection.register(OrganiserCollectionViewCell.self, forCellWithReuseIdentifier: "cell")
self.view.addSubview(collection)
collection.alwaysBounceVertical = true
collection.alwaysBounceHorizontal = true
collection.bounces = true
collection.isPagingEnabled = false
collection.isScrollEnabled = true
}
func numberOfSections(in collectionView: UICollectionView) -> Int {
return 15
}
func collectionView(_ collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
switch section {
case 0:
return 40
}
}
class OrganiserLayout:UICollectionViewLayout {
let cellWidth:CGFloat = 100
var attrDict = Dictionary<IndexPath,UICollectionViewLayoutAttributes>()
var contentSize = CGSize.zero
override var collectionViewContentSize : CGSize {
return self.contentSize
}
override func prepare() {
// Generate the attributes for each cell based on the size of the collection view and our chosen cell width
if let cv = collectionView {
let collectionViewHeight = cv.frame.height
let numberOfSections = cv.numberOfSections
self.contentSize = cv.frame.size
self.contentSize.width = cellWidth*CGFloat(numberOfSections)
for section in 0...numberOfSections-1 {
let numberOfItemsInSection = cv.numberOfItems(inSection: section)
let itemHeight = collectionViewHeight/CGFloat(numberOfItemsInSection)
let itemXPos = cellWidth*CGFloat(section)
for item in 0...numberOfItemsInSection-1 {
let indexPath = IndexPath(item: item, section: section)
let itemYPos = itemHeight*CGFloat(item)
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attr.frame = CGRect(x: itemXPos, y: itemYPos, width: cellWidth, height: itemHeight)
attrDict[indexPath] = attr
}
}
}
}
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
// Here we return the layout attributes for cells in the current rectangle
var attributesInRect = [UICollectionViewLayoutAttributes]()
for cellAttributes in attrDict.values {
if rect.intersects(cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}
return attributesInRect
}
override func layoutAttributesForItem(at indexPath: IndexPath) -> UICollectionViewLayoutAttributes? {
// Here we return one attribute object for the specified indexPath
return attrDict[indexPath]!
}
}
class OrganiserCollectionViewCell:UICollectionViewCell {
var label:UILabel!
var seperator:UIView!
override init(frame: CGRect) {
super.init(frame: frame)
label = UILabel()
label.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(label)
seperator = UIView()
seperator.backgroundColor = UIColor.black
seperator.translatesAutoresizingMaskIntoConstraints = false
self.addSubview(seperator)
let views:[String:UIView] = [
"label":label,
"sep":seperator
]
let cons = [
"V:|-20-[label]",
"V:[sep(1)]|",
"H:|[label]|",
"H:|[sep]|"
]
for con in cons {
self.addConstraints(NSLayoutConstraint.constraints(withVisualFormat: con, options: [], metrics: nil, views: views))
}
}
I need that because I need the user stops on the cell, and click on it. With that problem, he cannot click on the cells that are downstairs.
Thanks in advance.
Set some height for contentSize like below :
self.contentSize.height = CGFloat(2750)
In your code :
class OrganiserLayout:UICollectionViewLayout {
override func prepare() {
// Generate the attributes for each cell based on the size of the collection view and our chosen cell width
if let cv = collectionView {
let collectionViewHeight = cv.frame.height
let numberOfSections = cv.numberOfSections
self.contentSize = cv.frame.size
self.contentSize.width = cellWidth*CGFloat(numberOfSections)
self.contentSize.height = CGFloat(2750) // I added this line
for section in 0...numberOfSections-1 {
let numberOfItemsInSection = cv.numberOfItems(inSection: section)
let itemHeight = collectionViewHeight/CGFloat(numberOfItemsInSection)
let itemXPos = cellWidth*CGFloat(section)
for item in 0...numberOfItemsInSection-1 {
let indexPath = IndexPath(item: item, section: section)
let itemYPos = itemHeight*CGFloat(item)
let attr = UICollectionViewLayoutAttributes(forCellWith: indexPath)
attr.frame = CGRect(x: itemXPos, y: itemYPos, width: cellWidth, height: itemHeight)
attrDict[indexPath] = attr
}
}
}
}
}

Thread 5: EXC_BAD_INSTRUCTION (code=EXC_I386_INVOP, subcode=0x0) - Cast from 'Result<AnyObject>' to unrelated type 'NSDictionary' always fail

I am following the Ray Wenderlich tutorial on Alamofire (and struggling), http://www.raywenderlich.com/85080/beginning-alamofire-tutorial#comments , and I am getting the error in the title, in the "loading more photos" part.
The error is on the line "let photoInfos = ((JSON as! NSDictionary).valueForKey("photos") as! [NSDictionary]).filter ({"
Here is my code.
//
// PhotoBrowserCollectionViewController.swift
// Photomania
//
// Created by Essan Parto on 2014-08-20.
// Copyright (c) 2014 Essan Parto. All rights reserved.
//
import UIKit
import Alamofire
class PhotoBrowserCollectionViewController: UICollectionViewController, UICollectionViewDelegateFlowLayout {
var photos = NSMutableArray()
#IBOutlet weak var PhotoBrowserCell: PhotoBrowserCollectionViewCell!
let refreshControl = UIRefreshControl()
var populatingPhotos = false
var currentPage = 1
let PhotoBrowserCellIdentifier = "PhotoBrowserCell"
let PhotoBrowserFooterViewIdentifier = "PhotoBrowserFooterView"
// MARK: Life-cycle
override func viewDidLoad() {
super.viewDidLoad()
setupView()
populatePhotos()
//// Alamofire.request(.GET, "https://api.500px.com/v1/photos").responseJSON() {
//// (_, _, data) in
//// print(data.value)}
//
// Alamofire.request(.GET, "https://api.500px.com/v1/photos", parameters: ["consumer_key": "Jj0vPllqD0zvxttgFZ1aTbRF5zy9g1yDcsTxJRFV"]).responseJSON() {
// (_,_,JSON) in
// print(JSON.value)
//
// let photoInfos = (JSON.value!.valueForKey("photos") as! [NSDictionary]).filter({
// ($0["nsfw"] as! Bool) == false
// }).map {
// PhotoInfo(id: $0["id"] as! Int, url: $0["image_url"] as! String)
// }
//
// self.photos.addObject(photoInfos)
// print(self.photos)
//
// self.collectionView?.reloadData()
// }
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
}
// MARK: CollectionView
override func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return photos.count
}
override func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(PhotoBrowserCellIdentifier, forIndexPath: indexPath) as! PhotoBrowserCollectionViewCell
// let imageURL = (photos.objectAtIndex(indexPath.row) as! PhotoInfo).url
let imageURL = (photos.objectAtIndex(indexPath.row) as! PhotoInfo).url
Alamofire.request(.GET, imageURL).response() {
(_,_, data, _) in
let image = UIImage(data: data!)
cell.imageView.image = image
}
return cell
}
override func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
return collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: PhotoBrowserFooterViewIdentifier, forIndexPath: indexPath)
}
override func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
performSegueWithIdentifier("ShowPhoto", sender: (self.photos.objectAtIndex(indexPath.item) as! PhotoInfo).id)
}
// MARK: Helper
func setupView() {
navigationController?.setNavigationBarHidden(false, animated: true)
let layout = UICollectionViewFlowLayout()
let itemWidth = (view.bounds.size.width - 2) / 3
layout.itemSize = CGSize(width: itemWidth, height: itemWidth)
layout.minimumInteritemSpacing = 1.0
layout.minimumLineSpacing = 1.0
layout.footerReferenceSize = CGSize(width: collectionView!.bounds.size.width, height: 100.0)
collectionView!.collectionViewLayout = layout
navigationItem.title = "Featured"
collectionView!.registerClass(PhotoBrowserCollectionViewCell.classForCoder(), forCellWithReuseIdentifier: PhotoBrowserCellIdentifier)
collectionView!.registerClass(PhotoBrowserCollectionViewLoadingCell.classForCoder(), forSupplementaryViewOfKind: UICollectionElementKindSectionFooter, withReuseIdentifier: PhotoBrowserFooterViewIdentifier)
refreshControl.tintColor = UIColor.whiteColor()
refreshControl.addTarget(self, action: "handleRefresh", forControlEvents: .ValueChanged)
collectionView!.addSubview(refreshControl)
}
override func prepareForSegue(segue: UIStoryboardSegue, sender: AnyObject?) {
if segue.identifier == "ShowPhoto" {
(segue.destinationViewController as! PhotoViewerViewController).photoID = sender!.integerValue
(segue.destinationViewController as! PhotoViewerViewController).hidesBottomBarWhenPushed = true
}
}
// 1
override func scrollViewDidScroll(scrollView: UIScrollView) {
if scrollView.contentOffset.y + view.frame.size.height > scrollView.contentSize.height * 0.8 {
populatePhotos()
}
}
func populatePhotos() {
// 2
if populatingPhotos {
return
}
populatingPhotos = true
// 3
Alamofire.request(Five100px.Router.PopularPhotos(self.currentPage)).responseJSON() {
(_, _, JSON) in
// 4
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_HIGH, 0)) {
// 5, 6, 7
let photoInfos = ((JSON as! NSDictionary).valueForKey("photos") as! [NSDictionary]).filter ({
($0["nsfw"] as! Bool) == false }).map { PhotoInfo(id: $0["id"] as! Int, url: $0["image_url"] as! String)}
//8
let lastItem = self.photos.count
//9
self.photos.addObject(photoInfos)
//10
let indexPaths = (lastItem..<self.photos.count).map { NSIndexPath(forItem: $0, inSection: $0) }
// 11
dispatch_async(dispatch_get_main_queue()) {
self.collectionView!.insertItemsAtIndexPaths(indexPaths)
}
self.currentPage++
}
self.populatingPhotos = false
}
}
func handleRefresh() {
}
}
class PhotoBrowserCollectionViewCell: UICollectionViewCell {
let imageView = UIImageView()
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
backgroundColor = UIColor(white: 0.1, alpha: 1.0)
imageView.frame = bounds
addSubview(imageView)
}
}
class PhotoBrowserCollectionViewLoadingCell: UICollectionReusableView {
let spinner = UIActivityIndicatorView(activityIndicatorStyle: UIActivityIndicatorViewStyle.WhiteLarge)
required init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
}
override init(frame: CGRect) {
super.init(frame: frame)
spinner.startAnimating()
spinner.center = self.center
addSubview(spinner)
}
}
the answer is very simple. On the Five100px.swift file , you will see static let consumerKey. please update consumerKey. If you live to continue same problem. please download new version https://www.dropbox.com/s/e2unowffetv9h9c/Photomania.zip?dl=0 from this link.

gestureRecognizerShouldBegin: Unrecognized selector sent to instance

I am implementing a Collection View with a Calendar From based on Sapporo from nghialv ( https://github.com/nghialv/Sapporo ) for a complete different purpose. I want to define pulses which are going to be sent in six different channels in a 10 second frame. Therefore I have a PulseCollectionView of Seconds vs. Channels.
I want to implement cell dragging after long press using this tutorial: http://karmadust.com/drag-and-rearrange-uicollectionviews-through-layouts/.
My problem is that I am getting an error when I do long press on a cell:
*** Terminating app due to uncaught exception 'NSInvalidArgumentException', reason: '-[NSConcreteMapTable gestureRecognizerShouldBegin:]: unrecognized selector sent to instance 0x7b6bea30'
I have tried to find the faulty line through the debugger, but it seems I cannot find it. It breaks before even getting to gestureRecognizerShouldBegin
This is my Layout File:
import UIKit
import Sapporo
let SecondsMaximum : CGFloat = 10
let ChannelsMaximum : CGFloat = 6
let HorizontalSpacing : CGFloat = 10
let VerticalSpacing : CGFloat = 4
//let WidthPerSecond : CGFloat = 100
let SecondHeaderHeight : CGFloat = 40
let ChannelHeaderWidth : CGFloat = 100
class PulseLayout: SALayout, UIGestureRecognizerDelegate {
override func collectionViewContentSize() -> CGSize {
let contentHeight = collectionView!.bounds.size.height
let contentWidth = collectionView!.bounds.size.width
return CGSizeMake(contentWidth, contentHeight)
}
override func awakeFromNib() {
super.awakeFromNib()
self.setupGestureRecognizer()
}
override func layoutAttributesForElementsInRect(rect: CGRect) -> [AnyObject]? {
var layoutAttributes = [UICollectionViewLayoutAttributes]()
// Cells
let visibleIndexPaths = indexPathsOfItemsInRect(rect)
layoutAttributes += visibleIndexPaths.map {
self.layoutAttributesForItemAtIndexPath($0)
}
// Supplementary views
let secondHeaderViewIndexPaths = indexPathsOfSecondHeaderViewsInRect(rect)
layoutAttributes += secondHeaderViewIndexPaths.map {
self.layoutAttributesForSupplementaryViewOfKind(PulseHeaderType.Second.rawValue, atIndexPath: $0)
}
let channelHeaderViewIndexPaths = indexPathsOfChannelHeaderViewsInRect(rect)
layoutAttributes += channelHeaderViewIndexPaths.map {
self.layoutAttributesForSupplementaryViewOfKind(PulseHeaderType.Channel.rawValue, atIndexPath: $0)
}
// Decoration Views
let verticalGridViewIndexPaths = indexPathsOfVerticalGridLineViewsInRect(rect)
layoutAttributes += verticalGridViewIndexPaths.map {
self.layoutAttributesForDecorationViewOfKind(GridLineType.Vertical.rawValue, atIndexPath: $0)
}
let horizontalGridViewIndexPaths = indexPathsOfHorizontalGridLineViewsInRect(rect)
layoutAttributes += horizontalGridViewIndexPaths.map {
self.layoutAttributesForDecorationViewOfKind(GridLineType.Horizontal.rawValue, atIndexPath: $0)
}
return layoutAttributes
}
override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
var attributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: indexPath)
if let event = (getCellModel(indexPath) as? PulseEventCellModel)?.event {
attributes.frame = frameForEvent(event)
}
return attributes
}
override func layoutAttributesForSupplementaryViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
var attributes = UICollectionViewLayoutAttributes(forSupplementaryViewOfKind: elementKind, withIndexPath: indexPath)
let totalHeight = collectionViewContentSize().height
let totalWidth = collectionViewContentSize().width
if elementKind == PulseHeaderType.Second.rawValue {
let availableWidth = totalWidth - ChannelHeaderWidth
let widthPerSecond = availableWidth / SecondsMaximum
attributes.frame = CGRectMake(ChannelHeaderWidth + widthPerSecond * CGFloat(indexPath.item), 0, widthPerSecond, SecondHeaderHeight)
attributes.zIndex = -10
} else if elementKind == PulseHeaderType.Channel.rawValue {
let availableHeight = totalHeight - SecondHeaderHeight
let heightPerChannel = availableHeight / ChannelsMaximum
attributes.frame = CGRectMake(0, SecondHeaderHeight + (heightPerChannel * CGFloat(indexPath.item)), ChannelHeaderWidth, heightPerChannel)
attributes.zIndex = -10
}
return attributes
}
override func layoutAttributesForDecorationViewOfKind(elementKind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes! {
var attributes = UICollectionViewLayoutAttributes(forDecorationViewOfKind: elementKind, withIndexPath: indexPath)
let totalHeight = collectionViewContentSize().height
let totalWidth = collectionViewContentSize().width
if elementKind == GridLineType.Vertical.rawValue {
let availableWidth = totalWidth - ChannelHeaderWidth
let widthPerSecond = availableWidth / SecondsMaximum
attributes.frame = CGRectMake(ChannelHeaderWidth + widthPerSecond * CGFloat(indexPath.item), 0.0, 1, totalHeight)
attributes.zIndex = -11
} else if elementKind == GridLineType.Horizontal.rawValue {
let availableHeight = totalHeight - SecondHeaderHeight
let heightPerChannel = availableHeight / ChannelsMaximum
attributes.frame = CGRectMake(0.0, SecondHeaderHeight + (heightPerChannel * CGFloat(indexPath.item)), totalWidth, 1)
attributes.zIndex = -11
}
return attributes
}
override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}
struct Bundle {
var offset : CGPoint = CGPointZero
var sourceCell : UICollectionViewCell
var representationImageView : UIView
var currentIndexPath : NSIndexPath
var canvas : UIView
}
var bundle : Bundle?
var canvas : UIView? {
didSet {
if canvas != nil {
// self.calculateBorders()
}
}
}
func setupGestureRecognizer() {
if let collectionView = self.collectionView {
let longPressGestureRecogniser = UILongPressGestureRecognizer(target: self, action: "handleGesture:")
longPressGestureRecogniser.minimumPressDuration = 0.2
longPressGestureRecogniser.delegate = self
collectionView.addGestureRecognizer(longPressGestureRecogniser)
if self.canvas == nil {
self.canvas = self.collectionView!.superview
}
}
}
func gestureRecognizerShouldBegin(gestureRecognizer: UIGestureRecognizer) -> Bool {
if let ca = self.collectionView!.superview {
if let cv = self.collectionView {
let pointPressedInCanvas = gestureRecognizer.locationInView(ca)
for cell in cv.visibleCells() as! [PulseEventCell] {
let cellInCanvasFrame = ca.convertRect(cell.frame, fromView: cv)
if CGRectContainsPoint(cellInCanvasFrame, pointPressedInCanvas ) {
let representationImage = cell.snapshotViewAfterScreenUpdates(true)
representationImage.frame = cellInCanvasFrame
let offset = CGPointMake(pointPressedInCanvas.x - cellInCanvasFrame.origin.x, pointPressedInCanvas.y - cellInCanvasFrame.origin.y)
let indexPath : NSIndexPath = cv.indexPathForCell(cell as UICollectionViewCell)!
self.bundle = Bundle(offset: offset, sourceCell: cell, representationImageView:representationImage, currentIndexPath: indexPath, canvas: ca)
break
}
}
}
}
return (self.bundle != nil)
}
func handleGesture(gesture: UILongPressGestureRecognizer) -> Void {
if let bundle = self.bundle {
let dragPointOnCanvas = gesture.locationInView(self.collectionView!.superview)
if gesture.state == UIGestureRecognizerState.Began {
bundle.sourceCell.hidden = true
self.canvas?.addSubview(bundle.representationImageView)
UIView.animateWithDuration(0.5, animations: { () -> Void in
bundle.representationImageView.alpha = 0.8
});
}
if gesture.state == UIGestureRecognizerState.Changed {
// Update the representation image
var imageViewFrame = bundle.representationImageView.frame
var point = CGPointZero
point.x = dragPointOnCanvas.x - bundle.offset.x
point.y = dragPointOnCanvas.y - bundle.offset.y
imageViewFrame.origin = point
bundle.representationImageView.frame = imageViewFrame
let dragPointOnCollectionView = gesture.locationInView(self.collectionView)
if let indexPath : NSIndexPath = self.collectionView?.indexPathForItemAtPoint(dragPointOnCollectionView) {
// self.checkForDraggingAtTheEdgeAndAnimatePaging(gesture)
if indexPath.isEqual(bundle.currentIndexPath) == false {
// If we have a collection view controller that implements the delegate we call the method first
/*if let delegate = self.collectionView!.delegate as UICollectionViewDelegate? {
delegate.moveDataItem(bundle.currentIndexPath, toIndexPath: indexPath)
}*/
self.collectionView!.moveItemAtIndexPath(bundle.currentIndexPath, toIndexPath: indexPath)
self.bundle!.currentIndexPath = indexPath
}
}
}
if gesture.state == UIGestureRecognizerState.Ended {
bundle.sourceCell.hidden = false
bundle.representationImageView.removeFromSuperview()
if let delegate = self.collectionView!.delegate as UICollectionViewDelegate? { // if we have a proper data source then we can reload and have the data displayed correctly
self.collectionView!.reloadData()
}
self.bundle = nil
}
}
}
}
extension PulseLayout {
func indexPathsOfEventsBetweenMinSecondIndex(minChannelIndex: Int, maxChannelIndex: Int, minStartSecond: Int, maxStartSecond: Int) -> [NSIndexPath] {
var indexPaths = [NSIndexPath]()
if let cellmodels = getCellModels(0) as? [PulseEventCellModel] {
for i in 0..<cellmodels.count {
let event = cellmodels[i].event
if event.channel >= minChannelIndex && event.channel <= maxChannelIndex && event.startSecond >= minStartSecond && event.startSecond <= maxStartSecond {
let indexPath = NSIndexPath(forItem: i, inSection: 0)
indexPaths.append(indexPath)
}
}
}
return indexPaths
}
func indexPathsOfItemsInRect(rect: CGRect) -> [NSIndexPath] {
let minVisibleChannel = channelIndexFromYCoordinate(CGRectGetMinY(rect))
let maxVisibleChannel = channelIndexFromYCoordinate(CGRectGetMaxY(rect))
let minVisibleSecond = secondIndexFromXCoordinate(CGRectGetMinX(rect))
let maxVisibleSecond = secondIndexFromXCoordinate(CGRectGetMaxX(rect))
return indexPathsOfEventsBetweenMinSecondIndex(minVisibleChannel, maxChannelIndex: maxVisibleChannel, minStartSecond: minVisibleSecond, maxStartSecond: maxVisibleSecond)
}
func channelIndexFromYCoordinate(yPosition: CGFloat) -> Int {
let contentHeight = collectionViewContentSize().height - SecondHeaderHeight
let HeightPerChannel = contentHeight / ChannelsMaximum
let channelIndex = max(0, Int((yPosition - SecondHeaderHeight) / HeightPerChannel))
return channelIndex
}
func secondIndexFromXCoordinate(xPosition: CGFloat) -> Int {
let contentWidth = collectionViewContentSize().width - ChannelHeaderWidth
let WidthPerSecond = contentWidth / SecondsMaximum
let secondIndex = max(0, Int((xPosition - ChannelHeaderWidth) / WidthPerSecond))
return secondIndex
}
func indexPathsOfSecondHeaderViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMinY(rect) > SecondHeaderHeight {
return []
}
let minSecondIndex = secondIndexFromXCoordinate(CGRectGetMinX(rect))
let maxSecondIndex = secondIndexFromXCoordinate(CGRectGetMaxX(rect))
return (minSecondIndex...maxSecondIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}
func indexPathsOfChannelHeaderViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMinX(rect) > ChannelHeaderWidth {
return []
}
let minChannelIndex = channelIndexFromYCoordinate(CGRectGetMinY(rect))
let maxChannelIndex = channelIndexFromYCoordinate(CGRectGetMaxY(rect))
return (minChannelIndex...maxChannelIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}
func indexPathsOfVerticalGridLineViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMaxX(rect) < SecondHeaderHeight {
return []
}
let minSecondIndex = secondIndexFromXCoordinate(CGRectGetMinX(rect))
let maxSecondIndex = secondIndexFromXCoordinate(CGRectGetMaxX(rect))
return (minSecondIndex...maxSecondIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}
func indexPathsOfHorizontalGridLineViewsInRect(rect: CGRect) -> [NSIndexPath] {
if CGRectGetMaxY(rect) < ChannelHeaderWidth {
return []
}
let minChannelIndex = channelIndexFromYCoordinate(CGRectGetMinY(rect))
let maxChannelIndex = channelIndexFromYCoordinate(CGRectGetMaxY(rect))
return (minChannelIndex...maxChannelIndex).map { index -> NSIndexPath in
NSIndexPath(forItem: index, inSection: 0)
}
}
func frameForEvent(event: PulseEvent) -> CGRect {
let totalHeight = collectionViewContentSize().height - SecondHeaderHeight
let HeightPerChannel = totalHeight / ChannelsMaximum
let contentWidth = collectionViewContentSize().width - ChannelHeaderWidth
let WidthPerSecond = contentWidth / SecondsMaximum
var frame = CGRectZero
frame.origin.x = ChannelHeaderWidth + WidthPerSecond * CGFloat(event.startSecond)
frame.origin.y = SecondHeaderHeight + HeightPerChannel * CGFloat(event.channel)
frame.size.height = HeightPerChannel
frame.size.width = CGFloat(event.durationInSeconds) * WidthPerSecond
frame = CGRectInset(frame, 2.0, HeightPerChannel/8.0)
return frame
}
}
And this is my ViewController:
import UIKit
import Sapporo
enum PulseHeaderType: String {
case Second = "SecondHeaderView"
case Channel = "ChannelHeaderView"
}
enum GridLineType: String {
case Vertical = "VerticalGridLineView"
case Horizontal = "HorizontalGridLineView"
}
class PulseViewController: UIViewController {
#IBOutlet var collectionView: UICollectionView!
lazy var sapporo: Sapporo = { [unowned self] in
return Sapporo(collectionView: self.collectionView)
}()
override func viewDidLoad() {
super.viewDidLoad()
sapporo.delegate = self
sapporo.registerNibForClass(PulseEventCell)
sapporo.registerNibForSupplementaryClass(PulseHeaderView.self, kind: PulseHeaderType.Second.rawValue)
sapporo.registerNibForSupplementaryClass(PulseHeaderView.self, kind: PulseHeaderType.Channel.rawValue)
let layout = PulseLayout()
layout.registerClass(GridLineView.self, forDecorationViewOfKind: GridLineType.Vertical.rawValue)
layout.registerClass(GridLineView.self, forDecorationViewOfKind: GridLineType.Horizontal.rawValue)
sapporo.setLayout(layout)
let randomEvent = { () -> PulseEvent in
let randomID = arc4random_uniform(10000)
let title = "Event \(randomID)"
let randomChannel = Int(arc4random_uniform(6))
let randomStartSecond = Int(arc4random_uniform(8))
let randomDuration = Int(arc4random_uniform(2) + 1)
return PulseEvent(title: title, channel: randomChannel, startSecond: randomStartSecond, durationInSeconds: randomDuration)
}
let cellmodels = (0...20).map { _ -> PulseEventCellModel in
let event = randomEvent()
return PulseEventCellModel(event: event) { _ in
println("Selected event: \(event.title)")
}
}
sapporo[0].append(cellmodels)
sapporo.bump()
}
}
extension PulseViewController: SapporoDelegate {
func collectionView(collectionView: UICollectionView, viewForSupplementaryElementOfKind kind: String, atIndexPath indexPath: NSIndexPath) -> UICollectionReusableView {
if kind == PulseHeaderType.Second.rawValue {
let view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: PulseHeaderView.reuseIdentifier, forIndexPath: indexPath) as! PulseHeaderView
view.titleLabel.text = "\(indexPath.item)"
return view
}
let view = collectionView.dequeueReusableSupplementaryViewOfKind(kind, withReuseIdentifier: PulseHeaderView.reuseIdentifier, forIndexPath: indexPath) as! PulseHeaderView
view.titleLabel.text = "Channel \(indexPath.item + 1)"
return view
}
}
Can you please help me spot what I am missing?
Regards,
C
I solved this problem a while ago.:
struct Bundle
func setupGestureRecognizer()
func gestureRecognizerShouldBegin
func handleGesture(gesture: UILongPressGestureRecognizer) -> Void
should all go in the ViewController instead of the Layout File.

Resources