应用转换转换,同时仅添加比例转换

时间:2015-09-29 00:19:03

标签: ios swift core-animation

我正在创建一个动画,我想在应用程序在线检索某些数据时使用该动画。我的想法是,我连续有一些点,它们将缩小,原始尺寸然后恢复到原始尺寸,所有这些都在每次缩放之间有一个小延迟。重复动画并使用自动反转模式。

为此,我使用核心图形方法创建一些点,将它们添加到视图中并使用CGAffineTransformMakeTranslation转换定位它们。然后我使用一个循环来逐个动画它们,并使用CGAffineTransformScale转换进行缩放。

问题:我没有得到预期的动画(至少是我所期待的)。当缩放点时,它们也会移回原始位置。

有人可以告诉我为什么在UIView动画中有翻译转换,我只是指定缩放?

enter image description here

以下是代码:

private var dots = [UIImage]()

public init(numberOfDots: Int, hexaColor: Int, dotDiameter: CGFloat = 30, animationDuration: NSTimeInterval = 1) {
    self.dotDiameter = dotDiameter
    self.animationDuration = animationDuration

    for _ in 0 ..< numberOfDots {
        dots.append(GraphicHelper.drawDisk(hexaColor, rectForDisk: CGRect(x: 0, y: 0, width: dotDiameter, height: dotDiameter), withStroke: false))
    }

    let spaceBetweenDisks: CGFloat = dotDiameter / 3
    let viewWidth: CGFloat = CGFloat(numberOfDots) * dotDiameter + CGFloat(numberOfDots - 1) * spaceBetweenDisks
    super.init(frame: CGRectMake(0, 0, viewWidth, dotDiameter))

    setup()
}

private func setup() {
    for (i, dot) in dots.enumerate() {
        let dotImageView = UIImageView(image: dot)

        addSubview(dotImageView)

        let spaceBetweenDisks: CGFloat = dotDiameter / 3
        let xOffset = CGFloat(i) * (dotDiameter + spaceBetweenDisks)

        dotImageView.transform = CGAffineTransformMakeTranslation(xOffset, 0)
    }
}

public func startAnimation() {
    for i in 0 ..< self.dots.count {
        let dotImageView: UIImageView = self.subviews[i] as! UIImageView
        let transformBeforeAnimation = dotImageView.transform

        let delay: NSTimeInterval = NSTimeInterval(i)/NSTimeInterval(self.dots.count) * animationDuration

        UIView.animateWithDuration(animationDuration, delay: delay, options: [UIViewAnimationOptions.Repeat, UIViewAnimationOptions.Autoreverse], animations: {

            dotImageView.transform = CGAffineTransformScale(dotImageView.transform, 0.05, 0.05)

            }, completion: { finished in
                dotImageView.transform = CGAffineTransformIdentity
                dotImageView.transform = transformBeforeAnimation
        })
    }
}

编辑:

我找到了修复但我不明白为什么要修复它。所以,如果有人可以解释。

我添加了这两行:

dotImageView.transform = CGAffineTransformIdentity
dotImageView.transform = transformBeforeAnimation
startAnimation中的这一行之前

dotImageView.transform = CGAffineTransformScale(dotImageView.transform, 0.05, 0.05)

2 个答案:

答案 0 :(得分:2)

结合翻译和缩放变换令人困惑,很难做到正确。

我必须花太多时间用方格纸和深思熟虑才能搞清楚,我现在太累了。

不要那样做。通过移动中心坐标放置点图像视图,并将变换保留为标识。然后,当你缩放它们时,它们应该按照你想要的方式缩放。

请注意,如果您希望它们同时移动和缩放,您可以更改视图的center属性,并在同一animateWithDuration调用中进行变换缩放,并且它可以正常工作。 (顺便更改框架不是这样。如果更改了转换,那么框架属性就不再正常工作了.Apple的文档说明了使用非标识转换读取/写入视图的frame属性的结果是“未定义”。)

答案 1 :(得分:1)

你确定它会回到原来的位置,而不是根据原来的中心点进行缩放吗?尝试更改应用变换的顺序:

public func startAnimation() {
    for i in 0 ..< self.dots.count {
        let dotImageView: UIImageView = self.subviews[i] as! UIImageView
        let transformBeforeAnimation = dotImageView.transform

        let delay: NSTimeInterval = NSTimeInterval(i)/NSTimeInterval(self.dots.count) * animationDuration

        UIView.animateWithDuration(animationDuration, delay: delay, options: [UIViewAnimationOptions.Repeat, UIViewAnimationOptions.Autoreverse], animations: {
            // make scale transform separately and concat the two
            let scaleTransform = CGAffineTransformMakeScale(0.05, 0.05)
            dotImageView.transform = CGAffineTransformConcat(transformBeforeAnimation, scaleTransform)

            }, completion: { finished in
                dotImageView.transform = CGAffineTransformIdentity
                dotImageView.transform = transformBeforeAnimation
        })
    }
}

来自apple docs:

  

请注意,矩阵运算不是可交换的 - 连接矩阵的顺序很重要。也就是说,矩阵t1乘以矩阵t2的结果不一定等于矩阵t2乘以矩阵t1的结果。

因此,请记住,分配转换会创建一个新的仿射变换矩阵,并且连接将使用新的矩阵修改现有矩阵 - 您应用这些矩阵的顺序可能会产生不同的结果。

为了完成这项工作,我还在dotImageView上更新了您的翻译价值。如果在比例尺之前应用翻译,则需要requiredTranslation / scale ..所以在viewDidLoad

dotImageViewtransform = CGAffineTransformMakeTranslation(1000, 0)

然后是动画:

// make scale transform separately and concat the two
let scaleTransform = CGAffineTransformMakeScale(0.05, 0.05)
self.card.transform = CGAffineTransformConcat(transformBeforeAnimation, scaleTransform)