Ios UIView动画-旋转并放大,然后旋转并缩小

Ios UIView动画-旋转并放大,然后旋转并缩小,ios,swift,xcode,rotation,uiviewanimation,Ios,Swift,Xcode,Rotation,Uiviewanimation,我有一个子类imageview,我想淡入、放大和旋转,然后在缩小和淡出的同时继续旋转 我使用一个UIView动画块和一个完成处理程序来处理收缩 问题是它不是流体动画。在完成处理程序运行之前,动画会在再次运行之前停止。我需要它是一个很好的动画“突袭” 下面的代码: let duration: TimeInterval = 3.0 let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi)) UIVie

我有一个子类imageview,我想淡入、放大和旋转,然后在缩小和淡出的同时继续旋转

我使用一个UIView动画块和一个完成处理程序来处理收缩

问题是它不是流体动画。在完成处理程序运行之前,动画会在再次运行之前停止。我需要它是一个很好的动画“突袭”

下面的代码:

    let duration: TimeInterval = 3.0
    let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi))


    UIView.animate(withDuration: duration * 3, delay: 0, options: [.curveLinear], animations: {
        // initial transform
        self.alpha = 0
        self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
        // initial spin for duration of animaton
        UIView.animate(withDuration: duration * 3, delay: 0.0, options: [.curveLinear], animations: {
            self.transform = rotate
        }, completion: nil)

        // scaling and fading
        UIView.animate(withDuration: duration, delay: 0, options: [.curveLinear], animations: {
            UIView.setAnimationRepeatCount(3)
            self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
            self.alpha = 1
        }) { (true) in
            UIView.animate(withDuration: duration, animations: {
                UIView.setAnimationRepeatCount(3)
                self.transform = self.transform.scaledBy(x: 0.1, y: 0.1)
                self.alpha = 0
            })
        }
    }, completion: nil)

如何使动画在淡入和放大时始终旋转,然后再缩小和淡出?整个动画应持续3秒,并重复3次。谢谢。

尝试使用CGAffineTransformConcat()

我看到在完成的一开始,旋转时有轻微的口吃

我用您的代码创建了一个缩减(在下面的蓝色视图中显示),并在橙色视图中创建了一个变体。这是从模拟器中拍摄的,并转化为动画GIF,因此速度减慢。随着整个变换的缩小,橙色视图继续旋转

这是橙色视图的layoutSubviews()的代码

override func layoutSubviews() {
    super.layoutSubviews()
    
    let duration: TimeInterval = 3.0
    let rotate = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
    
    // initial transform
    self.alpha = 0
    self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)
    
    // initial spin for duration of animaton
    UIView.animate(withDuration: duration,
                   delay: 0.0,
                   options: [.curveLinear],
                   animations: {
                      self.transform = rotate;
                    },
                   completion: nil)
    // scaling and fading
    UIView.animate(withDuration: duration/2.0, animations: {
      self.transform = self.transform.scaledBy(x: 0.8, y: 0.8)
      self.alpha = 1
    }) { (true) in
      UIView.animate(withDuration: duration/2.0, animations: {
        self.transform = self.transform.scaledBy(x: 0.1, y: 0.1)
        self.alpha = 0
      })
    }
  }

对于您的修改请求,我正在使用块动画扩展您已经看到的内容。正如一些人所说,关键帧动画可能更好,不管怎样,这里是想法

通过变换视图来创建整个时间旋转的动画。 创建另一个基于当前变换(旋转)进行缩放和淡入的动画。在此过程中,我刚刚创建了一些变量,以允许您自定义(并重复)动画的部分。我把一些事情说得很清楚,我知道我可以重构,把事情写得更简洁

这是密码

import UIKit

