CAShapeLayer 动画问题

Posted

技术标签:

【中文标题】CAShapeLayer 动画问题【英文标题】:CAShapeLayer animation issue 【发布时间】:2020-02-06 00:27:22 【问题描述】:

我有一个用于绘制气泡的 CAShapeLayer(如下)。根据设计,这一切都很好,但是当我开始使用 tableView.beginUpdates() 和 tableView.endUpdates() 在 tableView 中调整它的大小时。我最终暂时将旧图层变为黑色。这看起来很糟糕。我真的很困惑如何解决这个问题。有点感觉图层是黑色的,填充像面具一样覆盖在它们上面。 我已经尝试了几件事来在不同的地方添加/删除图层。等等,但结果总是这样。

video to describe it

override func draw(_ rect: CGRect) 
  self.layer.backgroundColor = UIColor.clear.cgColor
  let fillColor: UIColor = self.shapeColor

  let shapeLayer = CAShapeLayer()
  shapeLayer.contentsScale = UIScreen.main.scale

  let path = UIBezierPath()
  shapeLayer.fillColor = fillColor.cgColor

  let width = self.bounds.size.width
  let height = self.bounds.size.height

  path.move(to: CGPoint(x: 3.02, y: height * 0.5))
  path.move(to: CGPoint(x: 3.02, y: 24.9))
  path.addLine(to: CGPoint(x: 3.02, y: 14.62))
  path.addLine(to: CGPoint(x: 3.02, y: 14.62))
  path.addCurve(to: CGPoint(x: 17.64, y: -0), controlPoint1: CGPoint(x: 3.02, y: 6.55),controlPoint2: CGPoint(x: 9.57, y: -0))
  path.addLine(to: CGPoint(x: width - 15.85, y: 0))
  path.addLine(to: CGPoint(x: width - 15.85, y: 0))
  path.addCurve(to: CGPoint(x: width, y: 14.62), controlPoint1: CGPoint(x: width - 7.77, y: 0), controlPoint2: CGPoint(x: width, y: 6.55))
  path.addLine(to: CGPoint(x: width, y: height - 15.1))
  path.addLine(to: CGPoint(x: width, y: height - 15.1))
  path.addCurve(to: CGPoint(x: width - 15.85, y: height), controlPoint1: CGPoint(x: width, y: height - 7.03), controlPoint2: CGPoint(x: width - 7.77, y: height))
  path.addLine(to: CGPoint(x: 17.64, y: height))
  path.addLine(to: CGPoint(x: 17.64, y: height))
  path.addCurve(to: CGPoint(x: 8.69, y: height - 3.56), controlPoint1: CGPoint(x: 14.39, y: height),controlPoint2: CGPoint(x: 11.24, y: height - 1.57))
  path.addLine(to: CGPoint(x: 8.79, y: height - 3.46))
  path.addCurve(to: CGPoint(x: 0, y: height), controlPoint1: CGPoint(x: 7.27, y: height - 1.27), controlPoint2: CGPoint(x: 3.84, y: height + 0.51))
  path.addCurve(to: CGPoint(x: 3.02, y: height - 14.1), controlPoint1: CGPoint(x: 4.06, y: height - 4.22), controlPoint2: CGPoint(x: 3.02, y: height - 9.62))
  path.close()

  if self.reverted 
    let mirrorOverXOrigin: CGAffineTransform = CGAffineTransform(scaleX: -1.0, y: 1.0);
    let translate: CGAffineTransform = CGAffineTransform(translationX: width, y: 0);

    // Apply these transforms to the path
    path.apply(mirrorOverXOrigin)
    path.apply(translate)
  

  path.fill()

  shapeLayer.path = path.cgPath
  shapeLayer.rasterizationScale = UIScreen.main.scale
  shapeLayer.shouldRasterize = true

  if let bubbleLayer = self.bubbleLayer 
    self.layer.replaceSublayer(bubbleLayer, with: shapeLayer)
   else 
    self.layer.insertSublayer(shapeLayer, at: 0)
  
  self.bubbleLayer = shapeLayer
 

 shapeLayer.path = path.cgPath
 shapeLayer.rasterizationScale = UIScreen.main.scale
 shapeLayer.shouldRasterize = true

 self.layer.insertSublayer(shapeLayer, at: 0)
 self.bubbleLayer?.removeFromSuperlayer()
 self.bubbleLayer = shapeLayer

【问题讨论】:

【参考方案1】:

您的解决方案无法正常工作。 Draw(_ :) 在动画块期间不会被调用。在tableView.endUpdates()之后绘制,在UITableView结束动画之后。

Draw(_ :) - 我认为你根本不应该使用它来满足你的需要。

如果我可以向您推荐一些解决方案:

1) 在awakeFromNib:

override func awakeFromNib() 
    super.awakeFromNib()

    self.contentView.backgroundColor = self.shapeColor
    self.contentView.layer.cornerRadius = 15

    /** make  left view and attach it to the left bottom anchors with fixed size and draw into this view the shape of your left arrow***/
    self.leftArrowView.isHidden = self.isReverted
    /** make  right view and attach it to the right bottom anchors with fixed size and draw into this view the shape of your right arrow***/
    self.rightArrowView.isHidden = !self.isReverted

2) 在prepareForReuse:

override func prepareForReuse() 
    super.prepareForReuse()
    self.leftArrowView.isHidden = self.isReverted
    self.rightArrowView.isHidden = !self.isReverted

这应该会导致您的单元格会顺利更改大小。

【讨论】:

抱歉,今天我才有机会测试这个。我刚试过这个,我仍然有同样的问题。问题不是箭头,而是单元格的高度发生变化时。它的动画,或摆脱黑色的形状。 (你有没有看到视频很难解释)

以上是关于CAShapeLayer 动画问题的主要内容,如果未能解决你的问题,请参考以下文章

使用 CAShapeLayer 创建的动画圆的 CAGradientLayer 问题

UIBezierPath + CAShapeLayer - 填充一个圆圈的动画[重复]

CAShapeLayer 动画路径毛刺/闪烁(从椭圆到矩形并返回)

CAShapeLayer 动画无需更新路径

CAShapeLayer 路径动画——缩小圆

CAShapeLayer 路径动画