setNeedsDisplay() 没有更新 collectionViewCell 子视图的 drawRect

setNeedsDisplay() is not updating collectionViewCell subView's drawRect

我正在尝试在 collectionView 单元格内显示进度指示器。为此,有一个后台线程向主线程发送通知以更新进度指示器。

在主视图控制器中...

    func updateProgressIndicator(notification:NSNotification){
        let userInfo = notification.userInfo! as NSDictionary
        let date = userInfo["date"] as! NSDate
        let percentComplete = userInfo["percent"] as! Double

        self.progressIndicator.text = "\(percentComplete)%" // this works
        let dateIndex = self.calendarDates.indexOf(date)
        let indexPath = NSIndexPath(forItem: dateIndex!, inSection: 0)
        let cell = self.collectionView.dequeueReusableCellWithReuseIdentifier("DateCell", forIndexPath: indexPath) as! DateCell
        cell.showProgress()
    }

该函数定位要更新的单元格的indexPath。然后调用单元格的 showProgress 方法。

class DateCell: UICollectionViewCell {
    @IBOutlet weak var dotGraph: DotGraphView!

    func showProgress(){
        print("   DateCell showProgress") // this does get printed
        self.setNeedsDisplay()
    }

    override func drawRect(rect: CGRect) {
        print("   DateCell drawRect") // this never gets printed
        //drawing functions go here
    }
}

为正确的单元格调用 showProgress() 方法并显示打印消息。但是,当 showProgress 方法调用 setNeedsDisplay() 时,永远不会执行 drawRect 函数。

我更新单元格的唯一方法是使用 reloadRowsAtIndexPaths 完全重新加载单元格,但这应该是不必要的。

关于如何调用 drawRect 函数有什么想法吗?

你说 showProgress() 是为正确的单元格调用的,但这似乎不太可能。当您调用 dequeueReusableCellWithReuseIdentifier(_:forIndexPath:) 时,我希望您获得与集合视图当前显示的实例不同的 DateCell 实例。显示的那个正在使用中,因此它不会从 dequeue... 方法中 returned。您可以通过在单元格上使用 NSLog 来测试我对此是否正确。我希望这个地址与您在 cellForItemAtIndexPath() 中 return 编辑的地址不同。

与其将单元格出队,不如将单元格放在 属性 中,这样每个人都可以使用相同的单元格。这也是您应该 return 在 cellForItemAtIndexPath() 中的单元格。

正如 Rob 所建议的那样,dequeueReusableCellWithReuseIdentifier(_:forIndexPath:) 导致了问题。在创建单元格时将其存储在字典中,允许直接引用它。这意味着 drawRect() 将被调用 setNeedsDisplay()

以下是更新后的功能...

var calendarDateCells:[NSDate:DateCell] = [:]

func updateProgressIndicator(notification:NSNotification){
    let userInfo = notification.userInfo! as NSDictionary
    let date = userInfo["date"] as! NSDate
    let myCell = self.calendarDateCells[date]
    if(myCell != nil){
        myCell!.showProgress()
    }
}


func collectionView(collectionView: UICollectionView, cellForItemAtIndexPath indexPath: NSIndexPath) -> UICollectionViewCell {
    let cell = collectionView.dequeueReusableCellWithReuseIdentifier("DateCell", forIndexPath: indexPath) as! DateCell
    let date = calendarDates[indexPath.item]
    self.calendarDateCells[date] = cell
    return cell
}