与给定的进度值相比,圆形 BezierPath 填充过多 - iOS Swift
Circular BezierPath fills too much vs. given progress value - iOS Swift
我有一个循环的 UIBezierPath 和 2x CAShapeLayers,我用它来显示我的一个应用程序中特定里程碑的进度。
问题: 当我通过 CABasicAnimation 设置进度动画时,进度超出了它应该做的事情。
上下文: 我在 milestonesCollectionView 内的自定义单元格的子视图中显示此 circularView。
视图层次结构: CollectionView > Custom Cell > subview > drawRect 以在其中创建和添加图层。
我的代码:
自定义单元格
在我的自定义单元格中,我设置了 currentProgress(为了测试目的而硬编码)
let placeHolderForProgressView: CircularTrackerView = {
let ctv = CircularTrackerView()
ctv.backgroundColor = UIColor.clear
ctv.translatesAutoresizingMaskIntoConstraints = false
ctv.currentProgress = 0.5 //set to 0.5 to get a circle filled at 50%
return ctv
}()
CircularTrackerView 内部
// 每当设置单元格并向 progressView 提供 currentProgress 时,我都会为进度设置动画
var currentProgress: CGFloat = 0.0 {
didSet {
animate(to: currentProgress)
let percent = Int(currentProgress * 100)
percentLbl.text = "\(percent)%"
}
}
let shapeLayer = CAShapeLayer() //displays the progress
let trackLayer = CAShapeLayer() //background of the ring
override func draw(_ rect: CGRect) {
super.draw(rect)
let center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.white.withAlphaComponent(0.2).cgColor
trackLayer.lineWidth = 5
trackLayer.fillColor = UIColor.clear.cgColor
trackLayer.lineCap = kCALineCapRound
layer.addSublayer(trackLayer)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.white.cgColor
shapeLayer.lineWidth = 5
shapeLayer.strokeEnd = 0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = kCALineCapRound
layer.addSublayer(shapeLayer)
}
private func animate(to progress: CGFloat) {
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0.0
animation.toValue = progress
animation.duration = 2
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
shapeLayer.add(animation, forKey: "randomString")
}
输出
圆圈超过了 50% 的标记......甚至很难我认为我按照正确的步骤创建了这个(略微改编自 YouTube 上的 LetsBuildThatApp 教程:https://www.youtube.com/watch?v=O3ltwjDJaMk)
如果您能提供任何有用的意见,请提前致谢。
问题是你的UIBezierPath
/你给它的角度:
let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
差异 endAngle - startAngle
是 2.5 * PI
,但应该只是 2 * PI
。当它是 2.5 * PI
时,这意味着您的 strokeEnd
of 0.5
导致 1.25 * PI
被抚摸。
解决方法,将endAngle
减少0.5 * PI
:
let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -0.5 * CGFloat.pi, endAngle: 1.5 * CGFloat.pi, clockwise: true)
我有一个循环的 UIBezierPath 和 2x CAShapeLayers,我用它来显示我的一个应用程序中特定里程碑的进度。
问题: 当我通过 CABasicAnimation 设置进度动画时,进度超出了它应该做的事情。
上下文: 我在 milestonesCollectionView 内的自定义单元格的子视图中显示此 circularView。
视图层次结构: CollectionView > Custom Cell > subview > drawRect 以在其中创建和添加图层。
我的代码:
自定义单元格
在我的自定义单元格中,我设置了 currentProgress(为了测试目的而硬编码)
let placeHolderForProgressView: CircularTrackerView = {
let ctv = CircularTrackerView()
ctv.backgroundColor = UIColor.clear
ctv.translatesAutoresizingMaskIntoConstraints = false
ctv.currentProgress = 0.5 //set to 0.5 to get a circle filled at 50%
return ctv
}()
CircularTrackerView 内部
// 每当设置单元格并向 progressView 提供 currentProgress 时,我都会为进度设置动画
var currentProgress: CGFloat = 0.0 {
didSet {
animate(to: currentProgress)
let percent = Int(currentProgress * 100)
percentLbl.text = "\(percent)%"
}
}
let shapeLayer = CAShapeLayer() //displays the progress
let trackLayer = CAShapeLayer() //background of the ring
override func draw(_ rect: CGRect) {
super.draw(rect)
let center = CGPoint(x: frame.size.width / 2, y: frame.size.height / 2)
let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
trackLayer.path = circularPath.cgPath
trackLayer.strokeColor = UIColor.white.withAlphaComponent(0.2).cgColor
trackLayer.lineWidth = 5
trackLayer.fillColor = UIColor.clear.cgColor
trackLayer.lineCap = kCALineCapRound
layer.addSublayer(trackLayer)
shapeLayer.path = circularPath.cgPath
shapeLayer.strokeColor = UIColor.white.cgColor
shapeLayer.lineWidth = 5
shapeLayer.strokeEnd = 0
shapeLayer.fillColor = UIColor.clear.cgColor
shapeLayer.lineCap = kCALineCapRound
layer.addSublayer(shapeLayer)
}
private func animate(to progress: CGFloat) {
let animation = CABasicAnimation(keyPath: "strokeEnd")
animation.fromValue = 0.0
animation.toValue = progress
animation.duration = 2
animation.fillMode = kCAFillModeForwards
animation.isRemovedOnCompletion = false
shapeLayer.add(animation, forKey: "randomString")
}
输出
圆圈超过了 50% 的标记......甚至很难我认为我按照正确的步骤创建了这个(略微改编自 YouTube 上的 LetsBuildThatApp 教程:https://www.youtube.com/watch?v=O3ltwjDJaMk)
如果您能提供任何有用的意见,请提前致谢。
问题是你的UIBezierPath
/你给它的角度:
let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -CGFloat.pi / 2, endAngle: 2 * CGFloat.pi, clockwise: true)
差异 endAngle - startAngle
是 2.5 * PI
,但应该只是 2 * PI
。当它是 2.5 * PI
时,这意味着您的 strokeEnd
of 0.5
导致 1.25 * PI
被抚摸。
解决方法,将endAngle
减少0.5 * PI
:
let circularPath = UIBezierPath(arcCenter: center, radius: frame.size.width / 2, startAngle: -0.5 * CGFloat.pi, endAngle: 1.5 * CGFloat.pi, clockwise: true)