文章目录
动画都是通过设置起始状态,结束状态,经过时间三个步骤实现的
Spring动画
一般usingSpringWithDamping设置为0.3或0.4
UIView.animate(
withDuration: 0.3,
delay: 0,
usingSpringWithDamping: 0.4,//弹性阻尼 0-1
initialSpringVelocity: 10,//初始弹簧速度
options: [],
animations: {
self.menuBarAnimate()
},
completion: nil
)
通过改变约束形成动画
改变约束常量constant
动画的函数withDuration设置时间
UIView.animate(withDuration: 0.3) {
self.menuBarAnimate()
}
func menuBarAnimate() {
menuHeight.constant = menuIsOpen ? 200 : 100
btnTrailing.constant = menuIsOpen ? 20 : 8
let angle = menuIsOpen ? CGFloat.pi/4 : 0 //2.按钮的旋转动画
buttonMenu.transform = CGAffineTransform(rotationAngle: angle)
view.layoutIfNeeded()//1.让根视图立刻重新布局
}
image的初始化,设置动画和销毁
func showItem(_ index: Int) {
let imageView = UIImageView(image: UIImage(named: "summericons_100px_0\(index).png"))
imageView.backgroundColor = UIColor(red: 0.0, green: 0.0, blue: 0.0, alpha: 0.5)
imageView.layer.cornerRadius = 5.0//设置圆角属性需要加layer
//1.用代码写的控件,默认情况下xcode会帮我们推断出约束,我们要自定义约束,所以定为false
imageView.translatesAutoresizingMaskIntoConstraints = false
view.addSubview(imageView)//在根视图上加子视图
//1.设定初始约束
let conWidth = imageView.widthAnchor.constraint(equalToConstant: 100)
let conHight = imageView.heightAnchor.constraint(equalTo: imageView.widthAnchor)
let conX = imageView.centerXAnchor.constraint(equalTo: view.centerXAnchor)
// let conY = imageView.bottomAnchor.constraint(equalTo: view.bottomAnchor, constant: 100)
let conY = imageView.topAnchor.constraint(equalTo: view.bottomAnchor)
//传入约束
NSLayoutConstraint.activate([conWidth,conHight,conX,conY])
//约束生效
view.layoutIfNeeded()
// 设定结束约束+经过时间
UIView.animate(
withDuration: 0.5,//时间
delay: 0,//延迟多久
usingSpringWithDamping: 0.4,
initialSpringVelocity: 10,
options: .curveEaseOut,//动画的类型
animations: {//动画过程中要进行的操作
conWidth.constant = 150
conY.constant = -300
self.view.layoutIfNeeded()
},
completion: nil
)
//没有Spring的动画
// UIView.animate(
// withDuration: 0.5, //时间
// delay: 0, //延迟多久
// options: .curveEaseOut, //动画的类型
// animations: { //动画过程中要进行的操作
// conWidth.constant = 150
// conY.constant = -300
// self.view.layoutIfNeeded()
// },
//
// completion: nil //动画结束
// )
//延迟一会消失
UIView.animate(
withDuration: 0.5,
delay: 1.5,
animations: {
conWidth.constant = 100
conY.constant = 0
self.view.layoutIfNeeded()
}) { _ in
//销毁ImageView
imageView.removeFromSuperview()
}
}
}
改变约束的乘数multiplier
其实multiplier值无法改变,但是可以设置两个multiplier不同的约束,在不同的情况设置他们的isActive
1.添加约束并且把Priority变小,取消Installed
2.添加到view controller
@IBOutlet weak var titleCenterX: NSLayoutConstraint!
@IBOutlet weak var titleCenterXOpen: NSLayoutConstraint!
3.设置isActive
UIView.animate(withDuration: 0.3) {
self.menuBarAnimate()
}
func menuBarAnimate() {
//1.对居中对齐的约束改变,先添加一个约束然后设置isActive
titleCenterXOpen.isActive = menuIsOpen
titleCenterX.isActive = !menuIsOpen
view.layoutIfNeeded()//1.让根视图立刻重新布局
}
通过改变元素的属性形成动画
改变alpha值
两个不同背景淡入淡出的无缝切换
func fade(toImage: UIImage, showEffects: Bool) {
//背景图的imageview的淡出淡入
//在View中放置两个ImageView一个淡出后下面一个消失,由此做到两个View的淡出淡入
let temp = UIImageView(frame: bgImageView.frame)
temp.image = toImage
temp.alpha = 0 //完全透明
view.insertSubview(temp, aboveSubview: bgImageView)//设置该ImageView在bgImageView的上面
UIView.animate(
withDuration: 0.5,
animations: {
temp.alpha = 1
}) { _ in
self.bgImageView.image = toImage
temp.removeFromSuperview()
}
//雪景view的淡出淡入
UIView.animate(withDuration: 1) {
self.snowView.alpha = showEffects ? 1 : 0
}
}
改变transform的translation
func duplicateLabel(label: UILabel) -> UILabel {
let newLabel = UILabel(frame: label.frame)
newLabel.font = label.font
newLabel.textAlignment = label.textAlignment
newLabel.textColor = label.textColor
newLabel.backgroundColor = label.backgroundColor
return newLabel
}
func moveLabel(currentLabel:UILabel,toText:String) {
//新建一个临时label
let temp = duplicateLabel(label: currentLabel)
temp.text = toText
temp.transform = CGAffineTransform(translationX: 80, y: 0)
temp.alpha = 0
view.addSubview(temp)
//移出当前label+移入临时label
UIView.animate(
withDuration: 0.5,
animations: {
currentLabel.transform = CGAffineTransform(translationX: 80, y: 0)
currentLabel.alpha = 0
temp.transform = .identity//还原transform值
temp.alpha = 1
}) { _ in
currentLabel.text = toText
currentLabel.transform = .identity
currentLabel.alpha = 1
temp.removeFromSuperview()
}
//上述动作完成后更新实际label的text,并remove掉临时label
}
关键帧动画
func planeDepart() {
let y = planeImage.center.y
let x = planeImage.center.x
UIView.animateKeyframes(
withDuration: 1,
delay: 0,
animations: {
//1.右移80,上移10
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 0.25) {
self.planeImage.center.x += 80
self.planeImage.center.y += 10
}
//2.逆时针旋转22.5
UIView.addKeyframe(withRelativeStartTime: 0.1, relativeDuration: 0.4) {
self.planeImage.transform = CGAffineTransform(rotationAngle: -.pi/8)
}
//3.往右上移出屏幕,淡出
UIView.addKeyframe(withRelativeStartTime: 0.25, relativeDuration: 0.25) {
self.planeImage.center.x += 100
self.planeImage.center.y -= 50
self.planeImage.alpha = 0
}
//4.回到屏幕左边,准备淡入
UIView.addKeyframe(withRelativeStartTime: 0.5, relativeDuration: 0.01) {
self.planeImage.center.x = 0
self.planeImage.center.y = y
self.planeImage.transform = .identity
}
//5.回到原先位置,淡入
UIView.addKeyframe(withRelativeStartTime: 0.55, relativeDuration: 0.45) {
self.planeImage.center.x = x
self.planeImage.center.y = y
self.planeImage.alpha = 1
}
},
completion: nil
)
}