ios - 带有旋转闪烁动画的自定义指示器,如 UIActivityIndi​​catorView

标签 ios swift uiviewanimation uiactivityindicatorview

我正在尝试制作自定义事件指标,请参阅下面的指标类

import UIKit
class MyIndicator: UIView {
    let gap = CGFloat(.pi/4 / 6.0)
    var count = 0
    override func draw(_ rect: CGRect) {
        super.draw(rect)
    }
    func blink() {
        backgroundColor = .clear
        let duration: CFTimeInterval = 1.2
        //let beginTime = CACurrentMediaTime()
        let beginTimes: [CFTimeInterval] = [0.25, 1, 1.75, 2.5]
        let timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)
        // Animation
        let animation = CAKeyframeAnimation(keyPath: "opacity")
        animation.keyTimes = [0, 0.5, 1]
        animation.timingFunctions = [timingFunction, timingFunction]
        animation.values = [1, 0.3, 1]
        animation.duration = duration
        animation.repeatCount = HUGE
        animation.isRemovedOnCompletion = false

        for i in 0...3 {
            let shape = CAShapeLayer()
            shape.frame = self.bounds
            shape.fillColor = UIColor.clear.cgColor
            shape.lineWidth = 6.8
            shape.strokeColor = UIColor.blue.cgColor

            let startAngle:CGFloat = CGFloat(i) * CGFloat(Double.pi/2) + gap
            let endAngle:CGFloat = startAngle + CGFloat(Double.pi/2) - gap * 2

            shape.path = UIBezierPath(arcCenter: center, radius: -20, startAngle: startAngle, endAngle: endAngle, clockwise: true).cgPath
            animation.beginTime =  beginTimes[i]
            shape.add(animation, forKey: "animation")
            self.layer.addSublayer(shape)
        }
    }
    func startAnimating() {
        blink()
    }
}


let indicator = MyIndicator(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        self.view.addSubview(indicator)
        indicator.startAnimating()

我附上了我目前的结果。 enter image description here

但是你可以看到动画不像标准的 UIActivityIndi​​catorView 那样做圆周运动。谁能帮我解决这个问题。

最佳答案

尝试使用 CAReplicatorLayer 和实例延迟来同步所有内容。这里是 Playground 。我不是 100% 确定您想要的视觉效果,但这应该很接近。

//: A UIKit based Playground for presenting user interface

import UIKit
import PlaygroundSupport


class MyIndicator: UIView {

    let gap = CGFloat(.pi/4 / 6.0)
    private var replicatorLayer = CAReplicatorLayer()
    private var mainShapeLayer = CAShapeLayer()
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonSetup()
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
        commonSetup()
    }

    func commonSetup(){

        mainShapeLayer = CAShapeLayer()
        mainShapeLayer.frame = self.bounds
        mainShapeLayer.fillColor = UIColor.clear.cgColor
        mainShapeLayer.lineWidth = 6.8
        mainShapeLayer.strokeColor = UIColor.blue.cgColor

        let startAngle:CGFloat = CGFloat(Double.pi * 2) + gap/2
        let endAngle:CGFloat = startAngle + CGFloat(Double.pi/2) - gap/2

        mainShapeLayer.path = UIBezierPath(arcCenter: center, radius: self.bounds.midX - 10, startAngle: startAngle, endAngle: endAngle, clockwise: true).cgPath


        replicatorLayer = CAReplicatorLayer()
        replicatorLayer.frame = self.bounds
        replicatorLayer.instanceCount = 4
        let angle = (Double.pi * 2)/4
        replicatorLayer.instanceTransform = CATransform3DRotate(CATransform3DIdentity, CGFloat(angle), 0, 0, 1)
        replicatorLayer.addSublayer(mainShapeLayer)
        replicatorLayer.opacity = 0

        self.layer.addSublayer(replicatorLayer)
    }


    func animate(){

        let defaultDuration : Double = 0.75

        let animate = CAKeyframeAnimation(keyPath: "opacity")
        animate.values = [1, 0.3, 1]
        animate.keyTimes = [0, 0.5, 1]
        animate.repeatCount = .greatestFiniteMagnitude
        animate.duration = defaultDuration
        animate.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseInEaseOut)

        replicatorLayer.instanceDelay = defaultDuration/4
        self.mainShapeLayer.add(animate, forKey: nil)

        let opacityIn = CABasicAnimation(keyPath: "opacity")
        opacityIn.fromValue = 1
        opacityIn.toValue = 0
        opacityIn.duration = 0.2
        replicatorLayer.add(opacityIn, forKey: nil)
        self.replicatorLayer.opacity = 1
    }

    func stopAnimating(){
        CATransaction.begin()
        let opacityOut = CABasicAnimation(keyPath: "opacity")
        opacityOut.fromValue = 1
        opacityOut.toValue = 0
        opacityOut.duration = 0.2
        CATransaction.setCompletionBlock {
            [weak self] in
            self?.mainShapeLayer.removeAllAnimations()
        }
        replicatorLayer.add(opacityOut, forKey: nil)
        self.replicatorLayer.opacity = 0
        CATransaction.commit()
    }

    override func layoutSubviews() {
        super.layoutSubviews()
        mainShapeLayer.frame = self.bounds
        replicatorLayer.frame = self.bounds
    }

}


class MyViewController : UIViewController {
    override func loadView() {
        let view = UIView()
        view.backgroundColor = .white

        let indicator = MyIndicator(frame: CGRect(x: 0, y: 0, width: 100, height: 100))
        indicator.animate()
        //just to simulate starting and stoping
        DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 10) {
            indicator.stopAnimating()
            DispatchQueue.main.asyncAfter(deadline: DispatchTime.now() + 5) {
                indicator.animate() 
            }
        }

        view.addSubview(indicator)
        self.view = view
    }
}
// Present the view controller in the Live View window
PlaygroundPage.current.liveView = MyViewController()

关于ios - 带有旋转闪烁动画的自定义指示器,如 UIActivityIndi​​catorView,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50180287/

相关文章:

ios - 导航栏一旦隐藏(滑动)就不会回来

ios - CCNode 作为 CCScene 触摸处理程序 cocos2d v3 的子项

ios - 如何创建自定义 UIView 动画

ios - 动画似乎不起作用 - 在 [self dismiss ViewController] 上将 View 从一个位置移动到另一个位置

ios - 使用自定义类设置/实例化 IB subview

ios - iTunes 连接 : "Release This Version" button is disabled

ios - 10000 个数据的 UITableView 性能

Swift uiwebview 目标空白链接 Safari

swift - 以编程方式最小化所有窗口或除了我的 Cocoa 应用程序?

ios - 如何在所有 UIView 完成动画后调用完成 block 来为 UIView 数组设置动画?