iOS 動畫
在iOS實際開發中常用的動畫總結下來包含3種:
- UIViewAnimation動畫
- CoreAnimation核心動畫
- 其他動畫
[TOC]
##UIViewAnimation動畫 UIView的兩種動畫api包含 方法形式 和 block 形式, 其中包含三種動畫實現
- UIView(UIViewAnimation)
- UIView (UIViewKeyframeAnimation)
- UIViewControllerAnimatedTransitioning
###函式形式
// 開始動畫
UIView.beginAnimations("Identifier", context: nil)
// 設定動畫代理
UIView.setAnimationDelegate(self)
// 通過 #selector 選擇器 新增開始動畫方法
UIView.setAnimationWillStart(#selector(animationAction))
// 通過 #selector 選擇器 新增結束動畫方法
UIView.setAnimationDidStop(#selector(animationAction))
// 設定動畫時間間隔
UIView.setAnimationDuration(1.0)
// 設定動畫延遲
UIView.setAnimationDelay(0)
// 設定動畫開始的時間,預設是現在開始
UIView.setAnimationStart(Date())
// 設定動畫曲線
UIView.setAnimationCurve(.easeInOut)
// 設定動畫重複次數,預設是 0
UIView.setAnimationRepeatCount(0) // 0 無線迴圈
// 自動返回原始狀態
UIView.setAnimationRepeatAutoreverses(false) // default = NO. used if repeat count is non-zero
// 設定動畫的開始是從現在的狀態開始, 預設是 false
UIView.setAnimationBeginsFromCurrentState(false)
// 用來開啟或禁止動畫顯示
UIView.setAnimationsEnabled(true)
// 設定動畫的過渡效果
UIView.setAnimationTransition(.curlUp, for: redView, cache: false)
// 設定 UIView 的動畫屬性
redView.transform = CGAffineTransform(rotationAngle: 90)
redView.transform = CGAffineTransform(scaleX: 0.3, y: 0.3)
redView.transform = CGAffineTransform(translationX: 0, y: 200)
// 動畫的狀態
print(UIView.areAnimationsEnabled)
// 標誌動畫程式碼結束,程式會建立新的執行緒,並準備執行動畫
UIView.commitAnimations()
複製程式碼
UIView.beginAnimations("Identifier", context: nil)
UIView.setAnimationDuration(1)
objectView.center.x = objectView.center.x + 100
UIView.commitAnimations()
複製程式碼
###block形式 將動畫實現封裝在block區域,引數構建在類方法上。
UIView.animate(withDuration: TimeInterval,
animations: ()->Void)
UIView.animate(withDuration: TimeInterval,
animations: ()->Void,
completion: ()->Void)
// 帶動畫曲線動畫
UIView.animate(withDuration: TimeInterval,
delay: TimeInterval,
options: UIViewAnimationOptions,
animations: ()->Void,
completion: (()->Void)?)
// 帶彈性動畫
UIView.animate(withDuration: TimeInterval,
delay: TimeInterval,
usingSpringWithDamping: 0,
initialSpringVelocity: 0,
options: UIViewAnimationOptions,
animations: ()->Void,
completion: (()->Void)?)
複製程式碼
UIView.animate(withDuration: 1.0) {
self.objectView.center.x = self.objectView.center.x - 100
}
複製程式碼
更多引數動畫函式
//.curveEaseIn, .autoreverse, .repeat
UIView.animate(withDuration: 1.0, delay: 0, options: [.curveEaseIn, .autoreverse, .repeat], animations: {
self.objectView.center.x = self.objectView.center.x - 100
}, completion: nil)
//delay
UIView.animate(withDuration: 1.0, delay: 0.5, options: .curveEaseIn, animations: {
self.objectView2.center.x = self.objectView2.center.x - 100
}, completion: nil)
複製程式碼
各個引數的含義
Duration :動畫執行的時長
delay :延時時長,即上一個動畫執行完以後多久再執行下一個動畫
options :一些樣式的選取
animations:我們想要實現的動畫效果
completion:動畫執行完我們還想做的事情
複製程式碼
options
1.屬性設定
UIViewAnimationOptionLayoutSubviews // 動畫過程中保證子檢視跟隨運動
UIViewAnimationOptionAllowUserInteraction // 動畫過程中允許使用者互動
UIViewAnimationOptionBeginFromCurrentState // 所有檢視從當前狀態開始執行
UIViewAnimationOptionRepeat // 重複執行動畫
UIViewAnimationOptionAutoreverse // 動畫執行到結束點後仍然以動畫方式回到初始點
UIViewAnimationOptionOverrideInheritedDuration // 忽略巢狀動畫時間設定
UIViewAnimationOptionOverrideInheritedCurve // 忽略巢狀動畫速度設定
UIViewAnimationOptionAllowAnimatedContent // 動畫過程中重繪檢視(注意僅僅適用於轉場動畫)
UIViewAnimationOptionShowHideTransitionViews // 檢視切換時直接隱藏舊檢視、顯示新檢視,而不是將舊檢視從父檢視移除(僅僅適用於轉場動畫)
UIViewAnimationOptionOverrideInheritedOptions //不繼承父動畫設定或動畫型別
複製程式碼
2.動畫速度控制
UIViewAnimationOptionCurveEaseInOut // 動畫先緩慢,然後逐漸加速
UIViewAnimationOptionCurveEaseIn // 動畫逐漸變慢
UIViewAnimationOptionCurveEaseOut // 動畫逐漸加速
UIViewAnimationOptionCurveLinear // 動畫勻速執行,預設值
複製程式碼
3.轉場型別(僅適用於轉場動畫設定,可以從中選擇一個進行設定,基本動畫、關鍵幀動畫不需要設定)
UIViewAnimationOptionTransitionNone // 沒有轉場動畫效果
UIViewAnimationOptionTransitionFlipFromLeft // 從左側翻轉效果
UIViewAnimationOptionTransitionFlipFromRight // 從右側翻轉效果
UIViewAnimationOptionTransitionCurlUp // 向後翻頁的動畫過渡效果
UIViewAnimationOptionTransitionCurlDown // 向前翻頁的動畫過渡效果
UIViewAnimationOptionTransitionCrossDissolve // 舊檢視溶解消失顯示下一個新檢視的效果
UIViewAnimationOptionTransitionFlipFromTop // 從上方翻轉效果
UIViewAnimationOptionTransitionFlipFromBottom // 從底部翻轉效果
複製程式碼
支援的動畫屬性
frame //大小變化:改變檢視框架(frame)和邊界。
bounds //拉伸變化:改變檢視內容的延展區域。
center //居中顯示
transform //仿射變換(transform)
alpha //改變透明度:改變檢視的alpha值。
backgroundColor //改變背景顏色
contentStretch //拉伸內容
複製程式碼
- Opacity -- 設定透明度
UIView.animate(withDuration: 1.0) {
self.objectView.alpha = 0.2
}
複製程式碼
- Scale -- 放大縮小
UIView.animate(withDuration: 1.0) {
self.objectView.transform = CGAffineTransform(scaleX: 2, y: 2)
}
UIView.animate(withDuration: 1.0, delay: 1.0, options: .curveLinear, animations: {
self.objectView.transform = CGAffineTransform(scaleX: 0.5, y: 0.5)
}, completion: nil)
複製程式碼
- Translation -- 平移
UIView.animate(withDuration: 1.0) {
self.objectView.transform = CGAffineTransform(translationX: 200, y: 200)
}
複製程式碼
- Color -- 顏色
UIView.animate(withDuration: 1.0, delay: 0, options: [.autoreverse, .repeat], animations: {
self.objectView.backgroundColor = UIColor.brown
}, completion: nil)
複製程式碼
- Rotation -- 旋轉
UIView.animate(withDuration: 1.0, delay: 0, options: [.curveLinear, .repeat], animations: {
self.objectView.transform = CGAffineTransform(rotationAngle: CGFloat(Double.pi))
}, completion: nil)
複製程式碼
###彈簧動畫函式
UIView.animate(withDuration: 1.0, delay: 0, usingSpringWithDamping: 0.5, initialSpringVelocity: 20, options: .curveEaseIn, animations: {
self.objectView.center.y = self.objectView.center.y + 100
}, completion:nil)
複製程式碼
關鍵幀動畫
為當前檢視建立可以容納一個或多個關鍵幀動畫物件的動畫塊,然後根據指定的時間一幀幀的執行指定動畫,需要與addKeyframeWithRelativeStartTime: relativeDuration: animations: 結合使用,注意:如果在block中沒用新增關鍵幀動畫物件,動畫還是會執行,只不過跟呼叫animateWithDuration(duration: delay: options: animations: completion: 效果一樣!簡單點來說,呼叫該API就是建立了一個動畫容器,然後可以向這個容器中新增多個動畫!
UIViewKeyframeAnimationOptions:
1 .CalculationModeLinear:在幀動畫之間採用線性過渡
2 .CalculationModeDiscrete:在幀動畫之間不過渡,直接執行各自動畫
3 .CalculationModePaced:將不同幀動畫的效果儘量融合為一個比較流暢的動畫
4 .CalculationModeCubic:不同幀動畫之間採用Catmull-Rom演算法過渡
5 .CalculationModeCubicPaced:3和4結合,試了就知道什麼效果了
複製程式碼
animateKeyframesWithDuration:delay:options:animations:completion:結合使用,用來指定幀動畫開始時間,持續時間和執行操作,呼叫一次就可以新增一個幀動畫!
frameStartTime:幀動畫開始時間,取值範圍為(0,1),開始時間是相對於整個動畫時間,整個關鍵幀動畫時長6秒,設定開始時間為0.5,那麼這一幀動畫的實際開始時間為第3秒!
2 frameDuration:幀動畫持續時間,取值範圍為(0,1),持續時間也是相對於整個動畫時間,演算法同上!
複製程式碼
UIView.animateKeyframes(withDuration: 10, delay: 0, options: .calculationModeCubicPaced, animations: {
UIView.addKeyframe(withRelativeStartTime: 0, relativeDuration: 1/5, animations: {
self.objectView.backgroundColor = UIColor.red
})
UIView.addKeyframe(withRelativeStartTime: 1/5, relativeDuration: 1/5, animations: {
self.objectView.backgroundColor = UIColor.green
})
UIView.addKeyframe(withRelativeStartTime: 2/5, relativeDuration: 1/5, animations: {
self.objectView.backgroundColor = UIColor.yellow
})
UIView.addKeyframe(withRelativeStartTime: 3/5, relativeDuration: 1/5, animations: {
self.objectView.backgroundColor = UIColor.purple
})
UIView.addKeyframe(withRelativeStartTime: 4/5, relativeDuration: 1/5, animations: {
self.objectView.backgroundColor = UIColor.gray
})
}, completion: nil)
複製程式碼
Transitions 過渡
過度動畫強調的是view改變內容。一般有兩個方法
UIView.transition(with:, duration:, options:, animations:, completion:)
UIView.transition(from: , to:, duration:, options:, completion:)
複製程式碼
過渡動畫的型別是一個options (UIViewAnimationOptions)
.transitionFlipFromLeft,.transitionFlipFromRight
.transitionFlipFromTop,.transitionFlipFromBottom
.transitionCurlUp,.transitionCurlDown
.transitionCrossDissolve
複製程式碼
if self.objectView.backgroundColor == UIColor.gray {
self.objectView.backgroundColor = UIColor.blue
}else {
self.objectView.backgroundColor = UIColor.gray
}
}, completion: nil)
複製程式碼
ImageView動畫
在 UIImageView 上執行動畫非常簡單,只需要提供animationImages 屬性。一個UIImage 陣列。這個陣列程式碼一個一個的幀,當我們呼叫 startAnimating 方法的時候,這個陣列的圖片就會輪流播放。animationDuration 決定了播放的速度。animationRepeatCount指定重複次數 (預設是0 , 代表無限重複),或者呼叫stopAnimating 方法停止動畫。
UIImage 有一些類方法為 UIImageView 構造 可以動畫的image :
直接指定了image陣列和duration。
UIImage.animatedImage(with:, duration:)
複製程式碼
提供一個單個的image name , 系統會自動在後面加 "0" (如果失敗則"1") 。使這個image成為第一個image。最後一位數字累加。(知道沒有圖片或者到達”1024“)
UIImage.animatedImageNamed(, duration: )
複製程式碼
跟上面的方式差不多,但是同時對每個image做了拉伸或者平鋪。 影像本身也有resizableImage(withCapInsets: , resizingMode: )方法可以縮放(指定某個區域的拉伸或者平鋪)
UIImage.animatedResizableImageNamed(, capInsets: , duration: )
複製程式碼
let image = UIImage.animatedImageNamed("voice", duration: 2)
self.imageView.image = image
複製程式碼
其中voice1-3 已經命名好,放在Assets.xcassets
##CoreAnimation核心動畫 Core Animation可以用在 Mac OS X 和 iOS平臺. Core Animation的動畫執行過程是在後臺操作的.不會阻塞主執行緒. 要注意的是, Core Animation是直接作用在CALayer上的.並非UIView
- CABasicAnimation 基礎動畫
- CAKeyframeAnimation 關鍵幀動畫
- CATransition 轉場動畫
- CAAnimationGroup 組動畫
- CASpringAnimation 彈性動畫 (iOS9.0之後新增CASpringAnimation類,它實現彈簧效果的動畫,是CABasicAnimation的子類。)
動畫操作過程:
- 建立一個CAAnimation物件
- 設定一些動畫的相關屬性
- 給CALayer新增動畫(addAnimation:forKey: 方法)
- 移除CALayer中得動畫(removeAnimationForKey: 方法)
###CAAnimation (一部分屬性來自 CAMediaTiming)
-
duration:動畫的持續時間,預設為0.25秒
-
speed :速度 speed = 1.0 / duration = 1.0 的動畫效果 和 speed = 2.0 / duration = 2.0 的動畫效果是一模一樣的,我們設定的duration可能和動畫進行的真實duration不一樣,這個還依賴於speed。
-
timeOffset 設定動畫線的起始結束時間點
//假定一個3s的動畫,它的狀態為t0,t1,t2,t3,當沒有timeOffset的時候,正常的狀態序列應該為:
//t0->t1->t2->t3
//當設定timeOffset為1的時候狀態序列就變為
//t1->t2->t3->t0
//同理當timeOffset為2的時候狀態序列就變為:
//t2->t3->t0->t1
複製程式碼
-
autoreverses:是否自動回到動畫開始狀態
-
repeatCount:動畫的重複次數
-
repeatDuration:動畫的重複時間
-
removedOnCompletion:預設為YES,代表動畫執行完畢後就從圖層上移除,圖形會恢復到動畫執行前的狀態。如果想讓圖層保持顯示動畫執行後的狀態,那就設定為NO,不過還要設定fillMode屬性為kCAFillModeForwards
-
fillMode:決定當前物件在非active時間段的行為.比如動畫開始之前,動畫結束之後
-
beginTime:可以用來設定動畫延遲執行時間,若想延遲2s,就設定為CACurrentMediaTime()+2,CACurrentMediaTime()為圖層的當前時間。 CALayer 的beginTime 一般用於動畫暫停的使用,CAAnimation 的beginTime一般用於動畫延遲執行,但只在使用groupAnimation的時候生效,直接新增在layer上的animation使用會導致動畫不執行。
-
timingFunction:速度控制函式,控制動畫執行的節奏
列舉引數:
kCAMediaTimingFunctionLinear 時間曲線函式,勻速
kCAMediaTimingFunctionEaseIn 時間曲線函式,由慢到特別快
kCAMediaTimingFunctionEaseOut 時間曲線函式,由快到慢
kCAMediaTimingFunctionEaseInEaseOut 時間曲線函式,由慢到快
kCAMediaTimingFunctionDefault 系統預設
複製程式碼
- delegate:動畫代理,一般設定隱式代理,該代理是NSObject的分類,需要遵守協議CAAnimationDelegate
-(void)animationDidStart:(CAAnimation *)anim; 核心動畫開始時執行
-(void)animationDidStop:(CAAnimation *)anim finished:(BOOL)flag; 核心動畫執行結束後呼叫
複製程式碼
CAPropertyAnimation
屬性:
keyPath:通過指定CALayer的一個屬性名做為keyPath裡的引數(NSString型別),並且對CALayer的這個屬性的值進行修改,達到相應的動畫效果。比如,指定@”position”為keyPath,就修改CALayer的position屬性的值,以達到平移的動畫效果。
CABasicAnimation *animation = [CABasicAnimation animationWithKeyPath:@"position.y"];
複製程式碼
一些常用的animationWithKeyPath值的總結
值 | 說明 | 使用形式 |
---|---|---|
transform.scale | 比例轉化 | @(0.8) |
transform.scale.x | 寬的比例 | @(0.8) |
transform.scale.y | 高的比例 | @(0.8) |
transform.rotation.x | 圍繞x軸旋轉 | @(M_PI) |
transform.rotation.y | 圍繞y軸旋轉 | @(M_PI) |
transform.rotation.z | 圍繞z軸旋轉 | @(M_PI) |
cornerRadius | 圓角的設定 | @(50) |
backgroundColor | 背景顏色的變化 | (id)[UIColor purpleColor].CGColor |
bounds | 大小,中心不變 | [NSValue valueWithCGRect:CGRectMake(0, 0, 200, 200)]; |
position | 位置(中心點的改變) | [NSValue valueWithCGPoint:CGPointMake(300, 300)]; |
contents | 內容,比如UIImageView的圖片 | imageAnima.toValue = (id)[UIImage |
opacity | 透明度 | @(0.7) |
contentsRect.size.width | 橫向拉伸縮放 | @(0.4)最好是0~1之間的 |
####CABasicAnimation基本動畫 CABasicAnimation能實現諸多的動畫,移動,旋轉,縮放....KeyPath所涉及的都能實現
1.fromValue : keyPath相應屬性的初始值 **2.toValue **: keyPath相應屬性的結束值,到某個固定的值(類似transform的make含義) 注意:隨著動畫的進行,在長度為duration的持續時間內,keyPath相應屬性的值從fromValue漸漸地變為toValue. 如果fillMode = kCAFillModeForwards和removedOnComletion = NO;那麼在動畫執行完畢後,圖層會保持顯示動畫執行後的狀態,但實質上,圖層的屬性值還是動畫執行前的初始值,並沒有真正被改變.比如: CALayer的postion初始值為(0,0),CABasicAnimation的fromValue為(10,10),toValue為 (100,100),雖然動畫執行完畢後圖層保持在(100,100) 這個位置,實質上圖層的position還是為(0,0); 3.byValue:不斷進行累加的數值(byvalue 值加上fromValue => tovalue)
Position
let baseAnimation = CABasicAnimation(keyPath: "position.x")
baseAnimation.fromValue = objectView.center.x
baseAnimation.toValue = objectView.center.x + 100
baseAnimation.duration = 1
//逆行動畫
baseAnimation.autoreverses = true
baseAnimation.repeatCount = MAXFLOAT
//防止動畫接收後回到初始狀態
baseAnimation.isRemovedOnCompletion = false
baseAnimation.fillMode = CAMediaTimingFillMode.forwards
objectView.layer.add(baseAnimation, forKey: "demo")
複製程式碼
Scale
let baseAnimation = CABasicAnimation(keyPath: "transform.scale")
baseAnimation.fromValue = 0.5
baseAnimation.toValue = 1
baseAnimation.duration = 1
baseAnimation.repeatCount = MAXFLOAT
baseAnimation.fillMode = CAMediaTimingFillMode.forwards
objectView.layer.add(baseAnimation, forKey: "demo")
複製程式碼
####CASpringAnimation彈性動畫 iOS9才引入的動畫類,它繼承於CABaseAnimation,用於製作彈簧動畫
引數說明:
mass: 質量,影響圖層運動時的彈簧慣性,質量越大,彈簧拉伸和壓縮的幅度越大
stiffness: 剛度係數(勁度係數/彈性係數),剛度係數越大,形變產生的力就越大,運動越快
damping: 阻尼係數,阻止彈簧伸縮的係數,阻尼係數越大,停止越快
initialVelocity: 初始速率,動畫檢視的初始速度大小 速率為正數時,速度方向與運動方向一致,速率為負數時,速度方向與運動方向相反
settlingDuration: 結算時間 返回彈簧動畫到停止時的估算時間,根據當前的動畫引數估算 通常彈簧動畫的時間使用結算時間比較準確
let springAnimation = CASpringAnimation(keyPath: "position.x")
springAnimation.damping = 5
springAnimation.stiffness = 100;
springAnimation.mass = 1;
springAnimation.initialVelocity = 0;
springAnimation.fromValue = objectView.layer.position.x;
springAnimation.toValue = objectView.layer.position.x + 50;
springAnimation.duration = springAnimation.settlingDuration;
objectView.layer.add(springAnimation, forKey: springAnimation.keyPath);
複製程式碼
####CAKeyframeAnimation關鍵幀動畫
- CAKeyframeAnimation跟CABasicAnimation的區別是: CABasicAnimation只能從一個數值(fromValue)變到另一個數值(toValue),而CAKeyframeAnimation會使用一個NSArray儲存這些數值.
- CAKeyframeAnimation屬性解析: values:就是上述的NSArray物件。裡面的元素稱為”關鍵幀”(keyframe)。動畫物件會在指定的時間(duration)內,依次顯示values陣列中的每一個關鍵幀 . path:如果你設定了path,那麼values將被忽略. keyTimes:可以為對應的關鍵幀指定對應的時間點,其取值範圍為0到1.0,keyTimes中的每一個時間值都對應values中的每一幀.當keyTimes沒有設定的時候,各個關鍵幀的時間是平分的. 注: CABasicAnimation能實現的CAKeyframeAnimation也能實現,而且更具體和準確
Shake Sample
let shakeAnimation = CAKeyframeAnimation(keyPath: "transform.rotation")
//設定晃動角度
let angle = Double.pi / 2
//設定關鍵幀動畫的值
shakeAnimation.values = [angle, -angle, angle]
//設定關鍵幀動畫每幀的執行時間,這裡不設定也行,預設平均分配時間
shakeAnimation.keyTimes = [0, 0.5, 1]
//設定動畫重複次數,預設為1次
shakeAnimation.repeatCount = MAXFLOAT
//設定動畫執行效果
shakeAnimation.timingFunctions = [CAMediaTimingFunction(name: CAMediaTimingFunctionName.easeIn)]
//設定相鄰動畫過渡方式
shakeAnimation.calculationMode = CAAnimationCalculationMode.cubic
objectView.layer.add(shakeAnimation, forKey: shakeAnimation.keyPath);
複製程式碼
軌跡動畫
let path = UIBezierPath()
//設定動畫的執行路徑為一個M的形狀
path.move(to: CGPoint(x: 40, y: 300))
path.addLine(to: CGPoint(x: 80, y: 150))
path.addLine(to: CGPoint(x: 120, y: 300))
path.addLine(to: CGPoint(x: 160, y: 150))
path.addLine(to: CGPoint(x: 200, y: 300))
let bezierAnimation = CAKeyframeAnimation(keyPath: "position")
//由於CAKeyframeAnimation的path為CGPath,所以這裡要轉換一次
bezierAnimation.path = path.cgPath
//設定動畫時間
bezierAnimation.duration = 4
//自動旋轉layer角度與path相切
bezierAnimation.rotationMode = CAAnimationRotationMode.rotateAuto
//設定動畫重複次數
bezierAnimation.repeatCount = MAXFLOAT
//設定自動逆向
bezierAnimation.autoreverses = true
objectView.layer.add(bezierAnimation, forKey: nil)
複製程式碼
Scale動畫
let scaleAnimation = CAKeyframeAnimation(keyPath: "transform.scale")
scaleAnimation.values = [0.0, 0.4, 0.8, 1.2, 1.6, 1.2, 0.8, 0.4, 0.0]
scaleAnimation.duration = 2
scaleAnimation.autoreverses = true
scaleAnimation.repeatCount = MAXFLOAT
objectView.layer.add(scaleAnimation, forKey: nil)
複製程式碼
###CAAnimationGroup組合動畫 將多個動畫組合和併發執行 delegate 和 isRemovedOnCompletion 在動畫的屬性陣列中目前被忽略。 CAAnimationGroup 的 delegate 接收這些訊息
- animations CAAnimation 陣列,用於新增多個 CAAnimation 動畫
let animationPath = CAKeyframeAnimation.init(keyPath: "position")
animationPath.path = path.cgPath
animationPath.rotationMode = CAAnimationRotationMode.rotateAuto
//旋轉
let rotate:CABasicAnimation = CABasicAnimation()
rotate.keyPath = "transform.rotation"
rotate.toValue = Double.pi
//縮小圖片到0
let scale:CABasicAnimation = CABasicAnimation()
scale.keyPath = "transform.scale"
scale.toValue = 0.0
//組合動畫
let animationGroup:CAAnimationGroup = CAAnimationGroup()
animationGroup.animations = [animationPath,rotate,scale];
animationGroup.duration = 2.0;
animationGroup.fillMode = CAMediaTimingFillMode.forwards;
animationGroup.isRemovedOnCompletion = false
objectView.layer.add(animationGroup, forKey:
nil)
複製程式碼
###CATransition轉場動畫
CAAnimation的子類 在圖層狀態之間提供動畫轉換的物件 提供了一個圖層之間的過渡的動畫
CATransition 有一個 type 和 subtype 來標識變換效果
新增加的屬性
- startProgress 開始的進度 0~1
- endProgress 結束時的進度 0~1
- type 轉換型別
- kCATransitionFade (default)
- kCATransitionMoveIn
- kCATransitionPush
- kCATransitionReveal
- API引入的type,在蘋果官網是不會承認的,所以不建議使用
- 1 animation.type = @"cube"; //立方體效果
- 2 animation.type = @"suckEffect";//猶如一塊布被抽走
- 3 animation.type = @"oglFlip"; //上下翻轉效果
- 4 animation.type = @"rippleEffect"; //滴水效果
- 5 animation.type = @"pageCurl"; //向左翻頁
- 6 animation.type = @"pageUnCurl"; //向下翻頁
- subtype 基於運動方向預定義的轉換
- kCATransitionFromLeft
- kCATransitionFromRight
- kCATransitionFromTop
- kCATransitionFromBottom
- filter 濾鏡
** View Transaition**
let animation = CATransition()
animation.duration = 1.0
animation.timingFunction = CAMediaTimingFunction(name: CAMediaTimingFunctionName.linear)
// `fade', `moveIn', `push' and `reveal'. Defaults to `fade'
animation.type = CATransitionType.reveal
// `fromLeft', `fromRight', `fromTop' and `fromBottom'
animation.subtype = CATransitionSubtype.fromLeft
// animation.isRemovedOnCompletion = true
animation.startProgress = 0.5
objectView.layer.add(animation, forKey: nil)
複製程式碼
** ViewController Transaition(翻頁效果)**
let vc = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "second")
let anima = CATransition.init()
// anima.type = CATransitionType.reveal
anima.type = CATransitionType(rawValue: "pageUnCurl")
anima.subtype = CATransitionSubtype.fromLeft
anima.duration = 1.0
UIApplication.shared.keyWindow?.layer.add(anima, forKey: "pageUnCurl")
// UIApplication.shared.keyWindow?.layer.removeAnimation(forKey: "pageUnCurl")
self.navigationController?.pushViewController(vc, animated: false)
複製程式碼
##其他動畫
###控制器轉場動畫 UIViewControllerAnimatedTransitioning
####一、 轉場動畫-modal 給vc的transitioningDelegate屬性賦值,為即將跳轉的vc指定轉場動畫代理,協議中有兩個基礎方法,分別要求代理返回present時的動畫以及dismiss時的動畫。
class FadeTransitionDelegate: NSObject, UIViewControllerTransitioningDelegate {
private lazy var fadeAnimator = FadeAnimator()
// 提供dismiss的時候使用到的動畫執行物件
func animationController(forDismissed dismissed: UIViewController) -> UIViewControllerAnimatedTransitioning? {
fadeAnimator.isPresenting = false
return fadeAnimator
}
// 提供present的時候使用到的動畫執行物件
func animationController(forPresented presented: UIViewController, presenting: UIViewController, source: UIViewController) -> UIViewControllerAnimatedTransitioning? {
fadeAnimator.isPresenting = true
return fadeAnimator
}
}
複製程式碼
寫一個類專門來實現UIViewControllerAnimatedTransitioning動畫協議,作為動畫的實現類。然後代理就可以返回兩個動畫實現物件,實現UIViewControllerTransitioningDelegate轉場代理協議。
獲取轉場過程的三個檢視:containerView、fromView、toView。 containerView是動畫過程中提供的暫時容器。 fromView是轉場開始頁的檢視。 toView是轉場結束頁的檢視。
轉場的過程,大多數情況下我們都是對toView作各種變換操作,例如改變toView的alpha,size,旋轉等等。 在對它進行操作前,需要先把它放到container上才能顯示出來。[container addSubview:toView];
class FadeAnimator: NSObject, UIViewControllerAnimatedTransitioning {
let duration = 1.0
var isPresenting = true
// 指定轉場動畫持續的時間
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return duration
}
// 實現轉場動畫的具體內容
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// 得到容器檢視
let containerView = transitionContext.containerView
// 目標檢視
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
containerView.addSubview(toView)
// 為目標檢視的展現新增動畫
toView.alpha = 0.0
UIView.animate(withDuration: duration,
animations: {
toView.alpha = 1.0
}, completion: { _ in
transitionContext.completeTransition(true)
})
}
}
複製程式碼
最後presentViewController的時候賦值代理
let transitionDelegate = FadeTransitionDelegate()
@IBAction func UIViewControllerAnimatedTransitioning_Demo(_ sender: Any) {
let vc = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "second")
vc.transitioningDelegate = transitionDelegate
present(vc, animated: true, completion: nil)
}
複製程式碼
####二、 轉場動畫-push 流程同 轉場動畫基礎用法-modal 要自定義push動畫,需實現導航控制器的代理協議 UINavigationControllerDelegate
class PushTansitionDelegate: NSObject, UINavigationControllerDelegate {
private lazy var fadeAnimator = FadeAnimator()
// 是否需要互動
var interactive = false
//返回一個不可互動的轉場動畫
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return fadeAnimator
}
}
複製程式碼
其中fadeAnimator和Model裡的是同樣的定義。 使用Push動畫
let vc = UIStoryboard(name: "Main", bundle: nil)
.instantiateViewController(withIdentifier: "second")
self.navigationController?.delegate = pushTransitionDelegate
self.navigationController?.pushViewController(vc, animated: true)
複製程式碼
####一、 轉場動畫-互動式轉場動畫 互動式過渡是由事件驅動的。可以是動作事件或者手勢,通常為手勢。要實現一個互動式過渡,除了需要跟之前相同的動畫,還需要告訴互動控制器動畫完成了多少。開發者只需要確定已經完成的百分比,其他交給系統去做就可以了。例如,(平移和縮放的距離 / 速度的量可以作為計算完成的百分比的引數)。
互動式控制器實現了 UIViewControllerInteractiveTransitioning 協議:
- (void)startInteractiveTransition:(id <UIViewControllerContextTransitioning>)transitionContext;
複製程式碼
這個方法裡只能有一個動畫塊,動畫應該基於 UIView 而不是圖層,互動式過渡不支援 CATransition 或 CALayer 動畫。
互動式過渡的互動控制器應當是 UIPercentDrivenInteractiveTransition 子類。動畫類負責計算完成百分比,系統會自動更新動畫的中間狀態。
- (void)updateInteractiveTransition:(CGFloat)percentComplete;
- (void)cancelInteractiveTransition;
- (void)finishInteractiveTransition;
複製程式碼
對FadeAnimator新增handlePan,並且繼承UIPercentDrivenInteractiveTransition 支援互動式動畫
class FadeAnimator: UIPercentDrivenInteractiveTransition, UIViewControllerAnimatedTransitioning {
let durationAnimation = 1.0
// present/dismiss, push/pop
var isPresenting = true
// 是否需要互動
var interactive = false
// 指定轉場動畫持續的時間
func transitionDuration(using transitionContext: UIViewControllerContextTransitioning?) -> TimeInterval {
return durationAnimation
}
// 實現轉場動畫的具體內容
func animateTransition(using transitionContext: UIViewControllerContextTransitioning) {
// 得到容器檢視
let containerView = transitionContext.containerView
// 目標檢視
let toView = transitionContext.view(forKey: UITransitionContextViewKey.to)!
containerView.addSubview(toView)
// 為目標檢視的展現新增動畫
toView.alpha = 0.0
UIView.animate(withDuration: durationAnimation,
animations: {
toView.alpha = 1.0
}, completion: { _ in
transitionContext.completeTransition(true)
})
}
func handlePan(recognizer: UIPanGestureRecognizer) {
let translation = recognizer.translation(in: recognizer.view!.superview!)
var progress: CGFloat = abs(translation.x / 200.0)
progress = min(max(progress, 0.01), 0.99)
switch recognizer.state {
case .changed:
// 更新當前轉場動畫播放進度
update(progress)
case .cancelled:
cancel()
case .ended:
finish()
default:
break
}
}
複製程式碼
對應的Delegate更改為 支援互動的轉場動畫:
class PushTansitionDelegate: NSObject, UINavigationControllerDelegate {
private lazy var fadeAnimator = FadeAnimator()
// 是否需要互動
var interactive = false
//返回一個不可互動的轉場動畫
func navigationController(_ navigationController: UINavigationController, animationControllerFor operation: UINavigationController.Operation, from fromVC: UIViewController, to toVC: UIViewController) -> UIViewControllerAnimatedTransitioning? {
return fadeAnimator
}
// 返回一個可以互動的轉場動畫
func navigationController(_ navigationController: UINavigationController, interactionControllerFor animationController: UIViewControllerAnimatedTransitioning) -> UIViewControllerInteractiveTransitioning? {
if interactive == false {
return nil
}
return fadeAnimator
}
func handlePan(recognizer: UIPanGestureRecognizer) {
fadeAnimator.handlePan(recognizer: recognizer)
}
}
複製程式碼
控制器中使用,第二個頁面返回的時候使用互動式轉場動畫
class SecondViewController: UIViewController {
let pushTransitionDelegate = PushTansitionDelegate()
override func viewDidLoad() {
super.viewDidLoad()
}
override func viewDidAppear(_ animated: Bool) {
super.viewDidAppear(animated)
let pan = UIPanGestureRecognizer(target: self, action: #selector(handlePan(recognizer:)))
self.view.addGestureRecognizer(pan)
}
@objc func handlePan(recognizer: UIPanGestureRecognizer) {
if recognizer.state == .began {
pushTransitionDelegate.interactive = true
self.navigationController?.delegate = pushTransitionDelegate
self.navigationController?.popViewController(animated: true)
}else {
pushTransitionDelegate.handlePan(recognizer: recognizer)
}
}
@IBAction func close(_ sender: Any) {
self.dismiss(animated: true, completion: nil)
}
}
複製程式碼
###UIDynamic-動力學框架 UIDynamic是蘋果在iOS7之後新增的一套動力學框架,運用它我們可以極其方便地模擬現實生活中的運動,比如重力,碰撞等等。它是通過新增行為的方式讓動力學元素參與運動的。
iOS7.0中提供的動力學行為包括:
UIGravityBehavior:重力行為 UICollisionBehavior:碰撞行為 UIAttachmentBehavior:附著行為 UISnapBehavior:吸附行為 UIPushBehavior:推行為 UIDynamicItemBehavior:動力學元素行為
UIDynamic的使用還是相對簡單
1.首先我們建立一個小方塊 objectView 並把它放在self.view的上面部分。(只有遵循了UIDynamicItem協議的物件才能參與模擬模擬,而UIView正遵循了此協議,因此所有檢視控制元件都能參與模擬運動)
2.然後定義一個 UIDynamicAnimator 物理模擬器(凡是要參與運動的物件必須新增到此容器中)
3.再新增一個重力行為 到模擬器,並且 這個行為作用物件是我們之前定義的boxView
4.可以發現 放在self.view上半部分的boxView受重力行為影響,往下掉落。但是會掉出self.view範圍。
5.為了不掉出self.view 範圍 我們還需要給objectView新增一個別的行為:碰撞行為,接觸到模擬器邊界或者其他self.view中得容器會產生碰撞效果。
6.這樣小方塊就不會掉出模擬器範圍了,同理,其他行為的使用方式和上面一樣,一定要新增到模擬器才能生效。
var animator: UIDynamicAnimator!
@IBAction func UIDynamic_tap(_ sender: Any) {
animator = UIDynamicAnimator(referenceView: self.view)
let behavior = UIGravityBehavior(items: [objectView])
animator.addBehavior(behavior)
let behaviorCollision = UICollisionBehavior(items: [objectView])
behaviorCollision.translatesReferenceBoundsIntoBoundary = true
animator.addBehavior(behaviorCollision)
}
複製程式碼
CAEmitterLayer 粒子動畫
1、CAEmitterLayer。 這個主要是定義粒子原型發射層的形狀和發射位置,發射源的尺寸以及發射的模式等。
2、CAEmitterCell 單個粒子的原型,通常有多個,根據cell的屬性和CAEmitterCell的配置,由uikit隨機生成,粒子原型的屬性包括粒子的圖片,顏色,方向,運動,縮放比例和生命週期等。
這兩個類的引數看起來似乎很簡單,但這些引數的不同組合配合上相對應圖片,則可以實現許多意想不到的動畫效果。
var rainLayer: CAEmitterLayer!
@IBAction func CAEmitterLayer_tap(_ sender: Any) {
// 粒子發射圖層
rainLayer = CAEmitterLayer()
// 發射器形狀為線形,預設發射方向向上
rainLayer.emitterShape = CAEmitterLayerEmitterShape.line
// 從發射器的輪廓發射粒子
rainLayer.emitterMode = CAEmitterLayerEmitterMode.outline
// 優先渲染舊的粒子
rainLayer.renderMode = CAEmitterLayerRenderMode.oldestFirst
// 發射位置
// 對於線形發射器,線的兩端點分別為
// (emitterPosition.x - emitterSize.width/2, emitterPosition.y, emitterZPosition)和
// (emitterPosition.x + emitterSize.width/2, emitterPosition.y, emitterZPosition)
rainLayer.emitterPosition = CGPoint(x: view.bounds.midX, y: 0)
// 發射器大小
rainLayer.emitterSize = CGSize(width: view.bounds.width, height: 0)
// 粒子生成速率的倍數,一開始不發射,設定為零
rainLayer.birthRate = 0
// 發射的粒子
let cell = CAEmitterCell()
// 粒子顯示的內容,設定CGImage,顯示圖片
cell.contents = UIImage(named: "star")?.cgImage
// 粒子縮放倍數
cell.scale = 0.1
// 粒子壽命,單位是秒
cell.lifetime = 5
// 粒子生成速率,單位是個/秒,實際顯示效果要乘以CAEmitterLayer的birthRate
cell.birthRate = 1000
// 粒子速度
cell.velocity = 500
// 粒子發射角度,正值表示順時針方向
cell.emissionLongitude = CGFloat.pi
// 圖層要發射1種粒子
rainLayer.emitterCells = [cell]
// 新增粒子發射圖層
view.layer.addSublayer(rainLayer)
// 粒子生成速率漸變動畫
let birthRateAnimation = CABasicAnimation(keyPath: "birthRate")
birthRateAnimation.duration = 3
if rainLayer.birthRate == 0 {
// 雨變大
birthRateAnimation.fromValue = 0
birthRateAnimation.toValue = 1
rainLayer.birthRate = 1
} else {
// 雨變小
birthRateAnimation.fromValue = 1
birthRateAnimation.toValue = 0
rainLayer.birthRate = 0
}
// 加入動畫
rainLayer.add(birthRateAnimation, forKey: "birthRate")
}
複製程式碼
參考連線 www.jianshu.com/p/71f2fa270… www.jianshu.com/p/9aead7675… www.jianshu.com/p/802d47f0f…