重力学这个名词不论在哪个行业领域听起来似乎都很高大上。那么在Swift中的重力学是什么呢?那就是将我们移动端屏幕上毫无生命力的东西也置于万有引力中,使它们能够展现出好像真的由于引力而向下坠落以及碰到物体后自然的弹开的效果。
要想做到这一点,我们得需要两个利器:UIKit Dynamics
和Motion Effects
。
-
UIKit Dynamics
是UIKit
中一套完整的物理引擎。它可以让我们在程序中对界面元素添加一些行为从而达到诸如重力、弹簧等现实中的动作行为。你只需在引擎中注册界面元素,并指定好物理行为,其他的事就交给物理引擎去完成了。 -
Motion Effects
可以创建很酷的视差效果,就像你iPhone上横竖屏切换时那样。它基于Apple提供的重力加速器提供的数据计算分析,使我们的界面元素根据移动设备的倾斜方向做出相应的反应。
当这两者一起使用的时候,我们就可以让程序活起来,富有生命力。
让我们开始屌丝的逆袭
我们挑一些小例子来学习UIKit Dynamics
。
注:由于个人编码习惯,在Swift代码中我还是加了
;
,其实可加可不加,根据大家喜好。
打开Xcode6新建项目,选择iOS Application/Single View Application
,名称随便取,我这里命名为UIKitDynamicsDemo
,我们可以看到Single View Application
的目录结构:
打开ViewController.swift
文件,在viewDidLoad
方法中添加如下代码:
// 创建一个正方形View,颜色设置为蓝绿色,加入当前的View中
let square = UIView(frame: CGRect(x: 100, y: 100, width: 100, height: 100));
square.backgroundColor = UIColor.cyanColor();
self.view.addSubview(square);
上面的代码在我们的屏幕上添加了一个蓝绿色的正方形UIView
。运行一下,我们能看到一个木讷的蓝绿色正方形静静的待在屏幕中:
如果你用真机运行,你可以摇晃一下手机、倾斜手机、拿着手机手舞足蹈一下,看看那个木讷的方块有什么反应和变化么?答案是要有反应你就见鬼了。因为我们写的这几行代码只能让它杵在那一动不动,那怎么能让它动起来呢?接下来让我们见证奇迹的时刻!
添加重力行为
在ViewController.swift
文件中添加两个属性:
注:代码中感叹号的作用这里不做过多介绍,请自行查阅官方文档。
然后在viewDidLoad
方法中再加入以下代码:
现在再编译运行一下,这时我们可以看到这个蓝绿色正方形开始做自由落体运动了,一直跌落出屏幕下边缘然后消失。
我们来看看刚才我们添加的两个属性的类型:
- UIDynamicAnimator属于
-
UIGravityBehavior
是一个模拟重力的模型,可作用于一个或多个元素。它的构造函数需要传入一个数组,该数组的内容就是我们希望有重力表现的一个元素或多个元素。
UIKit
物理引擎中的类。它的作用是跟踪你添加到物理引擎中的各种行为动作,比如这里的重力行为,并且提供整个上下文。实例化UIDynamicAnimator
时,它的构造函数需要传入一个referenceView
参数,用于告知它要跟踪并制定坐标的View
。
大多数的行为都有一些配置属性,比如重力行为就有可以改变角度和速率的属性:
上述代码中的angle
是重力行为的角度属性,angle
的值为0时,方块会水平向右移动,随着值的增大,方块会顺时针改变角度。不过我们要模拟现实中的重力,所以该属性一般不设置,不设置时默认是垂直向下移动。magnitude
是重力行为的速率属性,值越大下降的速度越快,当magnitude
属性的值为0时,方块就不会下降了,所以最小的速率是0.1。
注意:在现实世界中,重力加速度大约是
g = 9.80665m/s^2
,就是9.8米每平方秒。根据牛顿第二定律,我们可以使用0.5 * g * Time^2
公式来计算下坠距离。
在UIKit的重力世界中,计算重力加速度的公式是一样的,但是单位有所不同。不是米而是像素,即g = 1000pixels/s^2
,我们同样可以使用牛顿第二定律来计算我们的方块在单位时间内下降的距离。我们只需要知道重力加速度g
越大,坠落速度越快,所以上述代码中的magnitude
属性就差不多是这意思。
不能让我们的方块一坠千里
从目前代码的运行状况知道,我们的方块下降到屏幕底部时丝毫没有停止的意思,直接坠崖而下,看都看不见。我们希望我们的屏幕类似一个盒子一样,方块在盒子中,当下降到底部时就停止,那么我们就需要设置一个边界。
在ViewController.swift
文件中再添加一个属性:
然后在viewDidLoad
方法中加入以下几行代码:
上面的代码创建了边界行为,它会将一个或多个边界与指定的View联系起来,并使两者有具有交互行为。
从上面代码我可以注意到collision.translatesReferenceBoundsIntoBoundary = true;
这行代码,它的意思是将UIDynamicAnimator
引用的View的边界作为碰撞行为的触发边界,这样就不用我们再去设置边界的坐标了,非常好用。
接着我们编译运行看看,此时小方块坠落到屏幕底部时会产生碰撞效果,并且还会反弹几下,是不是很逼真呢。
碰撞行为进阶应用
接下来我们在屏幕中再添加一个View,长方形并横在屏幕中间,在// 创建一个长方形View,颜色设置为红色,加入当前的View中
let barrier = UIView(frame:CGRect(x: 0, y: 300, width: 140, height: 20));
barrier.backgroundColor = UIColor.redColor();
self.view.addSubview(barrier);