Swift-UIView Animations、Transitions

Animations

  • UIView 层面的动画只是对 layer 层部分属性的封装

在UIView中执行动画,将需要动画的属性放入animations闭包中即可

  • 多个View的多个属性可同时执行
  • animations闭包中可添加UIView.performWithoutAnimation加入其中需要不需要动画的属性
 UIView.animate(withDuration: 5.0) {
   self.parentV.backgroundColor = UIColor.red
   self.parentV.x = 40
   self.parentV.alpha = 0.5
   self.childV.width = 40
   UIView.performWithoutAnimation {//可以对其中需要变换的属性去掉动画
     self.childV.height = 40
   }
 }
UIVisualEffectView(毛玻璃效果)

UIVisualEffectView 的 effect 属性也可以动画:动画前设置为 nil,在animations: 中设置effect

  let effect = UIBlurEffect(style: .dark)
  let effectView = UIVisualEffectView(frame: CGRect(x: 15, y: 280, width: 50, height: 50))
  effectView.effect = nil
  view.addSubview(effectView)
  UIView.animate(withDuration: 3.0) {
    effectView.effect = effect
  }
UIView 动画 options

实际上UIView的动画还有很多参数可以配置

UIView.animate(withDuration:, delay: , options: , animations: , completion: )

其中参数:

  • withDuration:动画的执行速度
  • delay:延时动画时间,默认无延时
  • options:附加选项,UIViewAnimationOptions指定多个
  • animations:执行动画的闭包
  • completion:动画完成后执行的闭包,可以为nil,也可以在这里链接下一个动画

下面是一些主要的options (UIView.AnimationOptions) :

  1. 动画执行过程速度的改变,会有一个加速度或者一个减速度。
  • .curveEaseIn
  • .curveEaseOut
  • .curveEaseInOut
  • .curveLinear
  1. 动画执行次数
  • .repeat : 指定这个选项后,动画会无限重复
  • .autoreverse:往返动画,从开始执行到结束后,又从结束返回开始。
let parentFrame = parentV.frame
//设置自动往返
UIView.animate(withDuration: 2.0, delay: 1.0, options: UIView.AnimationOptions.autoreverse, animations: {
  UIView.setAnimationRepeatCount(5)//设置指定循环次数
  self.parentV.x = 50
  self.parentV.width = 50
  self.parentV.height = 50
  }, completion: { (complete) in
    self.parentV.frame = parentFrame//因为动画过程中,view的frame都已改变,所以在结束后需要重新赋原值
  })

设置无限重复,需要添加一个repeat

let opts: UIViewAnimationOptions = [.autoreverse , .repeat]
取消动画
  • 调用 layer 层的 removeAllAnimations
self.parentV.layer.removeAllAnimations()
  finalFrame = CGRect(x: 50, y: parentV.y, width: parentV.width, height: parentV.height)
  UIView.animate(withDuration: 3.0, delay: 1.0, options: [.curveEaseIn], animations: {
    self.parentV.x = 50
    }, completion: { (complete) in
  })

记录用一个0.2秒的动画到终点,先拿到当前的位置。

  self.parentV.layer.position = self.parentV.layer.presentation()!.position
  self.parentV.layer.removeAllAnimations()
    UIView.animate(withDuration: 0.2) {
    self.parentV.frame = self.finalFrame
  }
transform也可以使用动画
  UIView.animate(withDuration: 5.0) {
    self.parentV.transform = CGAffineTransform.identity.translatedBy(x: -100, y: 0).rotated(by: 0.5).scaledBy(x: 0.5, y: 0.5)
  }
Spring 弹性动画
  UIView.animate(withDuration: 2.0, delay: 1.0, usingSpringWithDamping: 0.1, initialSpringVelocity: 5, options: [], animations: {
    self.parentV.x += 100
    self.parentV.width = 50
    self.parentV.height = 50
  }) { (complete) in

  }

其中的参数:

  • usingSpringWithDamping 值范围0~1 值越小摇晃的越剧烈 晃动范围越大
  • initialSpringVelocity 表示一个初始速度, 动画执行快慢由他和duration共同决定
AnimateKeyframes 关键帧动画
  • 把动画分成一个一个小的阶段,然后在将这些结合在一起。
  • 使用 UIView.animateKeyframes(withDuration:,delay:,options:,animations:,completion:)
  • 在 animations 的闭包中调用 UIView.addKeyframe(withRelativeStartTime: , relativeDuration: , animations:) 添加关键帧
