前面我们已经搞定了一个小例子的Demo, 现在让我们接下来看更炫酷的动画界面:
PS: 已更新到Swift 2.0, 支持Xcode 7, iOS 9
1.界面布局
小细节
2.添加假数据
import Foundation
struct FlightData {
let summary: String
let flightNr: String
let gateNr: String
let departingFrom: String
let arrivingTo: String
let weatherImageName: String
let showWeatherEffects: Bool
let isTakingOff: Bool
let flightStatus: String
}
let londonToParis = FlightData(
summary: "01 Apr 2015 09:42",
flightNr: "ZY 2014",
gateNr: "T1 A33",
departingFrom: "LGW",
arrivingTo: "CDG",
weatherImageName: "bg-snowy",
showWeatherEffects: true,
isTakingOff: true,
flightStatus: "Boarding")
let parisToRome = FlightData(
summary: "01 Apr 2015 17:05",
flightNr: "AE 1107",
gateNr: "045",
departingFrom: "CDG",
arrivingTo: "FCO",
weatherImageName: "bg-sunny",
showWeatherEffects: false,
isTakingOff: false,
flightStatus: "Delayed")
3.制作雪花控件
import UIKit
class SnowView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
let emitter = layer as! CAEmitterLayer
emitter.emitterPosition = CGPoint(x: bounds.size.width / 2, y: 0)
emitter.emitterSize = bounds.size
emitter.emitterShape = kCAEmitterLayerRectangle
let emitterCell = CAEmitterCell()
emitterCell.contents = UIImage(named: "flake.png")!.CGImage
emitterCell.birthRate = 200
emitterCell.lifetime = 3.5
emitterCell.color = UIColor.whiteColor().CGColor
emitterCell.redRange = 0.0
emitterCell.blueRange = 0.1
emitterCell.greenRange = 0.0
emitterCell.velocity = 10
emitterCell.velocityRange = 350
emitterCell.emissionRange = CGFloat(M_PI_2)
emitterCell.emissionLongitude = CGFloat(-M_PI)
emitterCell.yAcceleration = 70
emitterCell.xAcceleration = 0
emitterCell.scale = 0.33
emitterCell.scaleRange = 1.25
emitterCell.scaleSpeed = -0.25
emitterCell.alphaRange = 0.5
emitterCell.alphaSpeed = -0.15
emitter.emitterCells = [emitterCell]
}
required init(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override class func layerClass() -> AnyClass {
return CAEmitterLayer.self
}
}
4.实现代码
声明一个枚举
// 1.声明一个动画时间的枚举类型
enum AnimationDirection: Int {
case Positive = 1
case Negative = -1
}
关联控件
class ViewController: UIViewController {
// 2.关联控件
@IBOutlet weak var bgImageView: UIImageView!
@IBOutlet weak var summaryIcon: UIImageView!
@IBOutlet weak var summary: UILabel!
@IBOutlet weak var flightNr: UILabel!
@IBOutlet weak var gateNr: UILabel!
@IBOutlet weak var departingFrom: UILabel!
@IBOutlet weak var arrivingTo: UILabel!
@IBOutlet weak var planeImage: UIImageView!
@IBOutlet weak var flightStatus: UILabel!
@IBOutlet weak var statusBanner: UIImageView!
// 3.实例化SnowView
var snowView: SnowView!
}
设置viewDidLoad方法
// 4.设置viewDidLoad
override func viewDidLoad() {
super.viewDidLoad()
// 4.1.把icon添加到summary中
summary.addSubview(summaryIcon)
// 4.2.使得icon的y轴等于summary高度的2分之1
summaryIcon.center.y = summary.frame.size.height / 2
// 4.3.初始化snowView的位置
snowView = SnowView(frame: CGRect(x: -150, y: -100, width: 300, height: 50))
// 4.4.实例化一个UIView视图, 并且设置它的位置为view.frame, dx轴为0, dy轴为50
let snowClipView = UIView(frame: CGRectOffset(view.frame, 0, 50))
// 4.4.设置超出该视图的控件都剪切掉
snowClipView.clipsToBounds = true
// 4.5.把之前设置好的snowView添加到snowClipView上
snowClipView.addSubview(snowView)
// 4.6.把设置好的snowClipView添加到self.view上
view.addSubview(snowClipView)
// 4.7.调用自定义好的changFlightDataTo方法, 并且把数据模型londonToParis作为参数传入
changeFlightDataTo(londonToParis)
}
自定义更改数据的动画方法
// 5.自定义更改内容的方法
func changeFlightDataTo(data: FlightData, animate: Bool = false) {
// 5.1.判断animate是否为真
if animate {
// 5.2.调用自定义的飞机动画
planeDepart()
// 5.3.调用自定义的summary的文字切换动画
summarySwitchTo(data.summary)
// 5.4.调用自定义的背景图切换动画
fadeImageView(bgImageView, toImage: UIImage(named: data.weatherImageName)!, showEffects: data.showWeatherEffects)
// 5.5.获取动画方向, 判断isTakingOff是否为真, 如果为真就正方向, 否则就是反方向
let direction: AnimationDirection = data.isTakingOff ? AnimationDirection.Positive : AnimationDirection.Negative
// 5.6.调用自定义的文本切换动画, 并且把获取到的动画方向传入
cubeTransition(label: flightNr, text: data.flightNr, direction: direction)
cubeTransition(label: gateNr, text: data.gateNr, direction: direction)
cubeTransition(label: flightStatus, text: data.flightStatus, direction: direction)
// 5.7.获取Departing的文字切换偏移量
let offsetDeparting = CGPoint(x: CGFloat(direction.rawValue * 80), y: 0.0)
// 5.8.获取Arriving的文字切换偏移量
let offsetArriving = CGPoint(x: 0.0, y: CGFloat(direction.rawValue * 50))
// 5.9.调用自定义的文字切换动画, 并且把所要切换的x轴偏移量传入
moveLabel(departingFrom, text: data.departingFrom, offset: offsetDeparting)
// 5.10.调用自定义的文字切换动画, 并且把所要切换的y轴偏移量传入
moveLabel(arrivingTo, text: data.arrivingTo, offset: offsetArriving)
} else {
// 5.11.把FlightData里的值依依赋给关联好的控件
summary.text = data.summary
flightNr.text = data.flightNr
gateNr.text = data.gateNr
departingFrom.text = data.departingFrom
arrivingTo.text = data.arrivingTo
flightStatus.text = data.flightStatus
bgImageView.image = UIImage(named: data.weatherImageName)
// 5.12.设置snowView的隐藏属性
snowView.hidden = !data.showWeatherEffects
}
// 5.13.调用自定义好的延迟方法, 并且设置每隔三秒就会自动回调一次3.0秒
delay(seconds: 3.0) {
// 5.13.1.调用changeFlightDataTo方法, 并且在传入的参数中使用三目运算符, 判断data.isTakingOff是否为真, 如果是, 传入parisToRome, 否则就传入londonToParis
self.changeFlightDataTo(data.isTakingOff ? parisToRome : londonToParis, animate: true)
}
}
自定义切换背景图的动画方法
// 6.自定义背景图淡入淡出的方法
func fadeImageView(imageView: UIImageView, toImage: UIImage, showEffects: Bool) {
// 6.1.自定义transitionWithView, 传入外部ImageView, 设置好持续时间, 动画类型, 开始动画
UIView.transitionWithView(imageView, duration: 1.0,
options: .TransitionCrossDissolve, animations: {
imageView.image = toImage
}, completion: nil)
// 6.2.自定义animateWithDuration, 设置好持续时间, 延迟时间, 动画类型, 开始动画
UIView.animateWithDuration(1.0, delay: 0.0,
options: .CurveEaseOut, animations: {
// 6.3.判断snowView的透明度, 如果showEffects为真, 那么就显示, 否则就隐藏
self.snowView.alpha = showEffects ? 1.0 : 0.0
}, completion: nil)
}
自定义延迟动画的方法
// 7.自定义一个延迟的方法
func delay(seconds seconds: Double, completion:()->()) {
// 7.1.创建一个默认的时间值
let popTime = dispatch_time(DISPATCH_TIME_NOW, Int64( Double(NSEC_PER_SEC) * seconds ))
// 7.2.在主线程中使用创建好的默认时间值
dispatch_after(popTime, dispatch_get_main_queue()) {
completion()
}
}
自定义飞机的动画方法
// 8.自定义飞机动画
func planeDepart() {
// 8.1.获取飞机的中心点
let originalCenter = planeImage.center
// 8.2.自定义关键帧动画, 设置持续时间, 延迟时间, 动画类型, 开始动画
UIView.animateKeyframesWithDuration(1.5, delay: 0.0, options: [], animations: {
// 8.3.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.25, animations: {
// 8.3.1.设置飞机的x轴和y轴
self.planeImage.center.x += 80.0
self.planeImage.center.y -= 10.0
})
// 8.5.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.1, relativeDuration: 0.4) {
// 8.5.1.设置飞机的transform
self.planeImage.transform = CGAffineTransformMakeRotation(CGFloat(-M_PI_4/2))
}
// 8.6.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.25, relativeDuration: 0.25) {
// 8.6.1.设置飞机的x轴, y轴, 以及透明度
self.planeImage.center.x += 100.0
self.planeImage.center.y -= 50.0
self.planeImage.alpha = 0.0
}
// 8.7.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.51, relativeDuration: 0.01) {
// 8.7.1.设置飞机的transform, 中心点
self.planeImage.transform = CGAffineTransformIdentity
self.planeImage.center = CGPoint(x: 0.0, y: originalCenter.y)
}
// 8.8.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.55, relativeDuration: 0.45) {
// 8.8.1.设置飞机的透明度, 中心点
self.planeImage.alpha = 1.0
self.planeImage.center = originalCenter
}
}, completion: nil)
}
自定义内容切换的动画方法
// 9.自定义切换动画
func summarySwitchTo(summaryText: String) {
// 9.1.自定义关键帧动画, 设置持续时间, 延迟时间, 动画类型, 开始动画
UIView.animateKeyframesWithDuration(1.0, delay: 0.0, options: [], animations: {
// 9.2.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.0, relativeDuration: 0.45, animations: {
// 9.2.1.设置summary的y轴
self.summary.center.y -= 100.0
})
// 9.3.自定义关键帧动画开始的时间, 相对持续时间, 开始动画
UIView.addKeyframeWithRelativeStartTime(0.5, relativeDuration: 0.45, animations: {
// 9.3.1.设置summary的y轴
self.summary.center.y += 100.0
})
}, completion: nil)
// 9.4.调用自定义的延迟方法
delay(seconds: 0.5, completion: {
// 9.4.1.设置summary的文本内容
self.summary.text = summaryText
})
}
自定义动画方向切换的方法
// 10.自定义方向的切换动画
func cubeTransition(label label: UILabel, text: String, direction: AnimationDirection) {
// 10.1.自定义一个UILabel, 位置大小和传入进来的Label位置大小一致
let auxLabel = UILabel(frame: label.frame)
// 10.2.获取传入进来的text内容
auxLabel.text = text
// 10.3.获取传入进来的Label文字大小
auxLabel.font = label.font
// 10.4.获取传入进来的Label文字位置
auxLabel.textAlignment = label.textAlignment
// 10.5.获取传入进来的Label文字颜色
auxLabel.textColor = label.textColor
// 10.6.设置auxLabel的背景颜色
auxLabel.backgroundColor = label.backgroundColor
// 10.7.设置auxLabl偏移量
let auxLabelOffset = CGFloat(direction.rawValue) *
label.frame.size.height/2.0
// 10.8.设置auxLabel的transform属性, 并且把对应的大小, translation的属性传入
auxLabel.transform = CGAffineTransformConcat(
CGAffineTransformMakeScale(1.0, 0.1),
CGAffineTransformMakeTranslation(0.0, auxLabelOffset))
// 10.9.把auxLabel添加到传入进来的label.superview
label.superview!.addSubview(auxLabel)
// 10.10.自定义animateWithDuration动画, 设置开始时间, 延迟时间, 动画类型, 开始动画
UIView.animateWithDuration(0.5, delay: 0.0, options: .CurveEaseOut, animations: {
// 10.11.设置auxLabel的transform
auxLabel.transform = CGAffineTransformIdentity
// 10.12.设置auxLabel的transform属性, 并且把对应的大小, translation的属性传入
label.transform = CGAffineTransformConcat(
CGAffineTransformMakeScale(1.0, 0.1),
CGAffineTransformMakeTranslation(0.0, -auxLabelOffset))
// 10.13.动画完成之后
}, completion: {_ in
// 10.13.1.把auxLabel.text赋值给传入进来的label.text
label.text = auxLabel.text
// 10.13.2.设置传入进来的labeltransform属性
label.transform = CGAffineTransformIdentity
// 10.13.3.把auxLabel从superview中删除
auxLabel.removeFromSuperview()
})
}
自定义移动标签的动方法
// 11.自定义移动标签的方法
func moveLabel(label: UILabel, text: String, offset: CGPoint) {
// 11.1.自定义一个UILabel, 位置大小和传入进来的Label位置大小一致
let auxLabel = UILabel(frame: label.frame)
// 11.2.获取传入进来的text内容
auxLabel.text = text
// 11.3.获取传入进来的Label文字大小
auxLabel.font = label.font
// 11.4.获取传入进来的Label文字位置
auxLabel.textAlignment = label.textAlignment
// 11.5.获取传入进来的Label文字颜色
auxLabel.textColor = label.textColor
// 11.6.设置auxLabel的背景颜色
auxLabel.backgroundColor = UIColor.clearColor()
// 11.7.设置auxLabel的transform属性为传入进来的offset的x轴和y轴
auxLabel.transform = CGAffineTransformMakeTranslation(offset.x, offset.y)
// 11.8.设置auxLabel的透明度
auxLabel.alpha = 0
// 11.9.把设置好的auxLabel添加到view上
view.addSubview(auxLabel)
// 11.10.自定义animateWithDuration动画, 设置开始时间, 延迟时间, 动画类型, 开始动画
UIView.animateWithDuration(0.5, delay: 0.0,
options: .CurveEaseIn, animations: {
// 11.10.1.设置传入进来的Label的transform属性为传入进来的offset的x轴和y轴
label.transform = CGAffineTransformMakeTranslation(
offset.x, offset.y)
// 11.10.2.设置传入进来的Label透明度
label.alpha = 0.0
}, completion: nil)
// 11.11.自定义animateWithDuration动画, 设置开始时间, 延迟时间, 动画类型, 开始动画
UIView.animateWithDuration(0.25, delay: 0.1,
options: .CurveEaseIn, animations: {
// 11.11.1.设置传入进来的Label的transform属性为传入进来的offset的x轴和y轴
auxLabel.transform = CGAffineTransformIdentity
// 11.11.2.设置传入进来的Label透明度
auxLabel.alpha = 1.0
// 11.12.完成动画之后的操作
}, completion: {_ in
// 11.12.1.把auxLabel从Superview中删除
auxLabel.removeFromSuperview()
// 11.12.2.把传入进来的text赋值给传入进来的label.text
label.text = text
// 11.12.3.设置传入进来的label透明度
label.alpha = 1.0
// 11.12.4.设置传入进来的label的transform属性为恒等转变
label.transform = CGAffineTransformIdentity
})
}
5.最终效果
项目地址: 链接: http://pan.baidu.com/s/1pJp8NQ7 密码: qhr1
本文通过一个实际案例,介绍了如何使用Swift语言实现iOS应用中的动画效果,包括界面布局、添加假数据、制作雪花控件等,并详细讲解了动画实现的具体步骤。
1772

被折叠的 条评论
为什么被折叠?



