圆形比例动画效果有点奇怪

Circle scale animation works a bit weird

我正在为我的 GMSMarker 制作动画,以便它在几秒钟内脉冲一次。

func addWave()
    {
//        circleView.layer.cornerRadius = size / 2

        //Scale
        let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
        scaleAnimation.fromValue = 1
        scaleAnimation.toValue = zoom

        //Opacity
        let alphaAnimation = CABasicAnimation(keyPath: "opacity")
        alphaAnimation.toValue = 0.0

        //Corner radius
//        let cornerRadiusAnimation = CABasicAnimation(keyPath: "cornerRadius")
//        cornerRadiusAnimation.fromValue = size / 2
//        cornerRadiusAnimation.toValue = (size * zoom)/2

        //Animation Group
        let animations: [CAAnimation] = [scaleAnimation, alphaAnimation]

        let animationGroup = CAAnimationGroup()
        animationGroup.duration = duration
        animationGroup.animations = animations
        animationGroup.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
        animationGroup.repeatCount = 1
        animationGroup.fillMode = kCAFillModeForwards
        animationGroup.isRemovedOnCompletion = false
        circleView.layer.add(animationGroup, forKey: "group")
    }

结果如下所示:

如果我取消注释 Corner radius 部分,它看起来像这样:

所以我需要一个建议。

根据我的观察,我认为这一定是您的 CAShapeLayer 路径错误的问题,因此遮蔽了圆圈。

刚刚写了一个雷达动画,希望对你有帮助。

    let scaleAnimation = CABasicAnimation(keyPath: "transform.scale")
    scaleAnimation.fromValue = 0
    scaleAnimation.toValue = 1

    let alphaAnimation = CABasicAnimation(keyPath: "opacity")
    alphaAnimation.fromValue = 1
    alphaAnimation.toValue = 0

    let animations = CAAnimationGroup()
    animations.duration = 0.8
    animations.repeatCount = Float.infinity
    animations.timingFunction = CAMediaTimingFunction(name: kCAMediaTimingFunctionEaseOut)
    animations.animations = [scaleAnimation, alphaAnimation]

    circleView.layer.add(animations, forKey: "animations")

我所做的是,我使用了两个 CAShapeLayer(一个是橙色标记,另一个是标记背面的雷达层)。动画应用于雷达层。

    radarLayer = CAShapeLayer()
    radarLayer.frame = CGRect(x: 0, y: 0, width: self.frame.size.width, height: self.frame.size.height);
    radarLayer.path = UIBezierPath(rect: radarLayer.frame).cgPath
    radarLayer.fillColor = UIColor.orange.cgColor
    radarLayer.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
    radarLayer.cornerRadius = radarLayer.frame.size.width/2
    radarLayer.masksToBounds = true
    radarLayer.opacity = 0
    self.layer.addSublayer(radarLayer)

    circleLayer = CAShapeLayer()
    circleLayer.frame = CGRect(x: 0, y: 0, width: 16, height: 16);
    circleLayer.path = UIBezierPath(rect: circleLayer.frame).cgPath
    circleLayer.fillColor = UIColor.orange.cgColor
    circleLayer.position = CGPoint(x: self.frame.size.width/2, y: self.frame.size.height/2)
    circleLayer.cornerRadius = circleLayer.frame.size.width/2
    circleLayer.masksToBounds = true
    self.layer.addSublayer(circleLayer)

PS。我是 Swift 的新手,如果我哪里错了,请多多指教 :)

示例:http://i.imgur.com/v2jFWgw.jpg

以下摘自 Google 标记文档:

The view behaves as if clipsToBounds is set to YES, regardless of its actual value. You can apply transforms that work outside the bounds, but the object you draw must be within the bounds of the object. All transforms/shifts are monitored and applied. In short: subviews must be contained within the view.

这样做的结果,至少对我而言,正是问题中提到的行为:方圆动画。我想在动画结束时添加到标记中的图像比容器大,所以一旦添加到标记中,它就会被剪裁到它的边界。

以下是我做的:

public var pulseImageView: UIImageView = {
    let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 300, height: 300))
    imageView.image = PaletteElements.pulseLocation.value
    imageView.contentMode = .center

    let pulseAnimation = CABasicAnimation(keyPath: "transform.scale.xy")
    pulseAnimation.repeatCount = Float.infinity
    pulseAnimation.fromValue = 0
    pulseAnimation.toValue = 2.0
    pulseAnimation.isRemovedOnCompletion = false

    let fadeOutAnimation = CABasicAnimation(keyPath: "opacity")
    fadeOutAnimation.duration = 2.5
    fadeOutAnimation.fromValue = 1.0
    fadeOutAnimation.toValue = 0
    fadeOutAnimation.repeatCount = Float.infinity

    let animationGroup = CAAnimationGroup()
    animationGroup.duration = 2.5
    animationGroup.animations = [pulseAnimation, fadeOutAnimation]
    animationGroup.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeOut)
    animationGroup.repeatCount = .greatestFiniteMagnitude
    animationGroup.fillMode = CAMediaTimingFillMode.forwards
    animationGroup.isRemovedOnCompletion = false
    imageView.layer.add(animationGroup, forKey: "pulse")

    return imageView
}()

我在助手 class 中定义了一个变量,这样我就可以在需要时检索图像。我的原始图像,脉冲图像,是 116x116,所以我将 imageView 创建为 300x300,contentMode = .center,所以小图像位于中心并且没有拉伸。我选择 300x300 是因为我的动画将脉冲图像放大到其初始值的 2 倍 (116x2),因​​此我为要执行的整个动画腾出了空间。

最后我将它作为标记添加到地图中:

let pulseMarker = GMSMarker(position: userLocation.coordinate)
pulseMarker.iconView = pulseImageView
pulseMarker.groundAnchor = CGPoint(x: 0.5, y: 0.5)
pulseMarker.map = googleMapView

希望对您有所帮助。