【问题标题】:Why does a CGAffineTransform applied in steps behave differently than applied at once?为什么在步骤中应用的 CGAffineTransform 的行为与一次应用的行为不同?
【发布时间】:2017-11-30 06:51:38
【问题描述】:

在逐步应用变换而不是一次应用变换时,我看到了一些意想不到的不一致行为,我想知道原因。

假设我们有一个标签,我们想将其转换为向右 100 和向下 50,然后放大到 1.5 倍于原始大小。所以有两种转换:

  1. 翻译
  2. 规模

并说我们正在试验两种不同的动画:

  1. 并行执行平移和缩放
  2. 先进行平移,再依次进行缩放

在第一个动画中,你可能会这样做:

UIView.animate(withDuration: 5, animations: {
    label.transform = label.transform.translatedBy(x: 100, y: 50).scaledBy(x: 1.5, y: 1.5)
}, completion: nil)

一切都如你所愿。标签可以同时平滑地平移和缩放。

在第二个动画中:

UIView.animate(withDuration: 5, animations: {
    label.transform = label.transform.translatedBy(x: 100, y: 50)
}, completion: { _ in
    UIView.animate(withDuration: 5, animations: {
        label.transform = label.transform.scaledBy(x: 1.5, y: 1.5)
    }, completion: nil)
})

标签翻译正确,然后boom,它意外跳跃然后开始缩放。

是什么导致了这种突然的、意想不到的跳跃?通过检查每个变换(并行变换和顺序变换)的矩阵,值是相同的,正如预期的那样。

并行动画

transform before translate and scale: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0)
translate and scale transform: CGAffineTransform(a: 1.5, b: 0.0, c: 0.0, d: 1.5, tx: 100.0, ty: 50.0)
transform after translate and scale: CGAffineTransform(a: 1.5, b: 0.0, c: 0.0, d: 1.5, tx: 100.0, ty: 50.0)

顺序动画

transform before translation: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 0.0, ty: 0.0)
translation transform: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 100.0, ty: 50.0)
transform after translation: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 100.0, ty: 50.0)

transform before scale: CGAffineTransform(a: 1.0, b: 0.0, c: 0.0, d: 1.0, tx: 100.0, ty: 50.0)
scale transform: CGAffineTransform(a: 1.5, b: 0.0, c: 0.0, d: 1.5, tx: 100.0, ty: 50.0)
transform after scale: CGAffineTransform(a: 1.5, b: 0.0, c: 0.0, d: 1.5, tx: 100.0, ty: 50.0)

那么是什么导致了突然的跳跃?

【问题讨论】:

  • 实际上是平行尺度的变换矩阵,变换矩阵是一次应用的,它作为一个整体在tx,ty中反映了平移,在a,b,c,d中反映了尺度。所以动画块应用了结束矩阵,它可以顺利完成所有事情,而不是单独应用。因为每个矩阵在应用第一个矩阵之后分别应用。我的理解:)
  • 在完成后记录按钮的转换,在这两种情况下。你会发现它们是不同的。查看this post
  • @MuhammadZohaibEhsan,你的意思是动画引擎一次只能平滑地对变换矩阵进行一次更新(具有任意数量的旋转、缩放或平移)?
  • @n00bProgrammer 这正是我所做的(见帖子末尾)。并且它们的最终状态在并行动画和顺序动画中完全相同。顺序动画需要额外的一步才能到达那里。

标签: ios swift animation cgaffinetransform cgaffinetransformscale


【解决方案1】:

您需要了解动画在 iOS 中的工作原理。您的 animation 闭包块会立即运行,最终值会立即分配给对象(这是最重要的一点之一 很多人忘记了)。 animation 块所做的只是让它看起来花费了那么多时间。让我用一个例子来详细说明。

let x = UIView()
x.alpha = 0
//At this point, alpha is 0
UIView.animate(withDuration: 5, animations: {
    x.alpha = 1
}, completion: nil)
//At this point, alpha is 1 right away. But the animation itself will take 5 seconds

考虑到这一点,让我们看看您发布的第二个示例

UIView.animate(withDuration: 5, animations: {
    label.transform = label.transform.translatedBy(x: 100, y: 50)
}, completion: { _ in
    UIView.animate(withDuration: 5, animations: {
        label.transform = label.transform.scaledBy(x: 1.5, y: 1.5)
    }, completion: nil)
})

第一个动画会立即运行并转换您的视图。移动到那里只需要 5 秒,但您的视图的 x 和 y 值已经改变。完成后,缩放它会导致奇怪的行为。

【讨论】:

  • 对,我的问题是,为什么翻译完成后缩放会导致缩放前跳转?我只是在缩放已经翻译的东西。记录动画前后的变换表明情况确实如此。 (抱歉这么久才回复你,假期。)
  • 您可能需要研究锚点及其对转换的影响。您可以在网上找到大量资源来详细解释它。为了快速解决问题,在缩放转换之前,如果您希望标签图层的锚点向右和向下缩放,可以将其设置为 (0,0),或者将其向左和向上缩放为 (1,1)
猜你喜欢
  • 2018-12-15
  • 2021-10-24
  • 1970-01-01
  • 2021-02-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多