SwiftDeveloper SwiftDeveloper - 3 months ago 26
Swift Question

Swift UICollectionView when scrolled disappears label.text and colors are mixed maybe BUG?

Hello I have UICollectionView when scrolled disappears label.text and colors are mixed .

My codes here

CustomCollectionViewCell

import UIKit

@IBDesignable
class CustomCollectionViewCell: UICollectionViewCell {

@IBOutlet weak var label: 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.blackColor().CGColor
self.layer.cornerRadius = 5.0
}
}


CustomCollectionViewLayout

import UIKit


public var CELL_HEIGHT = 22.0
public var CELL_WIDTH = 40.0


class CustomCollectionViewLayout: UICollectionViewLayout {

// Used for calculating each cells CGRect on screen.
// CGRect will define the Origin and Size of the cell.

let STATUS_BAR = UIApplication.sharedApplication().statusBarFrame.height

// Dictionary to hold the UICollectionViewLayoutAttributes for
// each cell. The layout attribtues will define the cell's size
// and position (x, y, and z index). I have found this process
// to be one of the heavier parts of the layout. I recommend
// holding onto this data after it has been calculated in either
// a dictionary or data store of some kind for a smooth performance.
var cellAttrsDictionary = Dictionary<NSIndexPath, UICollectionViewLayoutAttributes>()

// Defines the size of the area the user can move around in
// within the collection view.
var contentSize = CGSize.zero

// Used to determine if a data source update has occured.
// Note: The data source would be responsible for updating
// this value if an update was performed.
var dataSourceDidUpdate = true

override func collectionViewContentSize() -> CGSize {
return self.contentSize
}

override func prepareLayout() {

// Only update header cells.
if !dataSourceDidUpdate {

// Determine current content offsets.
let xOffset = collectionView!.contentOffset.x
let yOffset = collectionView!.contentOffset.y

if collectionView?.numberOfSections() > 0 {
for section in 0...collectionView!.numberOfSections()-1 {

// Confirm the section has items.
if collectionView?.numberOfItemsInSection(section) > 0 {

// Update all items in the first row.
if section == 0 {
for item in 0...collectionView!.numberOfItemsInSection(section)-1 {

// Build indexPath to get attributes from dictionary.
let indexPath = NSIndexPath(forItem: item, inSection: section)

// Update y-position to follow user.
if let attrs = cellAttrsDictionary[indexPath] {
var frame = attrs.frame

// Also update x-position for corner cell.
if item == 0 {
frame.origin.x = xOffset
}

frame.origin.y = yOffset
attrs.frame = frame
}

}

// For all other sections, we only need to update
// the x-position for the fist item.
} else {

// Build indexPath to get attributes from dictionary.
let indexPath = NSIndexPath(forItem: 0, inSection: section)

// Update y-position to follow user.
if let attrs = cellAttrsDictionary[indexPath] {
var frame = attrs.frame
frame.origin.x = xOffset
attrs.frame = frame
}

}
}
}
}


// Do not run attribute generation code
// unless data source has been updated.
return
}

// Acknowledge data source change, and disable for next time.
dataSourceDidUpdate = false

var maxItemInASection: Int?

// 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?.numberOfItemsInSection(section) > 0 {
for item in 0...collectionView!.numberOfItemsInSection(section)-1 {

// Build the UICollectionVieLayoutAttributes for the cell.
let cellIndex = NSIndexPath(forItem: item, inSection: section)
let xPos = Double(item) * CELL_WIDTH
let yPos = Double(section) * CELL_HEIGHT

let cellAttributes = UICollectionViewLayoutAttributes(forCellWithIndexPath: cellIndex)
cellAttributes.frame = CGRect(x: xPos, y: yPos, width: CELL_WIDTH, height: CELL_HEIGHT)

// 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

if maxItemInASection < item {
maxItemInASection = item
}

}
}

}
}

// Update content size.
let contentWidth = Double(maxItemInASection ?? 0) * CELL_WIDTH
let contentHeight = Double(collectionView!.numberOfSections()) * CELL_HEIGHT
self.contentSize = CGSize(width: contentWidth, height: contentHeight)

}

override func layoutAttributesForElementsInRect(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.values.elements {
if CGRectIntersectsRect(rect, cellAttributes.frame) {
attributesInRect.append(cellAttributes)
}
}

// Return list of elements.
return attributesInRect
}

override func layoutAttributesForItemAtIndexPath(indexPath: NSIndexPath) -> UICollectionViewLayoutAttributes? {
return cellAttrsDictionary[indexPath]!
}

override func shouldInvalidateLayoutForBoundsChange(newBounds: CGRect) -> Bool {
return true
}

}


HttpManager

import Foundation

