【问题标题】:Pulsing Animation on layer图层上的脉冲动画
【发布时间】:2021-08-09 03:02:52
【问题描述】:

我正在为一个应用程序制作一些自定义类型的加载器,我只需在我的视图中创建 4 个圆形层,所有这些都设置并显示良好。但是当我对所有图层应用脉冲动画缩放时,它们会干扰我的所有设计和图层缩放,但它会改变它的中心点。我希望所有圆形图层首先缩放图层并使其尺寸变小并使其变大然后再次标识并且它应该称为无穷大。但不应该改变它的中心点。

我在这里分享我的代码

class ViewController: BaseViewController{
    
    @IBOutlet weak var layerView: UIView!
    
    override func viewDidLoad() {
        super.viewDidLoad()
        drawCircles()
    }

    func drawCircles(){
        let width = layerView.bounds.width
        let halfOfView = width / 2
        
        let firstCirleLayer = UIBezierPath(arcCenter: CGPoint(x: halfOfView / 2, y: halfOfView), radius: halfOfView /  3.5, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        circleLayers(path: firstCirleLayer.cgPath, color: UIColor.purple)
        
        let secondCirleLayer = UIBezierPath(arcCenter: CGPoint(x: halfOfView, y: halfOfView / 2), radius: halfOfView /  3.5, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        circleLayers(path: secondCirleLayer.cgPath, color: UIColor.yellow)
        
        let thirdCirleLayer = UIBezierPath(arcCenter: CGPoint(x: width * 0.75, y: halfOfView), radius: halfOfView /  3.5, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        circleLayers(path: thirdCirleLayer.cgPath, color: UIColor.brown)

        let fourthCirleLayer = UIBezierPath(arcCenter: CGPoint(x: halfOfView, y: width * 0.75), radius: halfOfView /  3.5, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
        circleLayers(path: fourthCirleLayer.cgPath, color: UIColor.blue)
    }
    
    func circleLayers(path: CGPath, color: UIColor){

        let layer = CAShapeLayer()
        layer.path = path
        layer.fillColor = color.cgColor
        layerView.layer.addSublayer(layer)
        
        let scaling = CABasicAnimation(keyPath: "transform.scale")
        scaling.toValue = 1.2
        scaling.duration = 0.3
        scaling.autoreverses = true
        scaling.repeatCount = .infinity
        layer.add(scaling, forKey: nil)
    }
    
}

【问题讨论】:

    标签: swift core-animation cashapelayer cabasicanimation ios-animations


    【解决方案1】:

    要从中心缩放每个圆,您必须将每个层的frame 设置为贝塞尔路径的边界框。并且因为框架已经代表了每个圆圈的位置,您可以为贝塞尔路径的arcCenter 设置一个恒定的原点CGPoint(x: radius, y: radius)。是的,这太复杂了……

    class ViewController: UIViewController {
    
        @IBOutlet weak var layerView: UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            drawCircles()
        }
    
        func drawCircles(){
            let width = layerView.bounds.width
            let halfOfView = width / 2
            let radius = halfOfView / 3.5
    
            let firstCenter = CGPoint(x: halfOfView / 2, y: halfOfView)
            makeCircleLayer(center: firstCenter, radius: radius, color: .purple)
    
            let secondCenter = CGPoint(x: halfOfView, y: halfOfView / 2)
            makeCircleLayer(center: secondCenter, radius: radius, color: .yellow)
    
            let thirdCenter = CGPoint(x: width * 0.75, y: halfOfView)
            makeCircleLayer(center: thirdCenter, radius: radius, color: .brown)
    
            let fourthCenter = CGPoint(x: halfOfView, y: width * 0.75)
            makeCircleLayer(center: fourthCenter, radius: radius, color: .blue)
    
        }
    
        func makeCircleLayer(center: CGPoint, radius: CGFloat, color: UIColor) {
            
            let layer = CAShapeLayer()
    
            /// the frame is the actual frame/bounding box of the circle
            layer.frame = CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2)
    
            /// path is relative to the frame
            let path = UIBezierPath(arcCenter: CGPoint(x: radius, y: radius), radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true)
            layer.path = path.cgPath
    
            layer.fillColor = color.cgColor
            layerView.layer.addSublayer(layer)
    
            let scaling = CABasicAnimation(keyPath: "transform.scale")
            scaling.toValue = 1.2
            scaling.duration = 0.3
            scaling.autoreverses = true
            scaling.repeatCount = .infinity
            layer.add(scaling, forKey: nil)
        }
    }
    

    结果:


    但是,由于您的圆只是圆(不是复杂的形状),您应该只使用带有圆角半径的UIView。以下代码产生相同的结果,但更简洁。

    class ViewController: UIViewController {
    
        @IBOutlet weak var layerView: UIView!
    
        override func viewDidLoad() {
            super.viewDidLoad()
            drawCircles()
        }
    
        func drawCircles() {
            let width = layerView.bounds.width
            let halfOfView = width / 2
            let radius = halfOfView / 3.5
    
            let firstCenter = CGPoint(x: halfOfView / 2, y: halfOfView)
            makeCircleView(center: firstCenter, radius: radius, color: .purple)
    
            let secondCenter = CGPoint(x: halfOfView, y: halfOfView / 2)
            makeCircleView(center: secondCenter, radius: radius, color: .yellow)
    
            let thirdCenter = CGPoint(x: width * 0.75, y: halfOfView)
            makeCircleView(center: thirdCenter, radius: radius, color: .brown)
    
            let fourthCenter = CGPoint(x: halfOfView, y: width * 0.75)
            makeCircleView(center: fourthCenter, radius: radius, color: .blue)
        }
    
        func makeCircleView(center: CGPoint, radius: CGFloat, color: UIColor) {
            let frame = CGRect(x: center.x - radius, y: center.y - radius, width: radius * 2, height: radius * 2)
            let circleView = UIView(frame: frame)
            circleView.backgroundColor = color
            circleView.layer.cornerRadius = radius
            layerView.addSubview(circleView)
            
            UIView.animate(withDuration: 0.3, delay: 0, options: [.repeat, .autoreverse]) {
                circleView.transform = CGAffineTransform(scaleX: 1.2, y: 1.2)
            }
        }
    }
    

    【讨论】:

    • 很好,全面的答案。 (已投票。)不过一个尼特。在您的第一个解决方案中,为什么要使用相当复杂的UIBezierPath 初始化程序init(arcCenter:radius:startAngle:endAngle:clockwise:)?初始化器init(ovalIn:) 是为此用例量身定制的。 (UIBezierPath(arcCenter: CGPoint(x: halfOfView / 2, y: halfOfView), radius: halfOfView / 3.5, startAngle: 0, endAngle: 2 * .pi, clockwise: true) 之类的代码变为 UIBezierPath(ovalIn: layer.bounds)。)
    • @DuncanC 是的,ovalIn 会好很多。我完全忘记了它的存在。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-02-02
    • 1970-01-01
    • 1970-01-01
    • 2021-12-03
    • 2021-08-30
    相关资源
    最近更新 更多