UITableViewCell 加载错误的 CAShapeLayer 形状

UITableViewCell Loading Wrong CAShapeLayer Shapes

我有一个自定义单元格,其中有一个 CAShapeLayer 用于绘制箭头形状。不同的箭头(向上、向下、向右)在正确的单元格中正确显示。选择单元格时更改箭头形状按预期工作。

问题:

当显示的单元格的箭头发生变化时(选择单元格时),屏幕外单元格的箭头似乎随机继承了该行为,以在屏幕外单元格中呈现的随机箭头方向结束。屏幕外单元格的其余元素似乎可以正确呈现。

Table 视图控制器:

override func tableView(tableView: UITableView, cellForRowAtIndexPath indexPath: NSIndexPath) -> UITableViewCell {
    let currentCellDescriptor = getCellDescriptorForIndexPath(indexPath)
    let cell = tableView.dequeueReusableCellWithIdentifier(currentCellDescriptor["cellIdentifier"] as! String, forIndexPath: indexPath) as? CustomCell
    let settings = NSUserDefaults.standardUserDefaults()
    if currentCellDescriptor["cellIdentifier"] as! String == "idCellNormal" {
        if let settingName = currentCellDescriptor["settingsKey"] as? String {
            if let labelString = settings.stringForKey(settingName) {
                cell?.headerRightLabel?.text = labelString
            }
            else {
                cell?.headerRightLabel?.text = currentCellDescriptor["settingsValue"] as? String
            }
            if (currentCellDescriptor["isExpanded"] as? Bool == false) {
                    cell?.drawArrow(arrowDirection: "Down")
            }
            else {
                    cell?.drawArrow(arrowDirection: "Up")
            }
        }
        else {
            cell?.headerRightLabel?.text = ""
            cell?.drawArrow(arrowDirection: "Right")
        }
        if let secondaryTitle = currentCellDescriptor["secondaryTitle"] {
            cell?.headerLeftLabel?.text = secondaryTitle as? String
        }
    }
    else if currentCellDescriptor["cellIdentifier"] as! String == "idCellValuePicker" {
        cell?.textLabel?.text = currentCellDescriptor["primaryTitle"] as? String
    }
    cell?.delegate = self
    return cell!
}

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    (self.tableView.cellForRowAtIndexPath(indexPath) as? CustomCell)?.animateAccesoryView()
}

自定义单元格Class:

class CustomCell: UITableViewCell {

    // MARK: IBOutlet Properties

        @IBOutlet weak var textField         : UITextField!
        @IBOutlet weak var headerLeftLabel      : UILabel?
        @IBOutlet weak var headerRightLabel     : UILabel?
        @IBOutlet weak var rightAccessoryView   : UIView?

        var arrowShape = CAShapeLayer()
        var arrowDownPath = UIBezierPath()
        var arrowUpPath = UIBezierPath()
        var arrowRightPath = UIBezierPath()

        var delegate: CustomCellDelegate!



    func drawArrow(arrowDirection direction : String) {
        //Draw Accessory Arrow

            // Create CAShapeLayerS
            self.arrowShape.bounds = CGRect(x: 0, y: 0, width: 32, height: 32)
            self.arrowShape.position = CGPointMake(((rightAccessoryView?.frame.width)!/2), (rightAccessoryView?.frame.height)!/2)

            self.rightAccessoryView?.layer.addSublayer(self.arrowShape)

            //Arrow Down Path
            arrowDownPath.moveToPoint(CGPoint(x: 9, y: 13))
            arrowDownPath.addLineToPoint(CGPoint(x: 16, y: 19))
            arrowDownPath.addLineToPoint(CGPoint(x: 23, y: 13))
            arrowDownPath.addLineToPoint(CGPoint(x: 16, y: 19))
            arrowDownPath.addLineToPoint(CGPoint(x: 9, y: 13))
            arrowDownPath.closePath()

            //Arrow Up Path
            arrowUpPath.moveToPoint(CGPoint(x: 9, y: 19))
            arrowUpPath.addLineToPoint(CGPoint(x: 16, y: 13))
            arrowUpPath.addLineToPoint(CGPoint(x: 23, y: 19))
            arrowUpPath.addLineToPoint(CGPoint(x: 16, y: 13))
            arrowUpPath.addLineToPoint(CGPoint(x: 9, y: 19))
            arrowUpPath.closePath()

            //Arrow Up Path
            arrowRightPath.moveToPoint(CGPoint(x: 13, y: 9))
            arrowRightPath.addLineToPoint(CGPoint(x: 19, y: 16))
            arrowRightPath.addLineToPoint(CGPoint(x: 13, y: 23))
            arrowRightPath.addLineToPoint(CGPoint(x: 19, y: 16))
            arrowRightPath.addLineToPoint(CGPoint(x: 13, y: 9))
            arrowRightPath.closePath()

            //set Arrow Shape (CAShapeLayer)

            switch direction{
            case "Down":
                arrowShape.path = arrowDownPath.CGPath
            case "Up":
                arrowShape.path = arrowUpPath.CGPath
            case "Right":
                arrowShape.path = arrowRightPath.CGPath
            default:
                arrowShape.path = arrowDownPath.CGPath
            }

            arrowShape.strokeColor = UIColor(red: 1, green: 1, blue: 1, alpha: 0.2).CGColor
            arrowShape.lineWidth = 1.5
            arrowShape.lineJoin = kCALineJoinRound
            arrowShape.lineCap = kCALineCapRound
            arrowShape.strokeEnd = 0.5
    }

func animateAccesoryView (){
    let animation = CABasicAnimation(keyPath: "path")
    if (self.arrowShape.path == arrowDownPath.CGPath) {
        animation.toValue = arrowUpPath.CGPath
    }
    else {
        animation.toValue = arrowDownPath.CGPath
    }
    animation.duration = 0.3
    animation.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionLinear)
    animation.fillMode = kCAFillModeBoth
    animation.removedOnCompletion = false
    self.arrowShape.addAnimation(animation, forKey: animation.keyPath)
}

我能够通过在 Table View Cell 子类中使用 prepareForReuse 来解决这个问题。这也适用于 UICollectionViewCell。

override func prepareForReuse() {
    super.prepareForReuse()
    self.arrowShape.removeAllAnimations()
    self.arrowShape.removeFromSuperlayer()
}