这回开始学习iOS7新的UIKit Dynamics,我看有人翻译成UIKit 力学,我觉得倒挺贴切的,所以就借来用一用。
这个UIKit力学系统里要设计到四个东西:
1、UIDynamicAnimator:这个东西主要用于
- 提供动力xing为的上下文
- 根据ref view确定坐标系
- 控制动力引擎
- 维护着动力行为的状态
2、UIDynamicBehavior:主要用来描述动力的行为,iOS7里默认提供了以下几种行为
- UIAttachmentBehavior
- UICollisionBehavior
- UIDynamicItemBehavior
- UIGravityBehavior
- UIPushBehavior
- UISnapBehavior
3、Reference View:这个是用来初始化Animator的时候用的,作用是给动力行为提供参考坐标系
4、dynamic item:动力项就是遵循UIDynamicItem协议的任意对象。
说了那么多理论,我自己都搞不清楚了,直接上代码吧。
首先来一个最简单的demo,新建一个项目,选择single VIew Application,然后在ViewController.m里声明几个变量。
1 UIDynamicAnimator *_animator;
2 UIGravityBehavior *_gravity;
然后写一个小方法:
1 - (void)startAnimator
2 {
3 //新建一个view来做试验的物体。
4 UIView *testView = [[UIView alloc] initWithFrame:CGRectMake(110, 60, 100, 100)];
5 [testView setBackgroundColor:[UIColor blueColor]];
6 [self.view addSubview:testView];
7 //初始化animator并且给它一个参考坐标。
8 _animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
9 _gravity = [[UIGravityBehavior alloc] initWithItems:@[testView]];
10 [_animator addBehavior:_gravity];
11 }
再把这个方法在viewDidLoad方法里用一下,就OK了。
再运行程序,就会看见有模拟器上面有个蓝色的小球,然后他往下掉,接着就不见了= =。有点无聊。。。
现在无聊没关系,后面我们再玩点别的,现在先来研究一下这个暂时很无聊的程序代码是怎么写的,其实很简单,首先新建一个UIView实例名字叫testView,弄成一个蓝色小球的样子,然后初始化_animator再给他参考坐标,基本上UIKit力学里的所有动作都要经它手,然后初始化_gravity,给他testView。这个_gravity顾名思义,就是给testView一个类似受到地心引力的效果,会往下掉,而往下掉的加速度默认是跟现实中的重力加速度一样的。最后把_gravity这个行为加入到_animator,就完成了!
好,接下来我们研究点别的,虽然说_gravity名字叫gravity,但是我们能不能改一下加速度?可以的,下面我们来研究一下怎么改。
翻看一下UIGravityBehavior文挡,发现一个名字叫magnitude的属性,很明显就是这个改变加速度了。在_gravity初始化的那行后面加上
1 [_gravity setMagnitude:100];
再运行程序,就会发现那个蓝色方块一下就飞出去了,没错,就是它了。
另外
UIGravityBehavior
中还有几个属性
- angle:控制物体飘向的角度
- graviteDirection:也是控制角度,只不过是用x,y的增量来表示
好了,知道这几个属性我们就可以控制物体怎么飘了。
但是方块一下子就飘出去了,该怎么让他留在模拟器视图里面呢?这就要用到
UICollisionBehavior
了。
顾名思义就是一个碰撞行为,让他碰到视图边缘也算一个碰撞行为。
再ViewController.m里也声明一个UICollisionBehavior的实例名字叫_collision.
1 UICollisionBehavior * _collision;
然后在startAnimator方法里初始化一下,就在最后写就可以
1 _collision = [[UICollisionBehavior alloc] initWithItems:@[testView]];
2 [_collision setTranslatesReferenceBoundsIntoBoundary:YES];
3 [_animator addBehavior:_collision];
然后就可以看到方块掉到视图底部的时候,弹了几下,就停了。实现也很简单,初始化,给它testView,然后改
TranslatesReferenceBoundsIntoBoundary
属性为YES,最后将这个行为加到_animator里面就可以了。
TranslatesReferenceBoundsIntoBoundary
这个属性也很直观,就是告诉他把视图当边界就是了。
除了把视图边缘当碰撞的边界,我们也可以自定义一个边界。UICollisionBehavior也提供了这样一个方法来定义边界
用法如下:
1 [_collision addBoundaryWithIdentifier:@"barrier" fromPoint:CGPointMake(0, 360) toPoint:CGPointMake(240, 360)];
也就是给他一个字符串说一下名字,然后从这个点到那个点,两点之间即为自己定义的边界。然而这条线是看不到样子的,不过自己也可以画一个上去。比如说下面那样。
UICollisionBehavior还可以设置Delegate,让方块碰撞的时候发送回调一个方法,这时你就可以在碰撞的时候干点别的事情了。
比如这样:
给ViewController.m里遵守一个协议
<
UICollisionBehaviorDelegate
>
紧跟_collision设置自定义边界的后面写一行
1 [_collision setCollisionDelegate:self];
这样就可以把Delegate设置为ViewController了
然后重写写协议里的方法
1 - (void)collisionBehavior:(UICollisionBehavior *)behavior beganContactForItem:(id<UIDynamicItem>)item withBoundaryIdentifier:(id<NSCopying>)identifier atPoint:(CGPoint)p
2 {
3 UIView *v = (UIView *)item;
4 [v setBackgroundColor:[UIColor redColor]];
5 [UIView animateWithDuration:0.3 animations:^{
6 [v setBackgroundColor:[UIColor blueColor]];
7 }];
8
9 }
上面这个方法里就实现了当方块发生碰撞的时候,就会闪一下红色。
除此之外在
UICollisionBehaviorDelegate
协议中还有几种方法
分别可以在开始,结束,按物体来分事件还是按边界来分事件等。
UICollisionBehavior
里还可以设置碰撞模式,有一个名字叫CollisionMode的属性就可以修改这个属性,CollisionMode有三个枚举可以选择,分别是:
- UICollisionBehaviorModeItems
- UICollisionBehaviorModeEverything
- UICollisionBehaviorModeBoundaries
其实也就是你可以选择跟什么东西发生碰撞,比如选择
UICollisionBehaviorModeItems的时候,就表示你指向跟另外一个物体发生碰撞,而不跟边界碰撞。
碰撞说得差不多了,我们来研究点别的。
比如
UIAttachmentBehavior,按字面意思来理解应该是一种吸附行为,那我们再新建另一个方块来试试这个Behavior。
1 UIView *testView2 = [[UIView alloc] initWithFrame:CGRectMake(110, 170, 100, 100)];
2 [testView2 setBackgroundColor:[UIColor greenColor]];
3 [self.view addSubview:testView2];
把它放到第一个方块的下面,颜色为绿色。
然后在_gravity初始化的时候也把第二块方块加进里面,不然第二块方块就不会往下掉了。
1 _gravity = [[UIGravityBehavior alloc] initWithItems:@[testView,testView2]];
这个时候运行程序,发现第一块方块还留在我们之前定义的边界上,而第二块方块就掉出边界消失了,这是因为我们没有把第二块方块加进_collision里面,不过这我们不管,这正好用来研究
UIAttachmentBehavior。
在startAnimator方法最后加上这两行代码,初始化一下_attachment,并加入两个方块,这个初始化表示两个方块吸附在一起。
1 _attachment = [[UIAttachmentBehavior alloc] initWithItem:testView attachedToItem:testView2];
2
3 [_animator addBehavior:_attachment];
然后运行程序,发现第一个方块还是像以前那样留在边界上,但第二块方块就在边界下面,两个方块好像中间有跟绳子连在一起那样,这就是
UIAttachmentBehavior的作用了。
同样的,
UIAttachmentBehavior也提供了好几种属性来做出各种效果,分别是:
UIDynamicItemBehavior
这个行为提供了自转和直线的运动行为。实现一个实例来说明一下,首先把之前那些奇奇怪怪的Behavior都清除掉,只留下_collision来实现一个边界就好。
声明一个
UIDynamicItemBehavior实例:
1 UIDynamicItemBehavior *_dynamicItem;
然后添加下面的代码:
1 _dynamicItem = [[UIDynamicItemBehavior alloc] initWithItems:@[testView]];
2 [_dynamicItem addAngularVelocity:5 forItem:testView];
3 [_animator addBehavior:_dynamicItem];
这个时候,方块会自己按顺时针方向自转,然后慢慢停下来,也就是给他一个初速度自转,接着就在摩擦之类的作用下停下来了。
把上面第二行代码去掉,换成如下代码,就能实现另一个行为,直线运动,而LinearVelocity就是同样要给他一个x,y的初速度,然后它就会根据向量的叠加方向直线运动。
1 [_dynamicItem addLinearVelocity:CGPointMake(500, 100) forItem:testView];
在这两个行为的基础下,还有几个属性来配合这两个行为:
UIPushBehavior
还有一个PushBehavior,这个推也很好理解,我们直接来看代码,把代码中除了关于方块,_animator,_collision的东西都删掉,在最后添加如下代码:
1 _push = [[UIPushBehavior alloc] initWithItems:@[testView] mode:UIPushBehaviorModeInstantaneous];
2 [_push setAngle:1];
3 [_push setMagnitude:0.2];
4 [_animator addBehavior:_push];
再运行程序,就可以看见方块仿佛被推了一下,然后就动了起来,代码实现也很简单,初始化_push,然后给他方块,还有设置一个模式,这里模式分别有
UIPushBehaviorModeInstantaneous以及
mode:UIPushBehaviorModeContinuous,两个的区别就是一个是推一下,一个是连续推。
初始化完之后,就给他设置角度和初速度就好了,简单粗暴。
UISnapBehavior
最后还有一个
UISnapBehavior,其实这个更简单,按照惯例直接上代码
1 _snap = [[UISnapBehavior alloc] initWithItem:testView snapToPoint:CGPointMake(400, 400)];
2 [_animator addBehavior:_snap];
运行程序,就会发现方块突然好像被钉在某处那样,没错,这就是
UISnapBehavior的效果。无需多解释。
它也只有一个属性damping,直接加上这一行:
就会发现方块移动变慢了,这就是一个阻尼属性。
研究下来,其实实现也很简单的,这系列API真的帮助我们简单地实现这些挺好玩的效果,材料就在这里,炒成什么菜就看大家了!