iOS开发之UIKit Dynamics学习心得

在iOS7上新增加了UIKit Dynamic,它能够让UIView模拟逼真的物理效果。如重力,碰撞,弹簧,吸附等效果,有了这些效果能轻松的提高应用的用户体验。想要实现这些力学动画效果,首先要创建一个力学动画生成器(UIDynamicAnimator),然后使用各种行为进行定制,可用于定制UIDynamicAnimator的行为的类有:UIAttachmentBehaviorUICollisionBehaviorUIGravityBehaviorUIDynamicItemBehaviorUIPushBehaviorUISnapBehavior。他们能够赋予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就动手撸吧!

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 158,847评论 4 362
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 67,208评论 1 292
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 108,587评论 0 243
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 43,942评论 0 205
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 52,332评论 3 287
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 40,587评论 1 218
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 31,853评论 2 312
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 30,568评论 0 198
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 34,273评论 1 242
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 30,542评论 2 246
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 32,033评论 1 260
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 28,373评论 2 253
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 33,031评论 3 236
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 26,073评论 0 8
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 26,830评论 0 195
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 35,628评论 2 274
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 35,537评论 2 269

推荐阅读更多精彩内容