【问题标题】:Translate transformation applied while only scale transformation added应用了平移变换,而仅添加了缩放变换
【发布时间】:2015-10-01 09:08:40
【问题描述】:

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

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

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

有人能告诉我为什么在UIView 动画中存在平移转换,而我只是指定了缩放比例吗?

代码如下:

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)

【问题讨论】:

    标签: ios swift core-animation


    【解决方案1】:

    将平移和缩放变换结合起来令人困惑且难以正确处理。

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

    不要那样做。通过移动它们的中心坐标来放置您的点图像视图,并将变换保留在标识处。然后,当您缩放它们时,它们应该按照您的意愿缩放。

    请注意,如果您希望它们同时移动和缩放,您可以在同一个 animateWithDuration 调用中同时更改视图的中心属性和变换比例,并且它可以正常工作。 (顺便说一下,更改框架并非如此。如果更改转换,则框架属性将不再正常工作。Apple 的文档说,读取/写入具有非身份转换的视图的框架属性的结果是“未定义的”。)

    【讨论】:

      【解决方案2】:

      你确定它会回到原来的位置而不是根据原来的中心点进行缩放吗?尝试通过执行以下操作更改应用转换的顺序:

      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
              })
          }
      }
      

      来自苹果文档:

      请注意,矩阵运算不是可交换的——连接矩阵的顺序很重要。即矩阵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)
      

      【讨论】:

      • 我做了修改,还是一样的问题。关于你的问题我不确定。但是从我在动画中看到的内容来看,我会说它首先会回到它的原始位置,然后在缩放时(通过动画)移动到它的当前位置。我实际上找到了一种使它正确的方法,但我不明白,我在玩了一段时间不同的变换后找到了它。我正在编辑问题。
      • 所以是的,问题是你试图用仿射变换做所有事情。我可能会在没有平移变换的情况下设置框架,并且只缩放它们。如果你想用仿射变换来做这一切,想想串联是如何工作的。如果先应用变换然后应用比例,则需要将变换除以比例来计算偏移值。请记住,“变换”是您应用的所有变换矩阵相乘的结果。
      • 我用这个更好的信息更新了我的答案。经过测试并按预期工作,没有额外的转换分配。
      • 感谢您的回复。我尝试通过首先缩放到 0.05,然后在动画关闭中缩放 1/0.05 来做相反的动画,但它没有按预期工作,所以我最终没有使用平移来移动我的视图,我只是改变了中心并应用变换仅用于缩放。
      • 相反的动画只能使用 CGAffineTransformIdentity 来完成 - 这将使它恢复到无变换状态。
      猜你喜欢
      • 1970-01-01
      • 2016-11-25
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-07-24
      • 2016-05-18
      • 2011-01-04
      • 2020-01-01
      相关资源
      最近更新 更多