iOS collectionView.sizeForItemAtIndexPath Breaks On Anything Before iPhone 6

Jon Farmer picture Jon Farmer · Feb 20, 2015 · Viewed 14k times · Source

I am brand new to iOS development and I am trying to port a project I have on Android to iOS. I am trying to construct a collectionView in code as part of the implementation. The thing is as the data in each cell in the collection view can be different string sizes each cell can be a different size to it's neighbour. I am experimenting with the attached code but I have noticed that with an iPhone 6 either a physical device or in the simulator the UI looks as expected..anything else it looks horribly broken. It seems to be the sizeForIndexItemAtPath that is breaking it. Any ideas anyone? TIA

  import UIKit

  class ViewController: UIViewController,       UICollectionViewDelegateFlowLayout, UICollectionViewDataSource {

    var collectionView: UICollectionView?
    var thisCellHeight: CGFloat = 0.0

    override func viewDidLoad() {
        super.viewDidLoad()
        // Do any additional setup after loading the view, typically from a nib.
        let screenSize: CGRect = UIScreen.mainScreen().bounds
        let screenWidth = screenSize.width
        let screenHeight = screenSize.height

        var thisWidth = screenWidth - 10

        let layout: UICollectionViewFlowLayout = UICollectionViewFlowLayout()
        layout.sectionInset = UIEdgeInsets(top: 70, left: 10, bottom: 10, right: 10)
        layout.itemSize = CGSize(width: thisWidth, height: 120)
        collectionView = UICollectionView(frame: self.view.frame, collectionViewLayout: layout)
        //collectionView!.backgroundView?.backgroundColor = UIColor.blueColor()
        collectionView!.dataSource = self
        collectionView!.delegate = self
        collectionView!.registerClass(UICollectionViewCell.self, forCellWithReuseIdentifier: "Cell")
        collectionView!.backgroundColor = hexStringToUIColor("#15ADFF")
        self.view.addSubview(collectionView!)
    }

    override func didReceiveMemoryWarning() {
        super.didReceiveMemoryWarning()
        // Dispose of any resources that can be recreated.
    }

    func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
        return 14
    }

    func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {



        let cell = collectionView.dequeueReusableCellWithReuseIdentifier("Cell", forIndexPath: indexPath) as UICollectionViewCell
        cell.backgroundColor = UIColor.whiteColor()

        var typeLabel = UILabel(frame: CGRectMake(10, 0, 200, 21))
        typeLabel.text = "Card Type"
        typeLabel.font = typeLabel.font.fontWithSize(20)
        cell.addSubview(typeLabel)

        var titleLabel = UILabel(frame: CGRectMake(10, 25, 300, 21))

        titleLabel.text = "This Is The Article Title. This Is The Article Title. This Is The Article Title. This Is The Article Title."
        titleLabel.font = titleLabel.font.fontWithSize(20)
        titleLabel.numberOfLines = 0
        titleLabel.sizeToFit()
        self.thisCellHeight = CGFloat(titleLabel.frame.height)
        println("The title text is \(self.thisCellHeight) high")
        cell.addSubview(titleLabel)

        var authorLabel = UILabel(frame: CGRectMake(10, thisCellHeight + 30, 200, 21))
        authorLabel.text = "This Is The Article Author"
        authorLabel.font = authorLabel.font.fontWithSize(15)
        cell.addSubview(authorLabel)

        var timestampLabel = UILabel(frame: CGRectMake(10, thisCellHeight + 50, 200, 21))
        timestampLabel.text = "This Is The Timestamp"
        timestampLabel.font = timestampLabel.font.fontWithSize(15)
        cell.addSubview(timestampLabel)

        return cell
    }

    func hexStringToUIColor (hex:String) -> UIColor {
        var cString:String = hex.stringByTrimmingCharactersInSet(NSCharacterSet.whitespaceAndNewlineCharacterSet() as NSCharacterSet).uppercaseString

        if (cString.hasPrefix("#")) {
            cString = cString.substringFromIndex(advance(cString.startIndex, 1))
        }

        if (countElements(cString) != 6) {
            return UIColor.grayColor()
        }

        var rgbValue:UInt32 = 0
        NSScanner(string: cString).scanHexInt(&rgbValue)

        return UIColor(
            red: CGFloat((rgbValue & 0xFF0000) >> 16) / 255.0,
            green: CGFloat((rgbValue & 0x00FF00) >> 8) / 255.0,
            blue: CGFloat(rgbValue & 0x0000FF) / 255.0,
            alpha: CGFloat(1.0)
        )
    }

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {


        return CGSizeMake(320, 350)


    }



}

Answer

Dave Leverton picture Dave Leverton · Feb 20, 2015

You're setting the item size on the layout to be :

layout.itemSize = CGSize(width: thisWidth, height: 120)

And you're also using the delegate method

func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, sizeForItemAtIndexPath indexPath: NSIndexPath) -> CGSize {
    return CGSizeMake(320, 350)
}

The first is being overridden by the second. layout.itemSize is the default size for each item, if the delegate method sizeForItemAtIndexPath isn't overridden. You're overriding the layout.itemSize with something which looks to be completely different. Try just removing the delegate function sizeForItemAtIndexPath, does this do what you expect?