class OrangeView: UIView {



override func layoutSubviews() {
    super.layoutSubviews()

  let duration: TimeInterval = 9.0

  self.transform = CGAffineTransform.identity

  // initial transform
  self.alpha = 1
  self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

  // start rotation
  rotate(duration: duration)

  // scaling and fading
  scaleUpAndDown(desiredRepetitions: 3, initalDuration: duration)


  }

func rotate(duration: TimeInterval) {
                UIView.animate(withDuration: duration/2.0,
                               delay: 0.0,
                               options: [.curveLinear], animations: {
                                let angle = Double.pi
                                self.transform = self.transform.rotated(by: CGFloat(angle))
                }, completion: {[weak self] finished in
  guard let strongSelf = self else {
    return
  }
  if finished &&
    strongSelf.transform != CGAffineTransform.identity {
    strongSelf.rotate(duration: duration)
  } else {
    // rotation ending
  }
})

  }

func scaleUpAndDown(timesRepeated: Int = 0, desiredRepetitions: Int, initalDuration: TimeInterval) {

guard timesRepeated < desiredRepetitions,
  desiredRepetitions > 0, initalDuration > 0 else {
  self.transform = CGAffineTransform.identity
    return
}
let repeatedCount = timesRepeated + 1

let scalingDuration = initalDuration/2.0/Double(desiredRepetitions)

UIView.animate(withDuration: scalingDuration,
               delay: 0.0,
               animations: {
                let desiredOriginalScale: CGFloat = 0.8

                let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
                let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale

                self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
                self.alpha = 1
              }) { (true) in
                UIView.animate(withDuration:scalingDuration,
                               delay: 0.0,
                               animations: {

                                let desiredOriginalScale: CGFloat = 0.1

                                let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
                                let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale
                                  self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
                                  self.alpha = 0
                }) { finshed in
                  self.scaleUpAndDown(timesRepeated: repeatedCount, desiredRepetitions: desiredRepetitions, initalDuration: initalDuration);
                }
              }

  }

}
导入UIKit
类OrangeView:UIView{
覆盖func布局子视图(){
super.layoutSubviews()
let持续时间:时间间隔=9.0
self.transform=CGAffineTransform.identity
//初始变换
self.alpha=1
self.transform=CGAffineTransform(scaleX:0.1,y:0.1)
//开始旋转
轮换(持续时间:持续时间)
//缩放和衰减
scaleUpAndDown(所需重复:3,初始持续时间:持续时间)
}
函数旋转(持续时间:时间间隔){
UIView.animate(带持续时间:持续时间/2.0,
延迟:0.0,
选项:[.curveLinear],动画:{
设角度=Double.pi
self.transform=self.transform.rotated(按:CGFloat(角度))
},完成:{[弱自我]在中完成
守卫让strongSelf=self-else{
返回
}
如果完成&&
strongSelf.transform!=CGAffineTransform.identity{
strong自我轮换(持续时间:持续时间)
}否则{
//旋转结束
}
})
}
func scaleUpAndDown(timesRepeated:Int=0,desiredRepetitions:Int,initalDuration:TimeInterval){
保护时间重复<期望的重复,
desiredRepetitions>0,InitialDuration>0其他{
self.transform=CGAffineTransform.identity
返回
}
让repeatedCount=timesRepeated+1
让scalingDuration=initalDuration/2.0/Double(desiredRepetitions)
UIView.animate(withDuration:scalingDuration,
延迟:0.0,
动画:{
让desiredOriginalScale:CGFloat=0.8
设scaleX=abs(CGAffineTransform.identity.a/self.transform.a)*desiredOriginalScale
设scaleY=abs(CGAffineTransform.identity.d/self.transform.d)*desiredOriginalScale
self.transform=self.transform.scaledBy(x:scaleX,y:scaleY)
self.alpha=1
}){(正确)在
UIView.animate(withDuration:scalingDuration,
延迟:0.0,
动画:{
让desiredOriginalScale:CGFloat=0.1
设scaleX=abs(CGAffineTransform.identity.a/self.transform.a)*desiredOriginalScale
设scaleY=abs(CGAffineTransform.identity.d/self.transform.d)*desiredOriginalScale
self.transform=self.transform.scaledBy(x:scaleX,y:scaleY)
self.alpha=0
}){找到了
self.scaleUpAndDown(timesRepeated:repeatedCount,desiredRepetitions:desiredRepetitions,initialDuration:initialDuration);
}
}
}
}
最后,这里是另一个动画gif