class HttpManager {

class func getRequest(url: String, parameter: Dictionary <String, AnyObject>?, completionHandler: (responseData: [Item]?, errorMessage: String?) -> ()) {

guard let url = NSURL(string: url) else {
completionHandler(responseData: .None, errorMessage: "URL string was malformed")
return
}

let task = NSURLSession.sharedSession().dataTaskWithURL(url) { (data, response, error) in

guard error == nil else {
completionHandler(responseData: .None, errorMessage: error?.localizedDescription)
return
}

guard let data = data else {
completionHandler(responseData: .None, errorMessage: "Empty Data")
return
}

guard let jsonSerialization = try? NSJSONSerialization.JSONObjectWithData(data, options:[]), jsonArray = jsonSerialization as? NSArray else {
completionHandler(responseData: .None, errorMessage: "NSJSONSerialization error")
return
}

var items = [Item]()

jsonArray.forEach({ (eachItem) -> () in
guard let dic = eachItem as? NSDictionary else { return }
guard let service = dic["Seats"] as? String, base = dic["Base"] as? String else {
completionHandler(responseData: .None, errorMessage: "JSON structure missmatch")
return
}

let services = service.componentsSeparatedByString(",")
let item = Item(base: base, services: services)
items.append(item)
})

completionHandler(responseData: items, errorMessage: .None)
}

task.resume()
}
}


CustomCollectionViewController

class CustomCollectionViewController: UIViewController {

@IBOutlet weak var collectionView: UICollectionView!


var items = [Item]()

override func viewDidLoad() {
super.viewDidLoad()

// Uncomment the following line to preserve selection between presentations
// self.clearsSelectionOnViewWillAppear = false

getDataFromServer()
}

func getDataFromServer() {

HttpManager.getRequest(url, parameter: .None) { [weak self] (responseData, errorMessage) -> () in

guard let strongSelf = self else { return }

guard let responseData = responseData else {
print("Get request error \(errorMessage)")
return
}

guard let customCollectionViewLayout = strongSelf.collectionView?.collectionViewLayout as? CustomCollectionViewLayout else { return }

strongSelf.items = responseData
customCollectionViewLayout.dataSourceDidUpdate = true

NSOperationQueue.mainQueue().addOperationWithBlock({ () -> Void in
strongSelf.collectionView!.reloadData()
})
}
}
}

