如何在Swift中制作绘图动画,还能改变UIImageView的缩放比例?

时间:2018-04-19 23:50:25

标签: ios swift animation uiimageview core-animation

我想为绘图序列制作动画。我的代码将螺旋绘制到UIImageView.image中。序列更改图像内容,但也更改周围UIImageView的比例。代码参数化为螺旋的转数:

drawSpiral(2.0)

例如,我希望在1.0秒的持续时间内以20个为增量从drawSpiral(2.75)动画到UIView.annimate(withDuration...)

我可以设置{{1}}以使用连续的中间值调用我的方法吗?怎么样?有更好的动画方法吗?

3 个答案:

答案 0 :(得分:5)

  

我可以设置UIView.annimate(withDuration ...)来使用连续的中间值调用我的方法

动画 仅仅是一系列定时中间值被抛出的东西。要求他们抛出你的代码是完全合理的,这样你就可以随心所欲地做任何事。这是怎么回事。

您需要一个特殊的图层:

class MyLayer : CALayer {
    @objc var spirality : CGFloat = 0
    override class func needsDisplay(forKey key: String) -> Bool {
        if key == #keyPath(spirality) {
            return true
        }
        return super.needsDisplay(forKey:key)
    }
    override func draw(in con: CGContext) {
        print(self.spirality) // in real life, this is our signal to draw!
    }
}

该层实际上必须位于界面中,但用户无法看到:

let lay = MyLayer()
lay.frame = CGRect(x: 0, y: 0, width: 1, height: 1)
self.view.layer.addSublayer(lay)

随后,我们可以初始化图层的spirality

lay.spirality = 2.0
lay.setNeedsDisplay() // prints: 2.0

现在我们想要"动画" spirality,这就是我们所做的:

let ba = CABasicAnimation(keyPath:#keyPath(MyLayer.spirality))
ba.fromValue = lay.spirality
ba.toValue = 2.75
ba.duration = 1
lay.add(ba, forKey:nil)
CATransaction.setDisableActions(true)
lay.spirality = 2.75

控制台在1秒钟内显示一系列中间值的到来!

2.03143266495317
2.04482554644346
2.05783333256841
2.0708108600229
2.08361491002142
2.0966724678874
2.10976020619273
2.12260236591101
2.13551922515035
2.14842618256807
2.16123360767961
2.17421661689878
2.18713565543294
2.200748950243
2.21360073238611
2.2268518730998
2.23987507075071
2.25273013859987
2.26560932397842
2.27846492826939
2.29135236144066
2.30436328798532
2.31764804571867
2.33049770444632
2.34330793470144
2.35606706887484
2.36881992220879
2.38163591921329
2.39440815150738
2.40716737508774
2.42003352940083
2.43287514150143
2.44590276479721
2.45875595510006
2.47169743478298
2.48451870679855
2.49806520342827
2.51120449602604
2.52407149970531
2.53691896796227
2.54965999722481
2.56257836520672
2.57552136480808
2.58910304307938
2.60209316015244
2.6151298135519
2.62802086770535
2.64094598591328
2.6540260463953
2.6669240295887
2.6798157542944
2.69264766573906
2.70616912841797
2.71896715462208
2.73285858333111
2.74564798176289
2.75
2.75
2.75

这些正是在可动画属性中抛出的数字,例如当您将视图的帧起源x2更改为2.75时 - 第二次持续时间动画。但是现在数字会以数字的形式出现在你身上,所以现在你可以用这一系列的数字做你喜欢的任何事情。如果您想在每个新值到达时调用您的方法,请直接前进。

答案 1 :(得分:1)

Personally, in more complicated animations I would use lottie the animation itself is built with Adobe After Effect and exported as a JSON file which you will manage using the lottie library this approach will save you time and effort when you port your app to another platform like Android as they also have an Android Lottie which means the complicated process of creating the animation is only done once.

Lottie Files has some examples animations as well for you to look.

答案 2 :(得分:0)

@Matt提供了答案并获得了复选标记。我会回顾一些重点:

  • UIView动画适用于常见的动画属性,但是如果 你需要更改不在UIView的动画列表上的属性,你不能使用它。你必须 创建一个新的CALayer并向其添加CABasicAnimation(keyPath:)
  • 我尝试但是无法通过将它们添加到默认的UIView.layer来获取我的CABasicAnimations。我需要创建一个自定义CALayer UIView.layer的子层 - 类似于 myView.layer.addSublayer(myLayer)
  • 保留自定义子图层,并在想要为图形设置动画时(并且仅在何时)将CABasicAnimation重新添加到该子图层。
  • 在自定义CALayer对象中,请务必使用您的密钥属性override class func needsDisplay(forKey key: String) -> Bool(如@Matt的示例所示),以及override func draw(in cxt: CGContext)进行绘图。请务必使用@objc修饰您的密钥属性。 并参考图纸代码中的关键属性。
  • 要避免的“陷阱”:在UIView对象中,一定要将通常的draw方法(override func draw(_ rect: CGRect) { })置空,以避免单独图层上的动画和非动画绘图之间发生冲突。为了在同一个UIView中协调动画和非动画内容,从自定义层执行 all 绘图是很好的(必要吗?)。
  • 执行此操作时,请使用myLayer.setNeedsDisplay()更新自定义图层中的非动画内容;使用myLayer.add(myBasicAnimation, forKey:nil)触发自定义图层中的动画绘制。

正如我上面所说,@马特回答 - 但这些项目似乎值得强调。