你看过关键帧动画吗?我同意唐诺万·金的观点。。。您可能应该从
UIView
动画级别降到通过核心动画直接完成的关键帧动画。这将使您的整个动画成为一个连续循环。Donovan和Scott-通过关键帧动画,您是指使用cabasicanimation进行动画制作吗?通过在现有变换上调用类似scaledBy的函数,它已经在执行串联。这太棒了!感谢您花时间创建最终结果的gif!有没有办法将重复计数添加到橙色动画中?我尝试将setAnimationRepeatCount(3)添加到缩放和淡入块,但它将动画分割为3个“位”。我已将您的答案标记为正确,因为它符合我的要求。重复动画3x不在我最初问题的范围内,但如果你能帮助橙色视图动画重复3x,我将不胜感激:)在你的块中添加setAnimationRepeatCount,我得到了非常奇怪的结果。你想在3秒钟的时间内重复整个动画3次吗?或者您想说将整个动画的持续时间延长到9秒,以便动画重复(旋转和缩放/淡入)?后者!:)我希望整个动画能持续9秒。在这9秒钟内,“橙色视图”就可以了
import UIKit

class OrangeView: UIView {



override func layoutSubviews() {
    super.layoutSubviews()

  let duration: TimeInterval = 9.0

  self.transform = CGAffineTransform.identity

  // initial transform
  self.alpha = 1
  self.transform = CGAffineTransform(scaleX: 0.1, y: 0.1)

  // start rotation
  rotate(duration: duration)

  // scaling and fading
  scaleUpAndDown(desiredRepetitions: 3, initalDuration: duration)


  }

func rotate(duration: TimeInterval) {
                UIView.animate(withDuration: duration/2.0,
                               delay: 0.0,
                               options: [.curveLinear], animations: {
                                let angle = Double.pi
                                self.transform = self.transform.rotated(by: CGFloat(angle))
                }, completion: {[weak self] finished in
  guard let strongSelf = self else {
    return
  }
  if finished &&
    strongSelf.transform != CGAffineTransform.identity {
    strongSelf.rotate(duration: duration)
  } else {
    // rotation ending
  }
})

  }

func scaleUpAndDown(timesRepeated: Int = 0, desiredRepetitions: Int, initalDuration: TimeInterval) {

guard timesRepeated < desiredRepetitions,
  desiredRepetitions > 0, initalDuration > 0 else {
  self.transform = CGAffineTransform.identity
    return
}
let repeatedCount = timesRepeated + 1

let scalingDuration = initalDuration/2.0/Double(desiredRepetitions)

UIView.animate(withDuration: scalingDuration,
               delay: 0.0,
               animations: {
                let desiredOriginalScale: CGFloat = 0.8

                let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
                let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale

                self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
                self.alpha = 1
              }) { (true) in
                UIView.animate(withDuration:scalingDuration,
                               delay: 0.0,
                               animations: {

                                let desiredOriginalScale: CGFloat = 0.1

                                let scaleX = abs(CGAffineTransform.identity.a / self.transform.a) * desiredOriginalScale
                                let scaleY = abs(CGAffineTransform.identity.d / self.transform.d) * desiredOriginalScale
                                  self.transform = self.transform.scaledBy(x: scaleX, y: scaleY)
                                  self.alpha = 0
                }) { finshed in
                  self.scaleUpAndDown(timesRepeated: repeatedCount, desiredRepetitions: desiredRepetitions, initalDuration: initalDuration);
                }
              }

  }

}