在iOS7上新增加了UIKit Dynamic,它能够让UIView模拟逼真的物理效果。如重力,碰撞,弹簧,吸附等效果,有了这些效果能轻松的提高应用的用户体验。想要实现这些力学动画效果,首先要创建一个力学动画生成器(UIDynamicAnimator),然后使用各种行为进行定制,可用于定制UIDynamicAnimator的行为的类有:UIAttachmentBehavior
,UICollisionBehavior
,UIGravityBehavior
,UIDynamicItemBehavior
,UIPushBehavior
,UISnapBehavior
。他们能够赋予UIView逼真的行为和动画。
NOTE:每个力学动画生成器都是独立的,多个动画力学生成器可同时运行。要让力学动画生成器持续运行,必须要有指向它的有效应用。一旦动画处于静止状态(如弹簧效果恢复原状)之后,力学动画生成器将暂停,不在执行任何计算了。但是对于未用的力学动画生成器,最好把它删除掉。
生成一个力学动画生成器
UIDynamicAnimator *animator =[ [UIDynamicAnimator alloc] initWithReferenceView:self.view];//行为视图的父视图必须是动画生成器的参考视图
[animator addBehavior:aDynamicBeahvior];//aDynamicBeahvior是一个行为
重力(UIGravityBehavior)
重力的效果如图所示:
对于重力行为,需要注意的有角度(angle)和量级(magnitude,我也叫它重力加速度),实现代码如下:
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[footballView]];
//angle:角度(弧度) magnitude:量级(重力系数)
[gravityBehavior setAngle:3.14/2 magnitude:0.1f];
[self.animator addBehavior:gravityBehavior];
碰撞(UICollisionBehavior)
说到碰撞,一个是物体之间的碰撞,一个是与边界的碰撞,在上面的重力效果演示图中,足球从上落下,一直落到屏幕之外,这是由于我们没有给他设置边界
。我们看看碰撞的效果图:
我给图中的篮球
和足球
设置了重力效果和碰撞效果,代码如下:
UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[self.footballView,self.basketballView]];
[gravityBehavior setAngle:3.14/2 magnitude:0.1f];
//碰撞效果
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.footballView,self.basketballView]];
[collisionBehavior setCollisionMode:UICollisionBehaviorModeEverything];//碰撞效果,必须指定的
/**
* UICollisionBehaviorModeEverything:物体既相互碰撞又与边界碰撞
* UICollisionBehaviorModeBoundaries:物体不相互碰撞,只与边界碰撞
* UICollisionBehaviorModeItems:物体相互碰撞,不与边界碰撞
*/
//设置边界为动画器参考view的视图范围
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
//代理可以监听碰撞
collisionBehavior.collisionDelegate = self;
[self.animator addBehavior:gravityBehavior];
[self.animator addBehavior:collisionBehavior];
连接(UIAttachmentBehavior)
连接就是让一个物体的行为和移动受另外一个物体的移动。使用连接效果要指定连接点。效果大概如下:
在上面的效果演示图中,我添加了一个pan
手势,然后取pan
的坐标点让其成为篮球
的center
,在连接效果的作用下,足球会由于篮球的移动而动,具体代码如下:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.footballView,self.basketballView]];
[collisionBehavior setCollisionMode:UICollisionBehaviorModeEverything];
collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
CGPoint basketballCenter = CGPointMake(self.basketballView.center.x, self.basketballView.center.y);
self.attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.basketballView attachedToAnchor:basketballCenter];
[self.animator addBehavior:collisionBehavior];
[self.animator addBehavior:self.attachmentBehavior];
self.panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(handAttachmentesture:)];
[self.view addGestureRecognizer:self.panGesture];
- (void)handAttachmentesture:(UIPanGestureRecognizer *)gesture{
CGPoint gesturePoint = [gesture locationInView:self.view];
self.basketballView.center = gesturePoint;
[self.attachmentBehavior setAnchorPoint:gesturePoint];
}
弹簧
弹簧效果应该都懂,先看看效果:
弹簧效果其实是在连接效果上实现的,恰当设置连接效果的Frequency
,Damping
这二个属性后就可以达到弹簧的效果了,在上面的代码加上:
[self.attachmentBehavior setFrequency:1.0f];//振动频率
[self.attachmentBehavior setDamping:0.1f];//熨平动画的峰值
吸附(UISnapBehavior)
吸附效果有点像磁铁吸铁块一样,只要我们指定一个点,具有吸附效果的物体
就有了被磁铁
吸过去的效果了。
我们在屏幕上指定一个tap
手势,讲tap
后的点作为磁铁
,代码:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handTapGesture:)];
[self.view addGestureRecognizer:self.tapGesture];
- (void)handTapGesture:(UITapGestureRecognizer *)gesture{
CGPoint point = [gesture locationInView:self.view];
if (self.snapBehavior == nil) {
self.snapBehavior = [[UISnapBehavior alloc] initWithItem:self.footballView snapToPoint:point];
self.snapBehavior.damping = 0.75;
}
[self.animator addBehavior:self.snapBehavior];
}
推力
推力指得是可以对物体施加推力,效果:
我用了一个tap
手势作为施加推力的源,代码如下:
self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UICollisionBehavior * collisionBehavior = [[UICollisionBehavior alloc] initWithItems:@[self.footballView]];
[self.animator addBehavior:collisionBehavior];
UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.footballView] mode:UIPushBehaviorModeInstantaneous];
pushBehavior.angle = 0.0;
pushBehavior.magnitude = 0.;
self.pushBehavior = pushBehavior;
[self.animator addBehavior:self.pushBehavior];
self.tapGesture = [[UITapGestureRecognizer alloc] initWithTarget:self action:@selector(handTapGesture:)];
[self.view addGestureRecognizer:self.tapGesture];
- (void)handTapGesture:(UITapGestureRecognizer *)gesture{
CGPoint point = [gesture locationInView:self.view];
CGPoint origin = CGPointMake(CGRectGetMidX(self.view.bounds), CGRectGetMidY(self.view.bounds));
CGFloat distance = sqrtf(powf(point.x-origin.x, 2.0) + powf(point.y-origin.y, 2.0));
CGFloat angle = atan2(point.y-origin.y, point.x-origin.x);
distance = MIN(distance, 100.0);
[self.pushBehavior setMagnitude:distance/100.0];
[self.pushBehavior setAngle:angle];
[self.pushBehavior setActive:true];
}
物体属性
物体
都有很多的属性,通过对其配置,可以达到不同的效果,下面是一些常用的属性:
属性 | 描述 |
---|---|
elasticity | 表示与其他物体碰撞时的弹性,取值0-1,0表示没有弹性,1表示反弹作用力与碰撞作用力相等 |
allowsRotation | 指定物体在受力时是否会旋转,默认YES |
angularResistance | 旋转助力,值越大旋转下降得越快,取值为0-CGFLOAT_MAX |
density | 物体的密度,调整密度会影响重力和碰撞的效果。默认情况下,100x100的物体质量为1,100x200为2 |
friction | 物体之间的滑动阻力,0表示没有摩擦力,1表示摩擦力很大 |
resistance | 空气阻力,取值为0-CGFLOAT_MAX,0表示没有空气阻力,1表示一旦其他作用力消失,物体就会停止 |
总结
文章代码Demo点这里
UIDynamicAnimator还有代理方法和其他的小方法,真正发挥它的作用力的是你的创意,有好的ideal就动手撸吧!