概念介紹
UIDynamic從ios7才開始有的规丽,其他2D仿真引擎:
BOX2D:C語言框架蒲牧,免費
Chipmunk:C語言框架免費,其他版本收費(C#赌莺、Objective-C冰抢、Java)必須遵守了UIDynamicItem協(xié)議的控件才能應用這些行為,UIView遵守了艘狭,所以所有控件都可以使用
使用步驟:創(chuàng)建一個動畫者對象UIDynamicAnimator并設置坐標系挎扰,再添加一個動畫行為對象(并設置動畫作用的控件)
UIDynamic中的三個重要概念
- UIDynamicAnimator:動畫者翠订,為動力學元素提供物理學相關的能力及動畫,同時為這些元素提供相關的上下文遵倦,是動力學元素與底層iOS物理引擎之間的中介尽超,將Behavior對象添加到Animator即可實現(xiàn)動力仿真
- UIDynamicBehavior:仿真行為,是動力學行為的父類骇吭,基本的動力學行為類UIGravityBehavior橙弱、UICollisionBehavior歧寺、UIAttachmentBehavior燥狰、UISnapBehavior、UIPushBehavior以及UIDynamicItemBehavior均繼承自該父類
- UIDynamicItem:動力學元素(動力項斜筐,就是應用行為的控件)龙致,是任何遵守了UIDynamicItem協(xié)議的對象,從iOS 7.0始顷链,UIView和UICollectionViewLayoutAttributes默認實現(xiàn)該協(xié)議目代。如果自定義的對象實現(xiàn)了該協(xié)議,即可通過Dynamic Animator實現(xiàn)物理仿真
UIDynamicAnimator(動畫者)
是動力行為(UIDynamicBehavior)的容器嗤练,添加到容器內(nèi)的行為才會發(fā)揮作用
注意UIDynamicAnimator對象是否是強引用榛了,可以創(chuàng)建一個強引用animator屬性,進行懶加載
方法:
- 創(chuàng)建一個動畫者并設置一個坐標系view煞抬,參數(shù):動畫效果在哪個view的范圍霜大、坐標系之內(nèi)
-(instancetype)initWithReferenceView:(UIView *)view;
例子:
UIDynamicAnimator *animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
2.添加行為
- (void)addBehavior:(UIDynamicBehavior *)behavior;
3.移除行為、移除所有行為
- (void)removeBehavior:(UIDynamicBehavior *)behavior;
- (void)removeAllBehaviors;
屬性:
1.獲取坐標系View
@property (nullable, nonatomic, readonly) UIView *referenceView;
2.獲取所有行為對象
@property (nonatomic, readonly, copy) NSArray<__kindof UIDynamicBehavior*> *behaviors;
動力行為(UIDynamicBehavior)
所有的動力學行為可以獨立作用也可以組合使用革答,注意:避免重復添加行為對象战坤,可以用懶加載
UIDynamicBehavior (抽象類):
UIGravityBehavior:重力行為
UICollisionBehavior:碰撞行為
UISnapBehavior:甩行為
UIAttachmentBehavior:附著行為
UIPushBehavior:推行為
UIDynamicItemBehavior:動力學元素行為(執(zhí)行動畫物體自身的行為)
UIDynamicItem 協(xié)議,動力學元素残拐、動力項協(xié)議
ios9新特性參考 http://www.cocoachina.com/ios/20150719/12613.html
@property (nonatomic, readwrite) CGPoint center;
@property (nonatomic, readonly) CGRect bounds;(只讀)
@property (nonatomic, readwrite) CGAffineTransform transform;
一途茫、抽象類 UIDynamicBehavior
屬性:
1.獲取添加到該動態(tài)行為中的子動態(tài)行為
@property (nonatomic, readonly, copy) NSArray<__kindof UIDynamicBehavior *> *childBehaviors;
2.action屬性:行為執(zhí)行期間一直調(diào)用這個action block,可以用來不斷監(jiān)聽行為溪食,如在block中重繪
@property (nullable, nonatomic,copy) void (^action)(void);
3.獲取該動態(tài)行為相關聯(lián)的dynamicAnimator
@property (nullable, nonatomic, readonly) UIDynamicAnimator *dynamicAnimator;
方法:
1囊卜、添加一個子動態(tài)行為
- (void)addChildBehavior:(UIDynamicBehavior *)behavior;
2、移除一個子動態(tài)行為
- (void)removeChildBehavior:(UIDynamicBehavior *)behavior;
3错沃、 當該動態(tài)行為將要被添加到一個UIDynamicAnimator中時边败,這個方法會被調(diào)用
- (void)willMoveToAnimator:(nullable UIDynamicAnimator *)dynamicAnimator;
二、UIGravityBehavior(重力行為)
屬性
1.獲取該重力行為的所有動力項
@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
2.重力的方向捎废,默認(0.0,1.0)向下移動
(1.0,1.0)笑窜,是右下角移動,(1.0,0.0)是向右移動登疗,坐標上非0的位置表示移動的方向
@property (readwrite, nonatomic) CGVector gravityDirection;
例子:
gravity.gravityDirection = CGVectorMake(1.0, 1.0);
3.方向的弧度排截,向哪個方向進行重力動畫(和上面的效果差不多)
@property (readwrite, nonatomic) CGFloat angle;
例子:
gravity.angle = M_PI_2;
4.力度嫌蚤、力量(越大掉的越快,默認是1)
@property (readwrite, nonatomic) CGFloat magnitude;
方法
1.創(chuàng)建一個重力行為同時添加一組動力項
- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items;
例子:
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[self.redView]];
2.添加一個動力項
- (void)addItem:(id <UIDynamicItem>)item;
3.移除一個動力項
- (void)removeItem:(id <UIDynamicItem>)item;
4.設置重力方向和力度
- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;
三断傲、UICollisionBehavior:碰撞行為
屬性
1.獲取該碰撞行為的所有動力項
@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
2.碰撞模式
@property (nonatomic, readwrite) UICollisionBehaviorMode collisionMode;
UICollisionBehaviorMode 枚舉:
UICollisionBehaviorModeItems 僅僅和控件碰撞
UICollisionBehaviorModeBoundaries 僅僅和邊界碰撞
UICollisionBehaviorModeEverything 可以和邊界和控件碰撞
3.是否以參照視圖的bounds為碰撞邊界脱吱,設置為YES會設置當前view為邊界
@property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;
4.獲取該碰撞所有的邊界標識
@property (nullable, nonatomic, readonly, copy) NSArray<id <NSCopying>> *boundaryIdentifiers;
5.代理對象(可以監(jiān)聽動力項的碰撞過程)
@property (nullable, nonatomic, weak, readwrite) id <UICollisionBehaviorDelegate> collisionDelegate;
方法
1.創(chuàng)建一個碰撞行為同時添加給一組動力項
- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items;
2.給該行為添加一個動力項
- (void)addItem:(id <UIDynamicItem>)item;
3.給該行為移除一個動力項
- (void)removeItem:(id <UIDynamicItem>)item;
4.設置參照視圖的bounds為邊界,并且設置視圖的內(nèi)邊距
- (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;
5.設置邊界線的兩種方法认罩,identifier參數(shù)是給這個邊界隨意取一個標識箱蝠,碰到邊界后會產(chǎn)生一些行為方法,所以要指定一個標識垦垂,用于以后引用
(1)設置一個貝塞爾曲線路徑為邊界
- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath *)bezierPath;
例子:
UIBezierPath *path = [UIBezierPath bezierPathWithOvalInRect:CGRectMake(0, 0, 320, 320)];
[collision addBoundaryWithIdentifier:@"circle" forPath:path];
(2)設置一條線為邊界
- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;
6.移除該碰撞所有邊界
- (void)removeAllBoundaries;
7.根據(jù)邊界標識獲取路徑
- (nullable UIBezierPath *)boundaryWithIdentifier:(id <NSCopying>)identifier;
8.根據(jù)邊界標識移除邊界
- (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier;
UICollisionBehaviorDelegate 代理方法:
注意:碰撞代理是collisionDelegate宦搬,而不是delegate,注意與父類代理區(qū)分劫拗,如:
collision.collisionDelegate = self;
1.一個動力項碰到另一個動力項:
(1)一個動力項開始碰到另一個動力項時調(diào)用
- (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p;
(2)一個動力項結(jié)束碰到另一個動力項時調(diào)用
- (void)collisionBehavior:(UICollisionBehavior *)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2;
2.動力項和邊界的碰撞:
(1)動力項開始碰到某個邊界
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier atPoint:(CGPoint)p;
(2)動力項結(jié)束碰到某個邊界
- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier;
例子:一個動力項碰撞到邊界后改變不同顏色
// 碰撞行為的代理方法
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(nullable id <NSCopying>)identifier atPoint:(CGPoint)p {
//獲取當前碰撞到邊界的動力項(把item參數(shù)強轉(zhuǎn)成使用的控件)
UIView *view = (UIView *)item;
//獲取當前碰撞到的邊界名稱
NSString *ID = (NSString *)identifier;
//判斷當前碰撞到的邊界是否是“黃色view的邊界”
if ([ID isEqualToString:@"yellow_boundary"]) {
//碰到后就變成藍色
view.backgroundColor = [UIColor blueColor];
//0.3秒后變成紅色
[UIView animateWithDuration:0.3 animations:^{
view.backgroundColor = [UIColor redColor];
}];
}
}
四间校、UISnapBehavior(甩行為)
效果:觸摸哪個點這個紅色塊就跟隨到哪里,并產(chǎn)生附著效果页慷,甩行為可以將視圖通過動畫甩(吸附)到某個點上
屬性
1.振幅憔足,默認0.5,0振幅最大酒繁,1振幅最小
@property (nonatomic, assign) CGFloat damping;
2.設置附著點
@property (nonatomic, assign) CGPoint snapPoint;
方法
1.創(chuàng)建一個甩行為同時設置動力項和附著點
- (instancetype)initWithItem:(id <UIDynamicItem>)item snapToPoint:(CGPoint)point;
例子:
- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event {
UITouch *touch = touches.anyObject;
CGPoint loc = [touch locationInView:self];
// 1. 創(chuàng)建動畫者
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self];
// 2. 創(chuàng)建物理行為
UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:self.redView snapToPoint:loc];
snap.damping = 0;
// 3. 把行為添加到animator中
[self.animator addBehavior:snap];
}
五滓彰、UIAttachmentBehavior(附著行為、吸附行為)
描述一個view和一個錨相連接的情況州袒,也可以描述view和view之間的連接
在多個物體間設定多個UIAttachmentBehavior揭绑,可以模擬多物體連接
注意:吸附行為重復添加的問題,建議懶加載行為對象
分為剛性附著和彈性附著
1稳析、剛性附著洗做,固定了length就是剛性附著,紅彰居、藍兩點距離固定
attachment.length = 100;
2诚纸、彈性附著(設置了頻率和振幅),紅陈惰、藍兩色像皮筋一樣距離不固定
attachment.damping = 0;
attachment.frequency = 0.5;
屬性
1.獲取該吸附行為的所有動力項
當吸附行為類型是UIAttachmentBehaviorTypeItems
時有l(wèi)兩個動力項畦徘,當吸附行為類型是UIAttachmentBehaviorTypeAnchor
時只有一個動力項
@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
2.獲取連接類型
@property (readonly, nonatomic) UIAttachmentBehaviorType attachedBehaviorType;
UIAttachmentBehaviorType 枚舉:
UIAttachmentBehaviorTypeItems 連接到視圖view(至少兩個動力項)
UIAttachmentBehaviorTypeAnchor 連接到錨點(只有一個動力項)
3.設置動力項吸附的錨點
@property (readwrite, nonatomic) CGPoint anchorPoint;
4.視圖點連接錨點的距離,兩個吸附點之間的距離
@property (readwrite, nonatomic) CGFloat length;
5.只要設置了以下兩個屬性抬闯,即為彈性連接
(1)振幅大小井辆, 吸附行為減弱的阻力大小
@property (readwrite, nonatomic) CGFloat damping;
(2)振幅頻率
@property (readwrite, nonatomic) CGFloat frequency;
方法
注意: 吸附行為的創(chuàng)建不是直接 alloc + init, 而是 alloc + initWithItem
1.構(gòu)造方法
(1)創(chuàng)建一個吸附行為,讓一個動力項的中點和一個指定的錨點進行吸附溶握,該初始化方法的吸附行為的類型是UIAttachmentBehaviorTypeAnchor
- (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point;
(2)創(chuàng)建一個吸附行為杯缺,讓兩個動力項的中點進行吸附, 該初始化方法的吸附行為的類型是UIAttachmentBehaviorTypeItems
- (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2;
(3)創(chuàng)建一個吸附行為睡榆,讓一個動力項的某一點和指定的錨點進行吸附萍肆,UIAttachmentBehaviorTypeAnchor
類型袍榆,offset相對于動力項center的偏移
- (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(UIOffset)offset attachedToAnchor:(CGPoint)point;
(4)創(chuàng)建一個吸附行為,讓一個動力項的某一點和另一個動力項的某一點進行吸附塘揣,UIAttachmentBehaviorTypeItems
類型包雀,offset相對于動力項center的偏移
- (instancetype)initWithItem:(id <UIDynamicItem>)item1 offsetFromCenter:(UIOffset)offset1 attachedToItem:(id <UIDynamicItem>)item2 offsetFromCenter:(UIOffset)offset2;
把以子視圖為基準的坐標轉(zhuǎn)換為以父視圖為基準的視圖坐標方法:
注意:不能直接修改子控件的anchorPoint為0,0亲铡,因為以后使用center就會導致無法使用2判础!奖蔓!
UIPushBehavior(推行為)
注意要進行懶加載赞草,多次添加會導致無效
1.獲取該行為作用的動力項
@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
2.推力類型
@property (nonatomic, readonly) UIPushBehaviorMode mode;
UIPushBehaviorModeContinuous 持續(xù)推力
UIPushBehaviorModeInstantaneous 瞬時推力
3.是否激活,active表示推力是否還在作用锭硼,如果是瞬時推力房资,需要激活
@property (nonatomic, readwrite) BOOL active;
4蜕劝、推動角度檀头,可使用0~M_PI*2之間的值來定位所有方向
@property (readwrite, nonatomic) CGFloat angle;
5、重力加速度岖沛,推力大小暑始,越遠力量越大,默認為1.0婴削,可取負值
@property (readwrite, nonatomic) CGFloat magnitude;
算法:取觸摸點loc的x,y與動力項的中點center的x,y做差算出兩條直線長度廊镜,再用勾股定理:sqrt(x2+y2) 求出
例子:
CGFloat offsetX = loc.x - self.redView.center.x;
CGFloat offsetY = loc.y - self.redView.center.y;
CGFloat distance = sqrtf(powf(offsetX, 2.0) + powf(offsetY, 2.0));
//powf 函數(shù)為浮點型的參數(shù)1的參數(shù)2次方
6.推動方向,CGVector 矢量
@property (readwrite, nonatomic) CGVector pushDirection;
例子:push.pushDirection = CGVectorMake(1, 1);
方法:
1.將行為添加到動力項當中
- (void)addItem:(id <UIDynamicItem>)item;
2.將行為從動力項當中移除
- (void)removeItem:(id <UIDynamicItem>)item;
3.創(chuàng)建一個推行為添加給一組動力項唉俗,并設置推力類型
- (instancetype)initWithItems:(NSArray<id<UIDynamicItem>> *)items mode:(UIPushBehaviorMode)mode;
4.設置推動角度和力度
- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;
5.獲取推力作用點的偏移量嗤朴,默認是center
- (UIOffset)targetOffsetFromCenterForItem:(id <UIDynamicItem>)item;
6.設置推力作用點的偏移量,默認是center
- (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;
UIDynamicItemBehavior(動力項行為)
控件本身的行為:彈性系數(shù)虫溜、摩擦系數(shù)雹姊、密度、阻力衡楞、角阻力以及是否允許旋轉(zhuǎn)等
屬性
1.獲取有該行為的所有動力項
@property (nonatomic, readonly, copy) NSArray<id <UIDynamicItem>> *items;
2.設置彈性系數(shù)吱雏,決定了碰撞的彈性程度,比如碰撞時物體的彈性瘾境,值從0—1歧杏,0為無彈力
@property (readwrite, nonatomic) CGFloat elasticity;
3.摩擦系數(shù),決定了沿接觸面滑動時的摩擦力大小迷守,0為無摩擦犬绒,1最大
@property (readwrite, nonatomic) CGFloat friction;
4.密度,和size結(jié)合使用兑凿,計算物體的總質(zhì)量凯力。質(zhì)量越大眨业,物體加速或減速就越困難,默認為1
@property (readwrite, nonatomic) CGFloat density;
5.阻力沮协,決定線性移動的阻力大小龄捡,與摩擦系數(shù)不同,摩擦系數(shù)只作用于滑動運動慷暂,0為無阻力
@property (readwrite, nonatomic) CGFloat resistance;
6.角阻力聘殖,決定旋轉(zhuǎn)運動時的阻力大小
@property (readwrite, nonatomic) CGFloat angularResistance;
7.是否允許旋轉(zhuǎn),設置這個屬性為 NO 無論施加多大的轉(zhuǎn)動力物體都不會轉(zhuǎn)動
@property (readwrite, nonatomic) BOOL allowsRotation;
8.charge 代表能夠影響一個動力項在電磁場上如何移動的電荷
@property (readwrite, nonatomic) CGFloat charge;
9.anchored本質(zhì)上是將圖形變成了碰撞中的一個靜態(tài)物體行瑞,但沒有響應事件(如果有什么東西撞上了它奸腺,它會絲毫不動),所以可以完美地用來表示地板或墻壁血久。
@property (nonatomic, getter = isAnchored) BOOL anchored;
方法
1.創(chuàng)建一個動力項行為對象突照,并添加到一組動力項當中
- (instancetype)initWithItems:(NSArray<id <UIDynamicItem>> *)items;
2.將行為添加到動力項當中
- (void)addItem:(id <UIDynamicItem>)item;
3.將行為從動力項當中移除
- (void)removeItem:(id <UIDynamicItem>)item;
4、配置一些公用的屬性氧吐,與其他的Dynamic Behavior共同配合
(1)添加線速度讹蘑,滑行時候的速度
- (void)addLinearVelocity:(CGPoint)velocity forItem:(id <UIDynamicItem>)item;
(2)獲取線速度
- (CGPoint)linearVelocityForItem:(id <UIDynamicItem>)item;
(3)添加角速度,旋轉(zhuǎn)時候的速度
- (void)addAngularVelocity:(CGFloat)velocity forItem:(id <UIDynamicItem>)item;
(4)獲取角速度筑舅,動力項自身旋轉(zhuǎn)的速度
- (CGFloat)angularVelocityForItem:(id <UIDynamicItem>)item;