Swift-UIView Animations、Transiti
2020-03-06 本文已影响0人
爱玩游戏的iOS菜鸟
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) :
- 动画执行过程速度的改变,会有一个加速度或者一个减速度。
- .curveEaseIn
- .curveEaseOut
- .curveEaseInOut
- .curveLinear
- 动画执行次数
- .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(过渡动画)
![](https://img.haomeiwen.com/i7361389/dec3ddd1b51c8116.png)
过渡动画的类型options:
- . transitionFlipFromLeft、. transitionFlipFromRight
- . transitionFlipFromTop、. transitionFlipFromBottom
- . transitionCurlUp、. transitionCurlDown
- . transitionCrossDissolve
Transitions的2个重要方法:
-
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)
-
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
})
}