我已经在Swift中创建了一个圆形进度条,当用户按住视图时,它会在1.5秒内动画化为值1。但是我想在动画完成后添加一个新的viewcontroller,如果用户结束得很早,则重新启动循环进度条。有人可以帮我吗?
当用户按住视图并在放开时停止时,圆形进度条与动画一起使用。
class CounterView: UIView {
var bgPath: UIBezierPath!
var shapeLayer: CAShapeLayer!
var progressLayer: CAShapeLayer!
override init(frame: CGRect) {
super.init(frame: frame)
bgPath = UIBezierPath()
self.simpleShape()
}
required public init?(coder aDecoder: NSCoder) {
super.init(coder: aDecoder)
bgPath = UIBezierPath()
self.simpleShape()
}
func simpleShape()
{
createCirclePath()
shapeLayer = CAShapeLayer()
shapeLayer.path = bgPath.cgPath
shapeLayer.lineWidth = 5
shapeLayer.fillColor = nil
shapeLayer.strokeColor = UIColor.clear.cgColor
progressLayer = CAShapeLayer()
progressLayer.path = bgPath.cgPath
progressLayer.lineCap = kCALineCapRound
progressLayer.lineWidth = 5
progressLayer.fillColor = nil
progressLayer.strokeColor = UIColor.yellow.cgColor
progressLayer.strokeEnd = 0.0
self.layer.addSublayer(shapeLayer)
self.layer.addSublayer(progressLayer)
}
private func createCirclePath()
{
let x = self.frame.width/2
let y = self.frame.height/2
let center = CGPoint(x: x, y: y)
print(x,y,center)
bgPath.addArc(withCenter: center, radius: x/CGFloat(2), startAngle: CGFloat(0), endAngle: CGFloat(6.28), clockwise: true)
bgPath.close()
}
var animationCompletedCallback: ((_ isAnimationCompleted: Bool) -> Void)?
func setProgressWithAnimation(duration: TimeInterval, value: Float) {
CATransaction.setCompletionBlock {
if let callBack = self.animationCompletedCallback { callBack(true) }
}
CATransaction.begin()
let animation = CABasicAnimation (keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = value
animation.repeatCount = 1
animation.timingFunction = CAMediaTimingFunction (name: kCAMediaTimingFunctionLinear)
progressLayer.strokeEnd = CGFloat(value)
progressLayer.add(animation, forKey: "animateprogress")
CATransaction.commit()
}
func removeLayers() {
shapeLayer.removeAllAnimations()
shapeLayer.removeFromSuperlayer()
progressLayer.removeAllAnimations()
progressLayer.removeFromSuperlayer()
}
}
class ViewController: UIViewController {
@IBOutlet weak var counterView: CounterView!
@IBOutlet weak var holdView: UIView!
var isAnimationCompleted = false
override func viewDidLoad() {
super.viewDidLoad()
addLongPressGesture()
addCounterViewCallback()
}
@objc func longPress(gesture: UILongPressGestureRecognizer) {
if gesture.state == UIGestureRecognizerState.began {
// self.counterView.simpleShape()
self.counterView.setProgressWithAnimation(duration: 1.5, value: 1.0)
}
if gesture.state == UIGestureRecognizerState.ended {
if !isAnimationCompleted {
self.counterView.removeLayers()
}
}
}
func addLongPressGesture(){
let lpgr = UILongPressGestureRecognizer(target: self, action: #selector(longPress(gesture:)))
lpgr.minimumPressDuration = 0
self.holdView.addGestureRecognizer(lpgr)
}
private func addCounterViewCallback() {
counterView.animationCompletedCallback = { [weak self] (isCompleted) in
guard let weakSelf = self else {return}
weakSelf.isAnimationCompleted = isCompleted
weakSelf.addFlashView()
}
}
func addFlashView(){
let storyBoard : UIStoryboard = UIStoryboard(name: "Main", bundle:nil)
let resultViewController = storyBoard.instantiateViewController(withIdentifier: "ResultView") as! Flash
self.present(resultViewController, animated:true, completion:nil)
}
完成动画后添加新的viewcontroller,如果用户释放视图并再次按住它,则重新启动动画。
答案 0 :(得分:0)
添加callback
可以知道动画何时结束。然后使用CATransaction
知道动画何时完成。
var animationCompletedCallback: (() -> Void)?
func setProgressWithAnimation(duration: TimeInterval, value: Float) {
CATransaction.setCompletionBlock {
if let callBack = animationCompletedCallback {
callBack()
}
}
CATransaction.begin()
let animation = CABasicAnimation (keyPath: "strokeEnd")
animation.duration = duration
animation.fromValue = 0
animation.toValue = value
animation.repeatCount = .infinity
animation.timingFunction = CAMediaTimingFunction (name: kCAMediaTimingFunctionLinear)
progressLayer.strokeEnd = CGFloat(value)
progressLayer.add(animation, forKey: "animateprogress")
CATransaction.commit()
}
并在addLongPressGesture()
中viewDidLoad()
之后添加此函数:
private func addCounterViewCallback() {
counterView.animationCompletedCallback = { [weak self] in
guard let weakSelf = self else {return}
weakSelf.addFlashView()
}
}
要删除图层,请使用此:
func removeLayers() {
shapeLayer.removeAllAnimations()
shapeLayer.removeFromSuperlayer()
progressLayer.removeAllAnimations()
progressLayer.removeFromSuperlayer()
}
更新1:
要在用户停止按动时删除动画,您需要在回调中添加这样的变量:
var animationCompletedCallback: ((isAnimationCompleted: Bool) -> Void)?
因此,CounterView
中的回调将为:
if let callBack = animationCompletedCallback { callBack(true) }
在您的控制器中添加一个变量:
var isAnimationCompleted = false
更改addCounterViewCallback()
:
private func addCounterViewCallback() {
counterView.animationCompletedCallback = { [weak self] (isCompleted) in
guard let weakSelf = self else {return}
weakSelf.isAnimationCompleted = isCompleted
weakSelf.addFlashView()
}
}
现在,您可以在longPress()中添加一个条件:
if gesture.state == UIGestureRecognizerState.ended {
if !isAnimationCompleted {
//Call remove layers code
}
}
更新2:
在CounterView
中添加变量:
var isAnimationCompleted = true
像这样更改回调:
CATransaction.setCompletionBlock {
if let callBack = self.animationCompletedCallback { callBack(isAnimationCompleted) }
}
在控制器longPress()
中:
if gesture.state == UIGestureRecognizerState.ended {
if !isAnimationCompleted {
self.counterView.isAnimationCompleted = false
self.counterView.removeLayers()
}
}
将addCounterViewCallback()
修改为此:
private func addCounterViewCallback() {
counterView.animationCompletedCallback = { [weak self] (isCompleted) in
guard let weakSelf = self else {return}
weakSelf.isAnimationCompleted = isCompleted
if isCompleted {
weakSelf.addFlashView()
}
}
}