0

我正在尝试使用 CAReplicatorLayer 对象为我的背景视图实现这种马赛克灯光秀效果: https ://downloops.com/stock-footage/mosaic-light-show-blue-illuminated-pixel-grid-looping-background/

在此处输入图像描述

每个图块/CALayer 都是水平和垂直复制的单个图像。那部分我已经完成了。

在我看来,这项任务至少分为 4 个单独的部分:

  1. 选择一个随机瓷砖
  2. 为所选图块选择随机范围的颜色偏移
  3. 在指定的持续时间内应用该颜色偏移(以秒为单位)
  4. 如果随机颜色偏移超过特定阈值,则应用带有颜色偏移动画的发光效果。

但我实际上不确定这是否是正确的算法。

我当前的代码取自本教程: https ://www.swiftbysundell.com/articles/ca-gems-using-replicator-layers-in-swift/

动画不是我的强项,我实际上不知道如何在所有图块上应用连续/重复动画。这是我当前的代码:

    @IBOutlet var animationView: UIView!

    func cleanUpAnimationView() {
        self.animationView.layer.removeAllAnimations()
        self.animationView.layer.sublayers?.removeAll()
    }

    /// Start a background animation with a replicated pattern image in tiled formation.
    func setupAnimationView(withPatternImage patternImage: UIImage, animate: Bool = true) {
        // Tutorial: https://www.swiftbysundell.com/articles/ca-gems-using-replicator-layers-in-swift/

        let imageSize = patternImage.size.halve

        self.cleanUpAnimationView()

        // Animate pattern image
        let replicatorLayer = CAReplicatorLayer()
        replicatorLayer.frame.size = self.animationView.frame.size
        replicatorLayer.masksToBounds = true
        self.animationView.layer.addSublayer(replicatorLayer)

        // Give the replicator layer a sublayer to replicate
        let imageLayer = CALayer()
        imageLayer.contents = patternImage.cgImage
        imageLayer.frame.size = imageSize
        replicatorLayer.addSublayer(imageLayer)

        // Tell the replicator layer how many copies (or instances) of the image needs to be rendered. But we won't see more than one since they are, per default, all rendered/stacked on top of each other.
        let instanceCount = self.animationView.frame.width / imageSize.width
        replicatorLayer.instanceCount = Int(ceil(instanceCount))
        // Instance offsets & transforms is needed to move them
        // 'CATransform3D' transform will be used on each instance: shifts them to the right & reduces the red & green color component of each instance's tint color.

        // Shift each instance by the width of the image
        replicatorLayer.instanceTransform = CATransform3DMakeTranslation(imageSize.width, 0, 0)

        // Reduce the red & green color component of each instance, effectively making each copy more & more blue while horizontally repeating the gradient pattern
        let colorOffset = -1 / Float(replicatorLayer.instanceCount)
        replicatorLayer.instanceRedOffset = colorOffset
        replicatorLayer.instanceGreenOffset = colorOffset
        //replicatorLayer.instanceBlueOffset = colorOffset
        //replicatorLayer.instanceColor = UIColor.random.cgColor

        // Extend the original pattern to also repeat vertically using another tint color gradient
        let verticalReplicatorLayer = CAReplicatorLayer()
        verticalReplicatorLayer.frame.size = self.animationView.frame.size
        verticalReplicatorLayer.masksToBounds = true
        verticalReplicatorLayer.instanceBlueOffset = colorOffset
        self.animationView.layer.addSublayer(verticalReplicatorLayer)

        let verticalInstanceCount = self.animationView.frame.height / imageSize.height
        verticalReplicatorLayer.instanceCount = Int(ceil(verticalInstanceCount))

        verticalReplicatorLayer.instanceTransform = CATransform3DMakeTranslation(0, imageSize.height, 0)
        verticalReplicatorLayer.addSublayer(replicatorLayer)

        guard animate else { return }

        // Set both the horizontal & vertical replicators to add a slight delay to all animations applied to the layer they're replicating
        let delay = TimeInterval(0.1)
        replicatorLayer.instanceDelay = delay
        verticalReplicatorLayer.instanceDelay = delay

        // This will make the image layer change color
        let animColor = CABasicAnimation(keyPath: "instanceRedOffset")
        animColor.duration = animationDuration
        animColor.fromValue = verticalReplicatorLayer.instanceRedOffset
        animColor.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
        animColor.autoreverses = true
        animColor.repeatCount = .infinity
        replicatorLayer.add(animColor, forKey: "colorshift")

        let animColor1 = CABasicAnimation(keyPath: "instanceGreenOffset")
        animColor1.duration = animationDuration
        animColor1.fromValue = verticalReplicatorLayer.instanceGreenOffset
        animColor1.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
        animColor1.autoreverses = true
        animColor1.repeatCount = .infinity
        replicatorLayer.add(animColor1, forKey: "colorshift1")

        let animColor2 = CABasicAnimation(keyPath: "instanceBlueOffset")
        animColor2.duration = animationDuration
        animColor2.fromValue = verticalReplicatorLayer.instanceBlueOffset
        animColor2.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))
        animColor2.autoreverses = true
        animColor2.repeatCount = .infinity
        replicatorLayer.add(animColor2, forKey: "colorshift2")
    }
4

1 回答 1

0
 let imageSize = patternImage.size.halve 

 animColor.toValue = -1 / Float(Int.random(replicatorLayer.instanceCount-1))

两者都产生了错误。

我删除halve并注释掉了这些animColor行,代码运行和动画。在我使用您的代码之前,我根本无法让任何复制器层显示或制作动画(甚至是最基本的苹果或教程代码)。太感谢了!

于 2020-01-03T16:25:20.220 回答