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()
}
我有一个自定义单元格,其中有一个 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()
}