UIDynamic和iOS7的物理效果

接着上一篇文章,这里整理一下UIMotionEffect的姊妹篇,说说iOS7中的UIDynamics和物理效果。做过游戏开发、用过游戏开发引擎的朋友们可能对Box2D、chipmunk并不陌生,他们可以使你开发出来的游戏具有各种物理效果。在iOS7中,也有类似的工具,不过它不是物理引擎,他是UIKit提供的非常方便的API,UIDynamic。

0. UIDynamic概述

在iOS7的锁屏页,在右下角可以看到拍照的按钮,拖动这个按钮垂直向上,则照相的应用会直接打开。假如我们向上推到一半,松开,页面会沿着屏幕垂直向下做“自由落体”运动。或者,更进一步,我们用力向下回滑已经抬起的锁屏页面,页面会加速滑下并和页面底部边缘撞击反弹。如下图所示:

锁屏页的重力和碰撞效果

滑动锁屏页时的Dynamic效果

在这个过程中,实际上至少涉及了两类Dynamic效果,“重力”和“碰撞”。

我们来看一下UIDynamic的几个主要概念:

  • Behavior 。直接翻译过来就是“行为”,实际上也就是UIDynamic的物理效果。这个对象定义了一类效果,包括效果的具体属性。
  • Dynamic Item 。动态效果项目,也就是实际中应用了效果的对象,通常是UIView对象,比如上图例子中的锁屏页View。
  • Animator 。“动画绘制者”,实际上就是动画效果发挥作用的上下文,类似于物理引擎中物理效果的作用空间。这个通常也和一个View对应。

下面单独介绍下UIDynamicBehavior和UIDynamicAnimator,也看看这几个主要对象是怎么结合起来的。

1. UIDynamicBehavior和UIDynamicAnimator

按照上面的介绍,UIDynamicBehavior和UIDynamicAnimator就是UIDynamic中最重要的两个角色,一个代表着具体的物理效果,另一个则是这个效果展示的上下文。是的,没错,UIDynamicAnimator中也刚好有一个我们期待的,最重要的方法,那就是:

- (void)addBehavior:(UIDynamicBehavior *)behavior;

这样,效果和展示的上下文就关联了起来。就是这么简单!

那么问题来了,这两个对象和传统的UIKit中的其它类的对象,比如UIView是什么关系呢?我们回头再来看UIDynamicBehavior和UIDynamicAnimator这两个类的文档或头文件,发现其声明非常简单,都是直接继承自NSObject,方法也不多。

在UIDynamicAnimator的头文件中,给了这样一个初始化方法:

- (instancetype)initWithReferenceView:(UIView*)view;

这个方法的参数是一个UIView,我们叫做ReferenceView。无论是那种物理效果,其运动都是相对于一个上下文的,这个上下文就是我们这里的“参照视图”,ReferenceView。比如锁屏效果的例子,我们可以认为这个ReferenceView就是占据整个屏幕的rootView。

除了这个ReferenceView以外,就是具体发生物理效果的对象,在UIDynamic中我们叫做Item。这个Item的定义有一个protocol,即UIDynamicItem,不过通常情况下它就是一个具体的View,所以我们看到UIView在新版本的API中也有了<UIDynamicItem>这样一个声明。

虽然在UIDynamicBehavior中并没有直接提供类似ReferenceView参数的初始化方法,不过UIDynamicBehavior的各个子类几乎都提供了类似的方法:

- (instancetype)initWithItems:(NSArray *)items;

这样UIKit中传统的View对象就和UIDynamicAnimator、UIDynamicBehavior关联了起来,一起实现了UIDynamic物理效果。

2. Gravity和Collision效果

UIDynamicBehavior有很多子类,或者说iOS7中提供了很多具体的Dynamic效果。我们这里就简单以Gravity和Collision效果为例,介绍一下。

Gravity不管翻译为“重力”还是“万有引力”,效果其实都可以认为是一致的,结果是类似落体的加速运动,而最重要的参数是受力的方向和大小。

animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[itemView]];
CGVector gravityDirection = {0.0, -1.0};
[gravity setGravityDirection:gravityDirection];
[animator addBehavior:gravity];

像这样,牛顿的苹果就向上飞而不是向下落了。

类似的,碰撞反弹的效果也比较简单:

UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithItems:@[ itemView ]];
[collision setTranslatesReferenceBoundsIntoBoundary:YES];
[animator addBehavior:collision]

这是最简单的碰撞效果。如果想做得更漂亮一些,可以考虑用UIDynamicItemBehavior来设置一些通用的物理属性,比如弹性等。

另外,如果在碰撞过程中的各个环节想做定制处理,可以考虑使用UICollisionBehavior的delegate。

3. 其它

除了上面提到的Gravity和Collision外,还有Attach、Push等UIDynamic物理效果。

由于UIDynamic是iOS7的新特性,有很多兼容性考虑比较多的App并没有大范围使用。关于UIDynamic的文档苹果也提供的不是很多。在WWDC 2013的Session中有两篇做了介绍。

在我整理本文时,看到github上这里有一个完整的例子不错,大家感兴趣的还可以去看一下。

相关文章:

此条目发表在 iOS, iOS开发基础, 开发, 计算机技术 分类目录,贴了 , , , , 标签。将固定链接加入收藏夹。

UIDynamic和iOS7的物理效果》有 1 条评论

发表评论

电子邮件地址不会被公开。 必填项已用 * 标注

您可以使用这些 HTML 标签和属性: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>