Tim*_*Tim 2 cabasicanimation cashapelayer ios swift
我有一个CAShapeLayer()顶部有渐变的动画,但不知何故它看起来如下图所示:

怎么看起来是这个样子?
我的代码:
override func viewDidLayoutSubviews() {
displayLine()
}
override func viewDidAppear(_ animated: Bool) {
animateStroke()
}
func displayLine() {
let trackLayer = CAShapeLayer()
let rect = CGRect(x: topView.frame.width * 0.15, y: topView.frame.size.height / 1.5, width: topView.frame.width * 0.7, height: 2)
let path = UIBezierPath(roundedRect: rect, cornerRadius: 1)
trackLayer.path = path.cgPath
trackLayer.strokeColor = UIColor.groupTableViewBackground.cgColor
trackLayer.lineWidth = 3
trackLayer.fillColor = UIColor.clear.cgColor
shapeLayer.path = path.cgPath
shapeLayer.strokeColor = UIColor.green.cgColor
shapeLayer.lineWidth = 4
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.strokeEnd = 0
topView.layer.addSublayer(trackLayer)
topView.layer.addSublayer(shapeLayer)
let color = UIColor(red: 11/255, green: 95/255, blue: 244/255, alpha: 1).cgColor
let sndColor = UIColor(red: 255/255, green: 87/255, blue: 87/255, alpha: 1).cgColor
gradient.colors = [color, sndColor]
gradient.locations = [0.0, 1.0]
gradient.startPoint = CGPoint(x: 0, y: 0)
gradient.endPoint = CGPoint(x: 1, y: 0)
gradient.frame = topView.bounds
gradient.mask = shapeLayer
topView.layer.addSublayer(gradient)
}
func animateStroke() {
if !animated {
animated = true
let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")
var value: Double?
let distance = currLeasingCar!.currentKm - currLeasing!.startKm
value = Double(distance) / Double(finalKm)
basicAnimation.toValue = value
basicAnimation.duration = 1.5
basicAnimation.fillMode = .forwards
basicAnimation.isRemovedOnCompletion = false
basicAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)
shapeLayer.add(basicAnimation, forKey: "lineStrokeAnimation")
}
}
Run Code Online (Sandbox Code Playgroud)
问题是您的路径是圆角矩形。在您与我们分享的图像中,\xe2\x80\x99 可能有大约 2-3% 的描边。将其更改为描边 90%,您\xe2\x80\x99 会看到它尝试绘制一个宽且极短的圆角矩形,例如:
\n\n\n\n相反,只需将路径设为一条线,它就会按预期工作:
\n\nlet path = UIBezierPath()\n\nlet bounds = topView.bounds\npath.move(to: CGPoint(x: bounds.minX + bounds.width * 0.15, y: bounds.minY + bounds.height / 1.5))\npath.addLine(to: CGPoint(x: bounds.minX + bounds.width * 0.85, y: bounds.minY + bounds.height / 1.5))\nRun Code Online (Sandbox Code Playgroud)\n\n您可能还想将形状图层的盖子变圆:
\n\ntrackLayer.lineCap = .round // or whatever you want\nshapeLayer.lineCap = .round\nRun Code Online (Sandbox Code Playgroud)\n\n当然,这个改变失去了你原来路径的2点高度,所以如果你想让这些形状层\xe2\x80\x99s更厚,只需增加它们各自的高度即可lineWidth值即可。
一些不相关的观察结果:
\n\nviewDidLayoutSubviews()并且viewDidAppear(_:)应该打电话给他们super实现。
viewDidLayoutSubviews()可以被多次调用,所以你不想实例化一个新的trackLayer每次都实例化一个新的。或者,如果您这样做,请确保删除前一个。
添加子视图/子图层时,谨慎使用bounds而不是frame. 在这种情况下,它可能并不重要,但在某些情况下,您可能会遇到各种奇怪的问题,因为frame在视图\xe2\x80\x99s超级视图\xe2\x80\x99s坐标系中,而bounds是相关视图的坐标系。
就我个人而言,如果您要将这段代码保留在视图控制器中,我\xe2\x80\x99d 建议:
\n\nviewDidLoad;viewDidLayoutSubviews;更好的是,所有这些动画代码根本不属于 app\xe2\x80\x99s 视图控制器,而是一个UIView子类(或子视图控制器)。
因此,也许:
\n\n@IBDesignable\npublic class GradientProgressView: UIView {\n\n private var shapeLayer: CAShapeLayer = {\n let shapeLayer = CAShapeLayer()\n shapeLayer.strokeColor = UIColor.green.cgColor\n shapeLayer.fillColor = UIColor.clear.cgColor\n shapeLayer.lineCap = .round\n return shapeLayer\n }()\n\n private var trackLayer: CAShapeLayer = {\n let trackLayer = CAShapeLayer()\n trackLayer.strokeColor = UIColor.groupTableViewBackground.cgColor\n trackLayer.fillColor = UIColor.clear.cgColor\n trackLayer.lineCap = .round\n return trackLayer\n }()\n\n private var gradient: CAGradientLayer = {\n let gradient = CAGradientLayer()\n\n let color = UIColor(red: 11/255, green: 95/255, blue: 244/255, alpha: 1).cgColor\n let sndColor = UIColor(red: 255/255, green: 87/255, blue: 87/255, alpha: 1).cgColor\n\n gradient.colors = [color, sndColor]\n gradient.locations = [0.0, 1.0]\n gradient.startPoint = CGPoint(x: 0, y: 0)\n gradient.endPoint = CGPoint(x: 1, y: 0)\n\n return gradient\n }()\n\n override init(frame: CGRect = .zero) {\n super.init(frame: frame)\n addSubLayers()\n }\n\n required init?(coder aDecoder: NSCoder) {\n super.init(coder: aDecoder)\n addSubLayers()\n }\n\n override public func layoutSubviews() {\n super.layoutSubviews()\n updatePaths()\n }\n\n override public func prepareForInterfaceBuilder() {\n super.prepareForInterfaceBuilder()\n setProgress(0.75, animated: false)\n }\n\n public func setProgress(_ progress: CGFloat, animated: Bool = true) {\n if animated {\n animateStroke(to: progress)\n } else {\n shapeLayer.strokeEnd = progress\n }\n }\n}\n\nprivate extension GradientProgressView {\n func addSubLayers() {\n layer.addSublayer(trackLayer)\n layer.addSublayer(shapeLayer)\n layer.addSublayer(gradient)\n }\n\n func updatePaths() {\n let lineWidth = bounds.height / 2\n trackLayer.lineWidth = lineWidth * 0.75\n shapeLayer.lineWidth = lineWidth\n\n let path = UIBezierPath()\n path.move(to: CGPoint(x: bounds.minX + lineWidth / 2, y: bounds.midY))\n path.addLine(to: CGPoint(x: bounds.maxX - lineWidth / 2, y: bounds.midY))\n\n trackLayer.path = path.cgPath\n shapeLayer.path = path.cgPath\n\n gradient.frame = bounds\n gradient.mask = shapeLayer\n }\n\n func animateStroke(to progress: CGFloat) {\n let key = "lineStrokeAnimation"\n\n layer.removeAnimation(forKey: key)\n\n let basicAnimation = CABasicAnimation(keyPath: "strokeEnd")\n\n basicAnimation.toValue = progress\n basicAnimation.duration = 1.5\n basicAnimation.fillMode = .forwards\n basicAnimation.isRemovedOnCompletion = false\n basicAnimation.timingFunction = CAMediaTimingFunction(name: .easeInEaseOut)\n\n shapeLayer.add(basicAnimation, forKey: key)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n\n那么视图控制器只是:
\n\nclass ViewController: UIViewController {\n\n @IBOutlet weak var gradientProgressView: GradientProgressView!\n\n override func viewDidAppear(_ animated: Bool) {\n super.viewDidAppear(animated)\n updateProgress()\n }\n\n ...\n}\n\n// MARK: - Progress related methods\n\nprivate extension ViewController {\n func updateProgress() {\n let distance = currLeasingCar!.currentKm - currLeasing!.startKm\n let value = CGFloat(distance) / CGFloat(finalKm)\n gradientProgressView.setProgress(value)\n }\n}\nRun Code Online (Sandbox Code Playgroud)\n
| 归档时间: |
|
| 查看次数: |
471 次 |
| 最近记录: |