// MARK: UICollectionViewDataSource
extension CustomCollectionViewController {

func numberOfSectionsInCollectionView(collectionView: UICollectionView) -> Int {
return items.count
}

func collectionView(collectionView: UICollectionView, numberOfItemsInSection section: Int) -> Int {
return items[section].services.count + 1
}


DID SELECT CODES

func collectionView(collectionView: UICollectionView, didSelectItemAtIndexPath indexPath: NSIndexPath) {
// You must call super to animate selection

if indexPath.item == 0 {
print(items[indexPath.section].base)

} else {

let clickeditem = items[indexPath.section].services[indexPath.item - 1]



if let myStringc: String = items[indexPath.section].services[indexPath.item - 1] {
var myStringArrc = myStringc.componentsSeparatedByString("*")




let satimdurum:Int = Int(myStringArrc[3])!
let sirano:Int = Int(myStringArrc[0])!



if sirano == 1 || sirano == 2 {

if sirano == 2 {



if satimdurum == 0 {


if koltuksiraid.contains(clickeditem) {

if let index = koltuksiraid.indexOf(clickeditem) {
koltuksiraid.removeAtIndex(index)
}


let selectedCell:UICollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor.orangeColor()


}else{

koltuksiraid.append(clickeditem)

let selectedCell:UICollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor(red: 62/256, green: 211/256, blue: 238/256, alpha: 1)


}

}else{


}


}else{


if satimdurum == 0 {



if koltuksiraid.contains(clickeditem) {

if let index = koltuksiraid.indexOf(clickeditem) {
koltuksiraid.removeAtIndex(index)
}


let selectedCell:UICollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor.greenColor()


}else{

koltuksiraid.append(clickeditem)

let selectedCell:UICollectionViewCell = collectionView.cellForItemAtIndexPath(indexPath)!
selectedCell.contentView.backgroundColor = UIColor(red: 62/256, green: 211/256, blue: 238/256, alpha: 1)


}
}else{


}


}
}

}
}
print(koltuksiraid)



}


Latest collectionView Codes After @pkc456 s answer.

func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CustomCollectionViewCell

cell.label.font.fontWithSize(12)
cell.label.textColor = UIColor.whiteColor()

if indexPath.item == 0 {

cell.label.text = items[indexPath.section].base
cell.label.frame.size.width = 30
cell.label.frame.size.height = 30
cell.label.layer.borderColor = UIColor.clearColor().CGColor
cell.contentView.backgroundColor = UIColor.clearColor()

} else {

if let myStringc: String = items[indexPath.section].services[indexPath.item - 1] {
var myStringArrc = myStringc.componentsSeparatedByString("*")

let satimdurum:Int = Int(myStringArrc[3])!
let sirano:Int = Int(myStringArrc[0])!

if sirano == 1 || sirano == 2 {

cell.label.backgroundColor = (satimdurum == 1) ? UIColor.redColor() : UIColor.orangeColor()
cell.contentView.backgroundColor = (satimdurum == 1) ? UIColor.redColor() : UIColor.greenColor()
cell.label.layer.borderColor = UIColor.blackColor().CGColor
cell.alpha = 1

if sirano == 2 {
cell.frame.size.width = 80
cell.layer.frame.size.width = 80
CELL_WIDTH = 80.0
CELL_HEIGHT = 22.0

if satimdurum == 1 {

cell.label.alpha = 1
cell.label.layer.borderColor = UIColor.redColor().CGColor
cell.contentView.backgroundColor = UIColor.redColor()
cell.label.text = myStringArrc[1]

}else{





if myStringArrc[1] == "NULL" {
cell.label.alpha = 0
cell.label.layer.borderColor = UIColor.clearColor().CGColor
cell.label.frame.size.width = 0
cell.label.frame.size.height = 0
cell.contentView.backgroundColor = UIColor.clearColor()
}else{
cell.label.alpha = 1
cell.label.backgroundColor = UIColor.orangeColor()//Or put orange color as per your logic based on myStringArrc
cell.label.frame.size.width = 40
cell.label.frame.size.height = 40
cell.contentView.backgroundColor = UIColor.orangeColor()//Or put orange color as per your logic based on myStringArrc
cell.label.text = myStringArrc[1]
}


}

cell.label.text = "\(myStringArrc[1])-\(myStringArrc[5])"
}else{

cell.frame.size.width = 40
cell.layer.frame.size.width = 40
CELL_HEIGHT = 22.0
CELL_WIDTH = 40

if satimdurum == 1 {

cell.label.alpha = 1
cell.label.layer.borderColor = UIColor.redColor().CGColor
cell.contentView.backgroundColor = UIColor.redColor()
cell.label.text = myStringArrc[1]

}else{




if myStringArrc[1] == "NULL" {
cell.label.alpha = 0
cell.label.backgroundColor = UIColor.clearColor()
cell.label.layer.borderColor = UIColor.clearColor().CGColor
cell.label.frame.size.width = 0
cell.label.frame.size.height = 0
cell.contentView.backgroundColor = UIColor.clearColor()
}else{
cell.label.text = myStringArrc[1]
cell.label.alpha = 1
cell.label.frame.size.width = 40
cell.label.frame.size.height = 40
cell.contentView.backgroundColor = UIColor.greenColor()//Or put orange color as per your logic based on myStringArrc
}
}
}
}else{
cell.label.alpha = 0
cell.label.layer.borderColor = UIColor.clearColor().CGColor
cell.label.frame.size.width = 0
cell.label.frame.size.height = 0
cell.contentView.backgroundColor = UIColor.clearColor()
cell.alpha = 0
}

}
}

cell.label.backgroundColor = UIColor.clearColor()

return cell
}

}


And latest issuees after new collectionview codes.

Answer

Did select cell (blue color) after scroll missing

Either you are adding or removing clickeditem from koltuksiraid array on didSelectItemAtIndexPath

koltuksiraid.removeAtIndex(index)
koltuksiraid.append(clickeditem)

When you scroll cells are reusing view and call cellForItemAtIndexPath. You should add a check to determine the cell color here for e.g

let color = koltuksiraid.contains(myStringc) ? UIColor(red: 62/256, green: 211/256, blue: 238/256, alpha: 1) : UIColor.orangeColor()

Scrolled after cell label goes right bottom

Cell label should be center position of the cell no mater what the cell size is. So do it form the storyboard. Delete all the label frame related code from your viewController

Some double width cell looking like this

This is a big issue. Cells are layout before cellForItemAtIndexPath. You can not change frame size of the cells here. Right place is prepareLayout() method of your CustomCollectionViewLayout. Here when you calculate position of each item you need to check which item should be double.

Delete all the cell frame related code from your cellForItemAtIndexPath. Create a protocol

protocol CustomCollectionViewDelegateLayout: NSObjectProtocol {

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, widthForItemAtIndexPath indexPath: NSIndexPath) -> CGFloat
}

In your viewController implemented this protocol method. Return value will be the width for the given indexPath

extension CustomCollectionViewController: CustomCollectionViewDelegateLayout {

    func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, widthForItemAtIndexPath indexPath: NSIndexPath) -> CGFloat {

        //from indexPath.section and indexPath.item identify double width item
        if sirano == 2 && satimdurum == 0 {
            return regularWidth * 2
        }
        return regularWidth
    }
}

Made a demo project with xcode 7.2 here at https://github.com/rishi420/UICollectionviewsample