力学动画ide
以dynamicAnimate为首的力学动画是苹果在iOS7加入的API,里面包含了不少力学行为,这套API是基于Box2d实现的。其中包含了重力、碰撞、推、甩、和自定义行为。函数
涉及到的类以下oop
涉及类 | 描述 |
UIDynamicAnimator | 至关于一个manager,用于管理全部添加的力学行为 |
UIDynamicBehavior | 全部力学行为的父类,是一个抽象类 |
UIGravityBehavior | 重力 |
UICollisionBehavior | 碰撞,弹力 |
UIAttachmentBehavior | 吸附力 |
UIPushBehavior | 推力 |
UISnapBehavior | 甩行力 |
UIDynamicItemBehavior | 自定义行为 |
UIDynamicAnimator须要是一个实例变量,若是是局部变量动画会不起做用,我的感受像是动做没有添加到RunLoop在函数执行结束后被释放了。动画
UIDynamicAnimator的初始化须要绑定一个视图,并且与视图必须是一对一的关系。atom
每个行为均可以做用在不少的item上面,只要这个对象实现了<UIDynamicItem>协议,UIView默认就是因此不须要咱们手动实现。spa
下面咱们看几个例子来逐个解释代理
重力code
重力很简单,咱们先看一个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像是在重力做用下向下作匀加速直线运动。blog
上面代码咱们让重力做于在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 boundary 2015-08-19 15:31:49.157 TransAnimate[25564:17037174] end contact boundary 2015-08-19 15:31:49.524 TransAnimate[25564:17037174] began contact boundary 2015-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 | 角阻力,物体旋转时候,旋转方向的阻力 |