UIKit動力學最大的特色是將現實世界動力驅動的動畫引入了UIKit,好比重力,鉸鏈鏈接,碰撞,懸掛等效果,即將2D物理引擎引入了UIKit數組
注意:UIKit動力學的引入,並非爲了替代CA或者UIView動畫,在絕大多數狀況下CA或者UIView動畫仍然是最優方案,只有在須要引入逼真的交互設計的時候,才須要使用UIKit動力學它是做爲現有交互設計和實現的一種補充框架
其餘2D仿真引擎:dom
BOX2D:C語言框架,免費ide
Chipmunk:C語言框架免費,其餘版本收費動畫
// 以self.view爲參照系(參照視圖),實例化UIDynamicAnimatorspa
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];設計
// 實例化一個重力行爲,並傳入須要作動力仿真的對象view代理
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[view]];orm
// 將重力行爲添加到animator對象
[animator addBehavior:gravity];
Dynamic Animator:動畫者,爲動力學元素提供物理學相關的能力及動畫,同時爲這些元素提供相關的上下文,是動力學元素與底層iOS物理引擎之間的中介,將Behavior對象添加到Animator便可實現動力仿真
Dynamic Animator Item:動力學元素,是任何遵照了UIDynamicItem協議的對象,從iOS 7.0開始,UIView和UICollectionViewLayoutAttributes默認實現該協議。若是自定義的對象實現了該協議,便可經過Dynamic Animator實現物理仿真
UIDynamicBehavior:仿真行爲,是動力學行爲的父類,基本的動力學行爲類UIGravityBehavior、UICollisionBehavior、UIAttachmentBehavior、UISnapBehavior、UIPushBehavior以及UIDynamicItemBehavior均繼承自該父類
只有遵照了UIDynamicItem協議的對象才能夠參與到UI動力學仿真中
從iOS 7開始,UIView和UICollectionViewLayoutAttributes 類默認實現了該協議
協議定義的屬性:
bounds:Dynamic animator須要動畫元素的邊框時調用,只讀屬性,用於計算物體的邊界以及質量
center:動力學元素的中心點,讀寫屬性
transform:動力學元素的旋轉角度,讀寫屬性(須要指定Layer的形變屬性)
一個動力學行爲能夠爲一個或者多個動力學元素賦予參與在二維動畫中所具有的行爲
iOS7.0中提供的動力學行爲包括:
UIGravityBehavior:重力行爲
UICollisionBehavior:碰撞行爲
UIAttachmentBehavior:附着行爲
UISnapBehavior:吸附行爲
UIPushBehavior:推行爲
UIDynamicItemBehavior:動力學元素行爲
全部的UIDynamicBehavior都是能夠獨立做用,同時也遵照力的合成。也就是說,組合使用行爲能夠實現一些較複雜的效果
重力行爲用於給動力學元素指定一個重力向量
// 實例化一個重力行爲,並傳入須要作動力仿真的對象view
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[view]];
// 將重力行爲添加到animator
[animator addBehavior:gravity];
碰撞行爲用於指定一組動力學元素,在指定的邊界範圍內,能夠彼此發生碰撞
碰撞行爲提供了代理方法,可用於在物體碰撞前、後對動力學元素作碰撞後續的處理
// 實例化碰撞行爲,並指定view參與碰撞
UICollisionBehavior *collsion = [[UICollisionBehavior alloc] initWithItems:@[view]];
// 指定是否啓用參照系的邊界
collsion.translatesReferenceBoundsIntoBoundary = YES;
// 將碰撞行爲添加至animator
[animator addBehavior:collsion];
吸附行爲能夠將視圖經過動畫吸附到某個點上
初始化設定一下UISnapBehavior的initWithItem:snapToPoint:便可
屬性:
damping:振幅大小,默認爲0.5f
附着行爲描述一個視圖與一個錨點或者另外一個視圖相鏈接的狀況
附着行爲描述的是兩點之間的鏈接狀況,能夠模擬剛性或者彈性鏈接
在多個物體間設定多個UIAttachmentBehavior,能夠模擬多物體鏈接
屬性:
attachedBehaviorType:鏈接類型(鏈接到錨點或視圖)
items:鏈接視圖數組
anchorPoint:鏈接錨點
length:距離鏈接錨點的距離
只要設置瞭如下兩個屬性,即爲彈性鏈接
damping:振幅大小
frequency:振動頻率
推行爲能夠爲一個視圖施加一個做用力,該力能夠是持續的,也能夠是一次性的
能夠設置力的大小,方向和做用點等信息
屬性:
mode:推進類型(一次性或是持續推)
active:是否激活,若是是一次性推,須要激活
angle:推進角度
magnitude:推進力量
是一個輔助的行爲,用來設置運動學元素參與物理仿真過程當中的參數,如:彈性係數、摩擦係數、密度、阻力、角阻力以及是否容許旋轉等
elasticity(彈性係數):決定了碰撞的彈性程度,好比碰撞時物體的彈性
friction(摩擦係數) :決定了沿接觸面滑動時的摩擦力大小
density(密度): 跟size結合使用,計算物體的總質量。質量越大,物體加速或減速就越困難
resistance(阻力):決定線性移動的阻力大小,與摩擦係數不一樣,摩擦係數只做用於滑動運動
angularResistance(角阻力) :決定旋轉運動時的阻力大小
allowsRotation(容許旋轉):這個屬性頗有意思,它在真實的物理世界沒有對應的模型。設置這個屬性爲 NO 物體就徹底不會轉動,而不管施加多大的轉動力
在傳統物理學中
力的單位是牛頓(N = kg*m/s2)
距離單位是米(m)
時間單位是秒(s)
質量單位是千克(kg)
加速度單位是m/s2,重力加速度約爲:9.8m/s2
速度單位是m/s
UIDynamic中
使用點來替代傳統物理學中的m
一個點的的質量爲1g
UI重力加速度定義爲1000p/s2
// 5.1 設置障礙物碰撞邊界
CGPoint toPoint = CGPointMake(barrier.frame.origin.x + barrier.frame.size.width,barrier.frame.origin.y + barrier.frame.size.height);
[collision addBoundaryWithIdentifier:@"barrier" fromPoint:barrier.frame.origin toPoint:toPoint];
// 6. 設置物體的彈性係數
UIDynamicItemBehavior *item = [[UIDynamicItemBehavior alloc] initWithItems:@[view]];
[item setElasticity:0.5f];
// 7. 監聽碰撞動做
collision.action = ^{NSLog(@"%@", NSStringFromCGRect(view.frame));};
UIView *view = (UIView *)item;
// 動畫改變碰撞物體的顏色
NSString *ID = [NSString stringWithFormat:@"%@", identifier];
if ([ID isEqualToString:@"barrier"]) {
view.backgroundColor = [UIColor greenColor];
[UIView animateWithDuration:0.3f animations:^{
view.backgroundColor = [UIColor blueColor];
}];
}
// 刪除以前的吸附行爲
[_animator removeBehavior:_snap];
CGPoint location = [sender locationInView:self.view];
_snap = [[UISnapBehavior alloc] initWithItem:_boxImageView snapToPoint:location];
// 生成隨機振幅
CGFloat damping = arc4random_uniform(10) + 1;
_snap.damping = damping / 10.0f;
[_animator addBehavior:_snap];
if (UIGestureRecognizerStateBegan == sender.state) {
// 建立附加剛性行爲
CGPoint anchorPoint = CGPointMake(_boxImageView.center.x, _boxImageView.center.y);
_attachment = [[UIAttachmentBehavior alloc] initWithItem:_boxImageView offsetFromCenter:UIOffsetMake(-25.0, -25.0) attachedToAnchor:anchorPoint];
[_animator addBehavior:_attachment];
} else if (UIGestureRecognizerStateChanged == sender.state) {
// 設置行爲的錨點
[_attachment setAnchorPoint:[sender locationInView:self.view]];
} else if (UIGestureRecognizerStateEnded == sender.state) {
// 刪除附加行爲
[_animator removeBehavior:_attachment];
}
注:偏移點偏移必定位置,可使得在拖動手指時產生旋轉的效果
if (UIGestureRecognizerStateBegan == sender.state) {
CGPoint anchor = CGPointMake(_boxImageView.center.x, _boxImageView.center.y - 100);
_attachment = [[UIAttachmentBehavior alloc] initWithItem:_boxImageView attachedToAnchor:anchor];
[_animator addBehavior:_attachment];
[_attachment setFrequency:1.0f];
[_attachment setDamping:0.1f];
} else if (UIGestureRecognizerStateChanged == sender.state) {
[_attachment setAnchorPoint:[sender locationInView:self.view]];
} else if (UIGestureRecognizerStateEnded == sender.state) {
[_animator removeBehavior:_attachment];
}
注:設置了frequency和damping屬性,建立的即爲彈性鏈接
// 計算兩點之間距離
CGFloat distance = sqrtf(powf(p.x - _firstPoint.x, 2.0) + powf(p.y - _firstPoint.y, 2.0));
CGFloat angle = atan2(p.y - _firstPoint.y, p.x - _firstPoint.x);
_push.magnitude = distance / 20;
_push.angle = angle;
[_push setActive:YES];