let oringinFrame = parentV.frame
        var pFrame = oringinFrame
        var start = 0.0
        let count = 5
        let duration = 1.0 / 5.0
        
        let dx: CGFloat = -100
        let dy: CGFloat = 50
        var dir: CGFloat = 1

        UIView.animateKeyframes(withDuration: 4.0, delay: 2.0, options: [.autoreverse, .repeat], animations: {
            for _ in 0..<count{
                UIView.addKeyframe(withRelativeStartTime: start, relativeDuration: duration) {
                    pFrame.origin.x = dx * dir
                    pFrame.origin.y += dy
                    pFrame.size.width += dy * dir
                    pFrame.size.height += dy * dir
                    self.parentV.frame = pFrame
                }
                start += duration
                if start > 1.0 {
                    break
                }
                dir *= -1//换方向
            }
        }, completion: { (complete) in
            self.parentV.frame = oringinFrame
        })

其中的参数:

  • startTime 是从0 - 1 的相对时间 ,相对于整体动画的时间
  • duration:是一个相对时间,值为0...1

Transitions(过渡动画)

transition方法

过渡动画的类型options:

  • . transitionFlipFromLeft、. transitionFlipFromRight
  • . transitionFlipFromTop、. transitionFlipFromBottom
  • . transitionCurlUp、. transitionCurlDown
  • . transitionCrossDissolve

Transitions的2个重要方法:

  1. UIView.transition(with:, duration: , options: , animations, completion:)
    自定义View,并重写draw()方法
    注意:默认情况下,一个视图的子视图在transition动画期间改变layout,这个改变是不会有动画的,将在transition结束的时候直接改变,如果想要做动画改变,option需要加上.allowAnimatedContent
class CustomView: UIView {
  var reverse = false
  override func draw(_ rect: CGRect) {
    let f = self.bounds.insetBy(dx: 10, dy: 10)
    let context = UIGraphicsGetCurrentContext()
    if self.reverse {
      context?.strokeEllipse(in: f)
    }else{
      context?.stroke(f)
    }
  }
}
//点击翻转重绘
customV.reverse = !customV.reverse
        UIView.transition(with: customV , duration: 0.6 , options: .transitionFlipFromLeft , animations: {
            self.customV.setNeedsDisplay()
        }, completion: nil)
customV.reverse = !customV.reverse
        UIView.transition(with: customV , duration: 0.6 , options: [.transitionFlipFromLeft,.allowAnimatedContent] , animations: {
            self.flag = !self.flag
            let flagWidth = CGFloat(self.flag ? 20 : 50)
            self.customV.width = flagWidth
            self.customV.height = flagWidth
            self.customV.setNeedsDisplay()
        }, completion: nil)
  1. UIView.transition(from: , to:, duration:, options:, completion:)
    该方法需要两个view ,第一个会被第二个替换掉。整个transition动画会在他们的superview进行动画
  parentV.addSubview(customV)

  override func touchesBegan(_ touches: Set<UITouch>, with event: UIEvent?) {
    let newCustomV = UILabel(frame: self.customV.frame)
    newCustomV.text = self.customV.text == "Hello" ? "World" : "Hello"
    newCustomV.textColor = UIColor.white
    newCustomV.sizeToFit()
    //翻转的是其superView(parentV)
    UIView.transition(from: self.customV , to: newCustomV , duration: 0.8 , options: .transitionFlipFromLeft , completion: { _ in
      self.customV = newCustomV
    })
  }
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

  • 很惭愧第一次写简书,竟是因为我的嘟嘟和妍妍。这两个小家伙走进我的生活中,带给我无穷的快乐。很多次想记录他...
    严壮壮阅读 1,161评论 3 4
  • 不知不觉嘟嘟回乡已经过大半个月,嘟嘟爸爸昨儿视频说有比嘟嘟小两个月的宝宝都会听爸爸妈妈读书了,让嘟嘟妈妈...
    何丽娜阅读 466评论 0 0
  • 要想清楚,足球评论员,输球全在你们,你们不早给主教练意见?比赛完了开始嘟嘟了,到底是一种怎么样的存在。 从这个角度...
    dcd3170620de阅读 348评论 0 0
  • 大壮和嘟嘟是母子,他们都有一身的黄毛,常含泪水的眼睛。大壮体型不大,瘦瘦的,弟弟们可能是希望大壮可以有一个健壮的体...
    裟雪妮阅读 596评论 1 1
  • 第2章 船驶过去,桅杆和船身都过去,人生全部见鬼的激流都从你身上流过,从她身上流过,从紧跟着你的所有家伙身上流过。...
    laipeiyuan阅读 495评论 0 0

友情链接更多精彩内容