[ SWIFT ] - 史丹福 StandFord-CS193P-課程12-心得分享-20150903

[ SWIFT ] - 史丹福 StandFord-CS193P-課程12-心得分享-20150903
課程重點:

Physics based Dynamic Animation-物理動態動畫教學
Demo:打磚塊遊戲

1.Dynamic Animation
介紹:物理動畫與一般動畫不同在於,物理動畫指的是view上的物件,而一般動畫指的是整個view的動作。

2.使用物理動畫的步驟:
2.1建置一個UIDynamicAnimator
2.2加入UIDynamicAnimatorBehavios:增加動態行為,例如:加入重力或碰撞的效果
2.3加入UIDynamicItems:設置受影響的對象。
※將物理動畫效果設置在主View上,其SubView也會有相同效果。

程式範例:
(a)透過.addBehavior設置動畫行為到動畫器
(b)透過Add UIDynamicItems:設置對象。
例如:item1:設置gravity重力和collider碰撞
           Item2:設置gravity重力
則item1不會和item2碰撞,會直接穿過item2,需要2個物件都設置相同的效果才會有作用。

(c)UIDynamicItem Protocol-動畫協定,動畫協定有3個屬性
(c.1)bounds:動畫範圍,此屬性只能讀(get)不能修改,因為動畫器無法改變物件的大小。
(c.2)center:定義對象的位置。
(c.3)transform:設定旋轉,為AffineTransform類型。
※目前UIView已包含此協定,故不需手動設置。
當要改變view的中心或是使view變形時需要透過updateItemUsingCurrentState(item:UIDynamicItem)

3.Behaviors(UIDynamicAnimator)
3.1UIGravityBehavior:重力行為,共有2個參數:
Angle:a設置角度
Magnitude:設置大小,比例1:1000,表示每平方秒1000像素
※因重力是一種加速度,在地球上是每坪方秒9.8米

3.2UIAttachmentBehavior:附屬行為的動畫效果
例如:增加一個錨點,配合重力產生擺動效果。
3.3UICollisionBehavior:碰撞行為,除了設定物件之間的碰撞之外也可設定物件與邊界的碰撞行為。

3.4兩種邊界設置的方法:
(a)UIBexierPath:貝賽爾曲線,以曲線作為邊界。
(b)translatesReferenceBoundsIntoBoundary:true表示動畫對象的所有外邊框為一個邊界
※設置邊界時需要設置識別符號,此符號遵循NSCopying Protocol,接受NSString 或 NSNumber。
※設置邊界時需設定代理UICollisionBehaviorDelegate,透過collisionBehavior取的物件之間或物件與邊界碰撞時的訊息。
Snap:指物件移動後會有一個擺盪動作。
UISnapBehavior:
參數:(1)item:UIDynamicItem(2) snaptoPoint:CGPoint那一個點
UIPushBehavior:將物件推向一個特定角度(擺動角度)
mode:UIPushBehaviorMode,共有2種model:(a).Continuous(b).Instantaneous
說明:Push行為可以是一次性的效果 、連續的效果,但重力只能是恆定速度。
Push加入動畫器時會影響動畫器中所有物件,但Push會有佔用資源問體,所以需要有取回資源機制。


UIDynamicItemBehavior:所有行為的父親,本身是UIDynamicBehavior的子類,用來取的物件動態行為的資訊,例如:移動的速度、角度、是否旋轉等。

透過addChildBehavior(UIDynamicBehavior )增加動態的行為,透過多個子行為達到複合行為效果。
※所有的行為一次只能在動畫器中(此屬性只能讀get)

func willMoveToAnimator:從沒有動畫移至有動畫時
重要屬性action: 是一個行為的屬性,當action是使用某個行為時會形成retain cycle,需要將參考的類型編碼為unowned來打破retain cycle

 retain cycle補充說明:
範例:
class A {
    let b: B
    init() {
        b = B()
        b.a = self
    }

    deinit {
        println("A deinit")
    }
}

class B {
    var a: A? = nil
    deinit {
        println("B deinit")
    }
}
範例說明:
在類別 A、B中的初始化方法中,各自產生了 A、B 的instance並將 A 、B 的instance賦值給 a.b 與b.a。這樣 a.b 和 b.a 將在初始化的時候形成一個引用循環。現在當有第三方的調用初始化了 A,然後即使立即將其釋放,A 和 B 兩個類實例的 deinit 方法也不會被調用,說明它們並沒有被釋放。

unowned與weak的區別

unowned :設置以後即使它原來引用的內容已經被釋放了,它仍然會保持對被已經釋放了的對象的一個 "無效的" 引用,它不能是 Optional 值,也不會被指向 nil。

weak :在引用的內容被釋放後,標記為 weak 的成員將會自動地變成 nil (因此被標記為 @weak 的變量一定需要是 Optional 值)。

關於兩者使用的選擇,Apple 給我們的建議是如果能夠確定在訪問時不會已被釋放的話,盡量使用 unowned,如果存在被釋放的可能,那就選擇用 weak。

UIDynamicAnimator同時擁有一個代理對象(UIDynamicAnimatorDelegate),負責提供:動畫是否已經停止、開始或暫停
UIDynamicAnimatorDelegate
func DynamicAnimatorDidPause(UIDynamicAnimator)
func DynamicAnimatorWillResume(UIDynamicAnimator)
說明:當物件超過邊界時,他的物理行為還是持續,因次便可透過 DynamicAnimatorDidPause來停止物件的物理行為。
例如:當小球從頂層掉落超過底部時,仍會持續往下掉。

※永遠不要將一個view放在一個行為中,當一個 view不在參考view中的行為時,動畫器會使程式崩潰。
同樣不要對一個大小為0(0,0)的對象設置動畫,因為這是一個看不見得物件且這樣的設定不合理。

※Memory Cycle Avoidance

Push之後要移除Push行為
pushBehavior.DynamicAnimator!.removeBehavior(pushBehavior):在push的動作中參考到自己造成了 retain cycle 產生Memory action cycle
解決辦法:加入unowned pushBehavior表示push行為在封包中不會被強引用,所以不要捕獲他!
※強烈推薦在push 行為中加入此動作。

留言

熱門文章