滚动时Swift UICollectionView消失label.text和颜色混合可能BUG?

时间:2016-08-17 08:25:57

标签: ios swift uicollectionview

你好我滚动时有UICollectionView消失了label.text和颜色混合。

我的代码在这里

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)



      }

最新的集合查看代码@ pkc456的回答。

    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
    }

 }

最新问题是在新的collectionview代码之后。

3 个答案:

答案 0 :(得分:3)

  1. 您正在statring中设置cell.frame.size.width, CELL_WIDTH, layer.width并在if sirano == 2 {循环结束。我删除了这个副本。
  2. 由于cell.label.font.fontWithSize对所有人来说都很常见。我把它放在一开始。
  3. label.backgroundColor设置三次。我使用三元运算符更新嵌套的if satimdurum == 1条件,如下所示。
  4. 您在myStringArrc[1] is not NULL时未设置值。所以我更新了if-else条件语句,如下所示

    cell.label.backgroundColor =(satimdurum == 1)? UIColor.redColor():UIColor.orangeColor()

    cell.contentView.backgroundColor =(satimdurum == 1)? UIColor.redColor():UIColor.greenColor()

  5. 我删除了条件循环上方的静态行,因为无论上限条件如何,这些值都会被设置。

  6. 同时将cell.label.text = "\(myStringArrc[1])-\(myStringArrc[5])"移至正确的状态。在sirano == 2
  7. 时始终在标签上设置此值
  8. 继续前进到其他条件,再次检查if satimdurum == 1。在上面的第4点已经检查过这个条件。所以我在if-loop(if sirano == 1 || sirano == 2)的初始阶段写这个检查。

  9. 继续前进到下一个if myStringArrc[1] == "NULL"循环,我发现if-else和if-else之间的检查没有任何区别。在sirano == 2else时,您正在做同样的事情。但是我可能有可能在这里错过了你的一些业务逻辑,所以我把第二个条件保持原样,并在else loop中添加遗漏的代码。

  10. 更新了cellForItemAtIndexPath的代码: -

    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
        } 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 = 40
                        cell.layer.frame.size.width = 40
                        CELL_HEIGHT = 22.0
                        CELL_WIDTH = 40
    
                        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.alpha = 1
                            cell.label.backgroundColor = UIColor.redColor()//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.redColor()//Or put orange color as per your logic based on myStringArrc
                            cell.label.text = myStringArrc[1]
                        }
    
                        cell.label.text = "\(myStringArrc[1])-\(myStringArrc[5])"
                    }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.backgroundColor = UIColor.redColor()//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.redColor()//Or put orange color as per your logic based on myStringArrc
                        }
                    }
                }else{
                    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()
                    cell.alpha = 0
                }
    
            }
        }
        return cell
    }
    

答案 1 :(得分:1)

  

滚动丢失后选择了单元格(蓝色)

您要在clickeditem上的koltuksiraid数组中添加或删除didSelectItemAtIndexPath

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

滚动单元格时,重复使用视图并调用cellForItemAtIndexPath。您应该添加一个检查以确定此处的单元格颜色,例如

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

细胞标签右下方滚动

细胞标记应该是细胞的中心位置,无论细胞大小是多少。所以它来自storyboard。从viewController

中删除所有与标签框架相关的代码
  

一些双倍宽度的单元格看起来像这样

这是一个大问题。单元格在cellForItemAtIndexPath之前布局。您无法在此更改单元格的帧大小。正确的位置是prepareLayout()的{​​{1}}方法。在这里,当你计算每个项目的位置时,你需要检查哪个项目应该加倍。

CustomCollectionViewLayout删除所有与细胞框架相关的代码。创建cellForItemAtIndexPath

protocol

protocol CustomCollectionViewDelegateLayout: NSObjectProtocol { func collectionView(collectionView: UICollectionView, layout collectionViewLayout: UICollectionViewLayout, widthForItemAtIndexPath indexPath: NSIndexPath) -> CGFloat } 实施此协议方法中。返回值将是给定viewController

的宽度
indexPath

https://github.com/rishi420/UICollectionviewsample

处制作了一个带有xcode 7.2的演示项目

答案 2 :(得分:0)

仔细查看CustomCollectionViewController类中此函数的实现:

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

您可以调用此方法获取新单元格:

let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CustomCollectionViewCell

没关系。但它并不是每次都给你一个新的空白细胞。如果在此之前使用过该单元格,则可以使用与上次相同的颜色和标签文本(以及其他所有内容)来获取该单元格。

所以你需要做的就是完成该函数中的逻辑并确保你关心的每个属性在每个时间设置。举例来说,函数中的最后一个else块 - 它没有设置cell.label.text - 并且不能保证它是空的。这就是为什么文字和颜色随着细胞被iOS重新绘制而跳跃的原因。

有时,如果单元格逻辑很复杂,最好在单元格出列后立即清除旧格式。以下是一些属性的示例:

    let cell = collectionView.dequeueReusableCellWithReuseIdentifier(reuseIdentifier, forIndexPath: indexPath) as! CustomCollectionViewCell
    cell.label.text = nil
    cell.label.backgroundColor = UIColor.clearColor()
    cell.contentView.backgroundColor = UIColor.clearColor()