力學動畫
以dynamicAnimate為首的力學動畫是蘋果在iOS7加入的API,里面包含了很多力學行為,這套API是基于Box2d實現的。其中包含了重力、碰撞、推、甩、和自定義行為。
涉及到的類如下
涉及類 | 描述 |
UIDynamicAnimator | 相當于一個manager,用于管理所有添加的力學行為 |
UIDynamicBehavior | 所有力學行為的父類,是一個抽象類 |
UIGravityBehavior | 重力 |
UICollisionBehavior | 碰撞,彈力 |
UIAttachmentBehavior | 吸附力 |
UipushBehavior | 推力 |
UISnapBehavior | 甩行力 |
UIDynamicItemBehavior | 自定義行為 |
UIDynamicAnimator需要是一個實例變量,如果是局部變量動畫會不起作用,個人感覺像是動作沒有添加到RunLoop在函數執行結束后被釋放了。
UIDynamicAnimator的初始化需要綁定一個視圖,而且與視圖必須是一對一的關系。
每一個行為都可以作用在很多的item上面,只要這個對象實現了<UIDynamicItem>協議,UIView默認就是所以不需要我們手動實現。
下面我們看幾個例子來逐個解釋
重力
重力很簡單,我們先看一個demo
- (void)viewDidLoad { [super viewDidLoad]; view = [[UIView alloc] initWithFrame:CGRectMake(100, 100, 100, 100)]; view.backgroundColor = [UIColor grayColor]; [self.view addSubview:view]; _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view]; UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[view]]; [gravity setAngle:3.14/2 magnitude:0.5]; [_animator addBehavior:gravity];
}
其中_animator是一個實例變量,上面解釋過了。運行后會發現view像是在重力作用下向下做勻加速直線運動。
上面代碼我們讓重力作于在view上面,同時設置了重力的方向和大小。
@PRoperty (readwrite, nonatomic) CGVector gravityDirection;@property (readwrite, nonatomic) CGFloat angle;@property (readwrite, nonatomic) CGFloat magnitude;- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;
上面是重力的方法和屬性,我們逐個看一下。
gravityDirection是重力向量,既然是向量就有方向和大小。使用的坐標系為UIKit坐標系,所以默認左上角為(0,0)點,而向量的大小就是重力的大小。
angle為向量的方向,我們可以不通過gravityDirection來設定重力方向而用angle設置方向,因為angle更加的直觀不用計算。
同理用magnitude來設置重力的大小。
彈力
彈力是一個很有意思的行為,除了我們設置彈力的item外,還要設置彈力的邊界。
我們先看例子
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[view]];[collisionBehavior addBoundaryWithIdentifier:@"123ß" fromPoint:CGPointMake(0, 300) toPoint:CGPointMake(300, 600)];collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
[_animator addBehavior:collisionBehavior];
彈力中有一個屬性
@property (nonatomic, readwrite) BOOL translatesReferenceBoundsIntoBoundary;
是否把關聯視圖設置為邊界,這里的關聯視圖指的就是UIDynamicAnimator中的視圖。把該屬性設置為YES,運行代碼,大家會發view掉落到底部時會與底部放生彈性碰撞。
其實彈力行為提供了很多關于邊界的方法
- (void)setTranslatesReferenceBoundsIntoBoundaryWithInsets:(UIEdgeInsets)insets;- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier forPath:(UIBezierPath*)bezierPath;- (void)addBoundaryWithIdentifier:(id <NSCopying>)identifier fromPoint:(CGPoint)p1 toPoint:(CGPoint)p2;- (UIBezierPath*)boundaryWithIdentifier:(id <NSCopying>)identifier;- (void)removeBoundaryWithIdentifier:(id <NSCopying>)identifier;
這些都比較簡單就不一一解釋了,感興趣大家可以自己試一下。
下面著重介紹一個屬性
@property (nonatomic, assign, readwrite) id <UICollisionBehaviorDelegate> collisionDelegate;
彈力有一個代理,是不是覺得很有意思,我們繼續看例子
- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2 atPoint:(CGPoint)p{ NSLog(@"began contact item");}- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item1 withItem:(id <UIDynamicItem>)item2{ NSLog(@"end contanct item");}- (void)collisionBehavior:(UICollisionBehavior*)behavior beganContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier atPoint:(CGPoint)p{ NSLog(@"began contact boundary");}- (void)collisionBehavior:(UICollisionBehavior*)behavior endedContactForItem:(id <UIDynamicItem>)item withBoundaryIdentifier:(id <NSCopying>)identifier{ NSLog(@"end contact boundary");}
我們實現彈力的代理并實現方法,運行程序,當初碰到底部的時候我們發現系統打印出了
2015-08-19 15:31:49.123 TransAnimate[25564:17037174] began contact boundary2015-08-19 15:31:49.157 TransAnimate[25564:17037174] end contact boundary2015-08-19 15:31:49.524 TransAnimate[25564:17037174] began contact boundary2015-08-19 15:31:49.557 TransAnimate[25564:17037174] end contact boundary
每次發生彈力將要作用和結束作用都會分別調用代理方法。
根據方法名就可以明白,這兩組代理方法一組針對物體碰撞,一組針對邊界碰撞。
吸附力
關于吸附力,首先要解釋一下,大家可以把吸附力理解為在吸附原點有一根棍,注意是棍不是繩子,連接著item。也就是說吸附力是剛性的。
下面看demo
UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:view attachedToAnchor:CGPointMake(100, 200)]; attachment.length = 100; [_animator addBehavior:attachment];
可以看到這里我們用的吸附力的構造方法是一個點,length就代表"棍"的長度,運行程序發現物體在重力的作用下會以Anchor為中心,以length為半徑,稍微轉一下。
吸附力提供了很多的構造方法
- (instancetype)initWithItem:(id <UIDynamicItem>)item attachedToAnchor:(CGPoint)point;- (instancetype)initWithItem:(id <UIDynamicItem>)item offsetFromCenter:(UIOffset)offset attachedToAnchor:(CGPoint)point;- (instancetype)initWithItem:(id <UIDynamicItem>)item1 attachedToItem:(id <UIDynamicItem>)item2;- (instancetype)initWithItem:(id <UIDynamicItem>)item1 offsetFromCenter:(UIOffset)offset1 attachedToItem:(id <UIDynamicItem>)item2 offsetFromCenter:(UIOffset)offset2;
這兩組構造方法的區別在于吸附對象,第一組是以點為對象,第二組以item為對象。
再解釋一下offset,這里指的是被吸附對象的錨點偏移量,默認是center。
下面看一下屬性
@property (readonly, nonatomic) UIAttachmentBehaviorType attachedBehaviorType;@property (readwrite, nonatomic) CGPoint anchorPoint;@property (readwrite, nonatomic) CGFloat length;@property (readwrite, nonatomic) CGFloat damping; @property (readwrite, nonatomic) CGFloat frequency;
UIAttachmentBehaviorType屬性表明是吸附點是對象還是錨點。
下面幾個分別是錨點,吸附長度,阻力和振動頻率,就不說了。
推力
和重力差不多這里就不舉例子了看一下屬性和方法
- (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;@property (nonatomic, readonly) UIPushBehaviorMode mode;@property (nonatomic, readwrite) BOOL active;@property (readwrite, nonatomic) CGFloat angle;@property (readwrite, nonatomic) CGFloat magnitude;@property (readwrite, nonatomic) CGVector pushDirection;- (void)setAngle:(CGFloat)angle magnitude:(CGFloat)magnitude;
下面的angle、magnitude、pushDirection和重力一模一樣不多說了。
重點說一下UIPushBehaviorMode和active
UIPushBehaviorMode表示該推力是持續作用還是短暫作用,active表示推力是否還在作用。
上面的- (void)setTargetOffsetFromCenter:(UIOffset)o forItem:(id <UIDynamicItem>)item;方法是說推力作用點的偏移量,默認是center。
甩行力
甩行力我也解釋不是很清楚,我覺的可以理解為一個黑洞在吸附物體吧,這樣應該挺形象的...
直接看例子吧
我們用故事板對控制器添加一個tapGesture的事件
- (IBAction)handleGesture:(UIGestureRecognizer *)sender { CGPoint point = [sender locationInView:self.view]; UISnapBehavior *snap = [[UISnapBehavior alloc] initWithItem:view snapToPoint:point]; [_animator addBehavior:snap];}
運行程序發現我們點擊的位置,view會直接飛過去并且中間會有阻力。
甩行力只有一個屬性,就是阻力。
自定義行為
一般我們都是用不上自定義行為的,只有在少數時候需要自己定制
我們可以定制的屬性有很多
屬性 | 描述 |
desnsity | 密度,如果一個100*100點的物體,它的密度為1.0,作用力是1.0那么它的加速度就是100點/S2 |
elasticity | 彈力洗漱,取值范圍0.0~1.0,0.0代表沒有彈力,1.0代表返券彈性碰撞 |
friction | 摩擦系數,0.0表示沒有摩擦力,1.0表示摩擦力很強,如果要設置更強的可以大于1 |
resistance | 阻力,物體運動的時候,在線性方向的阻力,0.0沒有阻力,CGFLOAT_MAX表示最大阻力 |
allowRotation | 是否允許旋轉。 |
angularResistance | 角阻力,物體旋轉時候,旋轉方向的阻力 |
新聞熱點
疑難解答