ios - Animate CAShapeLayer with circle UIBezierPath and CABasicAnimation -


i'd animate circle angle 0 360 degrees in 15 sec.

the animation weird. know start/end angle issue, faced kind of problem circle animations, don't know how solve one.

var circle_layer=cashapelayer() var circle_anim=cabasicanimation(keypath: "path")  func init_circle_layer(){     let w=circle_view.bounds.width     let center=cgpoint(x: w/2, y: w/2)      //initial path     let start_angle:cgfloat = -0.25*360*cgfloat.pi/180     let initial_path=uibezierpath(arccenter: center, radius: w/2, startangle: start_angle, endangle: start_angle, clockwise: true)     initial_path.addline(to: center)      //final path     let end_angle:cgfloat=start_angle+360*cgfloat(cgfloat.pi/180)     let final_path=uibezierpath(arccenter: center, radius: w/2, startangle: start_angle, endangle: end_angle, clockwise: true)     final_path.addline(to: center)      //init layer     circle_layer.path=initial_path.cgpath     circle_layer.fillcolor=uicolor(hex_code: "ea535d").cgcolor     circle_view.layer.addsublayer(circle_layer)      //init anim     circle_anim.duration=15     circle_anim.fromvalue=initial_path.cgpath     circle_anim.tovalue=final_path.cgpath     circle_anim.isremovedoncompletion=false     circle_anim.fillmode=kcafillmodeforwards     circle_anim.delegate=self }  func start_circle_animation(){     circle_layer.add(circle_anim, forkey: "circle_anim") } 

i want start on top @ 0 degrees , finish on top after full tour: enter image description here

enter image description here

you can't animate fill of uibezierpath (or @ least without introducing weird artifacts except in nicely controlled situations). can animate strokeend of path of cashapelayer. , if make line width of stroked path wide (i.e. radius of final circle), , set radius of path half of of circle, you're looking for.

private var circlelayer = cashapelayer()  private func configurecirclelayer() {     let radius = min(circleview.bounds.width, circleview.bounds.height) / 2      circlelayer.strokecolor = uicolor(hexcode: "ea535d").cgcolor     circlelayer.fillcolor = uicolor.clear.cgcolor     circlelayer.linewidth = radius     circleview.layer.addsublayer(circlelayer)      let center = cgpoint(x: circleview.bounds.width/2, y: circleview.bounds.height/2)     let startangle: cgfloat = -0.25 * 2 * .pi     let endangle: cgfloat = startangle + 2 * .pi     circlelayer.path = uibezierpath(arccenter: center, radius: radius / 2, startangle: startangle, endangle: endangle, clockwise: true).cgpath      circlelayer.strokeend = 0 }  private func startcircleanimation() {     circlelayer.strokeend = 1     let animation = cabasicanimation(keypath: "strokeend")     animation.fromvalue = 0     animation.tovalue = 1     animation.duration = 15     circlelayer.add(animation, forkey: nil) } 

for ultimate control, when doing complex uibezierpath animations, can use cadisplaylink, avoiding artifacts can result when using cabasicanimation of path:

private var circlelayer = cashapelayer() private weak var displaylink: cadisplaylink? private var starttime: cftimeinterval!  private func configurecirclelayer() {     circlelayer.fillcolor = uicolor(hexcode: "ea535d").cgcolor     circleview.layer.addsublayer(circlelayer)     updatepath(percent: 0) }  private func startcircleanimation() {     starttime = cacurrentmediatime()     displaylink = {         let _displaylink = cadisplaylink(target: self, selector: #selector(handledisplaylink(_:)))         _displaylink.add(to: .current, formode: .commonmodes)         return _displaylink     }() }  @objc func handledisplaylink(_ displaylink: cadisplaylink) {   // @objc qualifier needed swift 4 @objc inference     let percent = cgfloat(cacurrentmediatime() - starttime) / 15.0     updatepath(percent: min(percent, 1.0))     if percent > 1.0 {         displaylink.invalidate()     } }  private func updatepath(percent: cgfloat) {     let w = circleview.bounds.width     let center = cgpoint(x: w/2, y: w/2)     let startangle: cgfloat = -0.25 * 2 * .pi     let endangle: cgfloat = startangle + percent * 2 * .pi     let path = uibezierpath()     path.move(to: center)     path.addarc(withcenter: center, radius: w/2, startangle: startangle, endangle: endangle, clockwise: true)     path.close()      circlelayer.path = path.cgpath } 

then can do:

override func viewdidappear(_ animated: bool) {     super.viewdidappear(animated)      configurecirclelayer()     startcircleanimation() }  override func viewdiddisappear(_ animated: bool) {     super.viewdiddisappear(animated)      displaylink?.invalidate()   // avoid displaylink keeping reference dismissed view during animation } 

that yields:

animated circle


Comments

Popular posts from this blog

node.js - Node js - Trying to send POST request, but it is not loading javascript content -

javascript - Replicate keyboard event with html button -

javascript - Web audio api 5.1 surround example not working in firefox -