iOS7 UIKit Dynamics

iOS7 Day-by-Day : : Day 0 : : UIKit Dynamics

原文:http://www.shinobicontrols.com/blog/posts/2013/09/19/ios7-day-by-day-day-0-uikit-dynamics


随着iOS7的推出,苹果已经明确表现出他们正在推进设备与真实世界的交互。新推出的API之一便是UIKit Dynamics,一个位于UIKit层的2维物理引擎。在这一系列的博客的第0天我们将了解一下UIKit Dynamics,并且建造一个牛顿物理学中的单摆模型。


这一系列文章的代码在github的软件仓库中 -github.com/ShinobiControls/iOS7-day-by-day


物理宇宙


为了模型化真实世界的物体,我们使用UIDynamicBehavior的子类来给符合UIDynamicItem协议的对象添加行为。这些行为的例子包括像重力、碰撞、弹力等概念。尽管你可以自己创建符合UIDynamicItem协议的对象,但重要地是UIView已经这样做了。这些UIDynamicBehavior对象可以组合在一起生成一个行为对象,这个对象包含了所给的一个或一系列对象的所有行为。


一旦给那些动态对象定义了行为,就可以将这些行为提供给一个UIDynamicAnimator对象,UIDynamicAnimator就是这个物理引擎。这个UIDynamicAnimator对象便会计算当考虑到他们的行为时不同的对象之间怎样相互作用。下图展示了UIKit Dynamics世界的整体概念。

iOS7 UIKit Dynamics_第1张图片


创建一个钟摆


回想一下高中学校的场景—在牛顿物理学中学到的最简单的物体之一便是钟摆。我们先创建一个视图代表这个钟摆:


UIView *ballBearing = [[UIView alloc] initWithFrame:CGRectMake(0,0,40,40)];

ballBearing.backgroundColor = [UIColor lightGrayColor];

ballBearing.layer.cornerRadius =10;

ballBearing.layer.borderColor = [UIColor grayColor].CGColor;

ballBearing.layer.borderWidth =2;

ballBearing.center = CGPointMake(200,300);

[self.view addSubview:ballBearing];


现在我们给这个钟摆添加一些行为。我们来创建一个组合的行为来将所有的行为放在一起:


UIDynamicBehavior *behavior = [[UIDynamicBehavior alloc] init];


接下来我们开始给模型添加我们想要的行为—第一个先是重力:


UIGravityBehavior *gravity = [[UIGravityBehavior alloc] initWithItems:@[ballBearing]];

gravity.magnitude =10;

[behavior addChildBehavior:gravity];


UIGravityBehavior代表物体和地球之间的引力。它有允许你设置引力向量(例如大小和方向)的属性。此处我们增加引力的大小,保持沿着y轴的正方向。


我们需要给钟摆添加的另一个行为是附件行为—附件行为表示的是这个物体吊在哪个细绳上。


CGPoint anchor = ballBearing.center;

anchor.y -=200;

UIAttachmentBehavior *attachment = [[UIAttachmentBehavior alloc] initWithItem:ballBearing attachedToAnchor:anchor];

[behavior addChildBehavior:attachment];


UIAttachmentBehavior实例对象使一个物体固定在一个锚点上或另一个物体上。UIAttachmentBehavior对象有能够控制依附着的那个细绳的行为的属性—指定它的频度、减震、长度。这些的默认值能够保证一个刚性的连接,这个正是我们想要给钟摆设置的。


现在已经给钟摆指定了行为,我们可以再创建一个物理引擎来管理这些。这个引擎定义为一个变量UIDynamicAnimator *_animator;


animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];

[_animator addBehavior:behavior];


UIDynamicAnimator代表了这个物体引擎,它被用来模型化动态系统。此处我们创建了它,并指定了参考视图(这个视图用来描述空间领域),并且添加我们创建的那个复合行为。


做好以上这些内容实际上就可以创建一个UIKit Dynamics系统了。但此时运行程序什么也不会发生。因为一开始这个系统处于平衡状态—我们要使系统不稳定以便观察一些运动。


手势代表了行为


我们需要给这个钟摆添加一个手势使用户能够摆弄这个它。


UIPanGestureRecognizer *gesture = [[UIPanGestureRecognizer alloc]initWithTarget:selfaction:@selector(handleBallBearingPan:)];

[ballBearing addGestureRecognizer:gesture];


使用手势的目的是使钟摆持续的获得力量:


(void)handleBallBearingPan:(UIPanGestureRecognizer *)recognizer

{

   //开始手势滑动时就会产生拖拽的力量

    if (recognizer.state == UIGestureRecognizerStateBegan) {

        if(_userDragBehavior) {

            [_animator removeBehavior:_userDragBehavior];

        }

        _userDragBehavior = [[UIPushBehavior alloc] initWithItems:@[recognizer.view] mode:UIPushBehaviorModeContinuous];

        [_animator addBehavior:_userDragBehavior];

    }


   //使力量和手势移动的距离成比例


    _userDragBehavior.pushDirection = CGVectorMake([recognizer translationInView:self].x / 10.f,0);

 // 当手势滑动结束时取消小球的’let-go’行为

    if (recognizer.state == UIGestureRecognizerStateEnded) {

        [_animator removeBehavior:_userDragBehavior];

        _userDragBehavior =nil;

    }

}



UIPushBehavior表示给物体施加一个简单的线性力。我们使用回调将力施加于钟摆,回调使施加力的操作与钟摆分离开。在手势开始时创建一个UIPushBehavior变量,记得要将它添加到动态动画器中(注:前面创建的引擎)。再设置力的大小与水平移动距离成正比。为了让钟摆摆动在手势滑动结束时移除推行为。


结合多个钟摆


一个牛顿支架摆放着相同的钟摆,这样钟摆直接就能碰撞。

为了使用UIKit Dynamics重新创建这个牛顿支架,我们需要先创建多个钟摆—每个都和上面的创建步骤一样。他们直接要有一些空隙,这样才不是总是碰撞(看一下示例代码了解详情)。


还需要增加一个新的行为,它描述了单摆之间怎样碰撞。现在使用一个变量来存储钟摆NSArray *_ballBearings;:


UICollisionBehavior *collision = [[UICollisionBehavior alloc] initWithObjects:_ballBearings];

[behavior addChildBehavior:collision];


此处用到了碰撞行为和一系列系统被模型化的物体。碰撞行为也能够被用来模型化物体碰撞边界,例如视图边界和贝塞尔曲线边界。


如果现在运行程序并试图移动一个钟摆,你会发现这个支架并没有表现的和你预想的一样。这是因为当前的碰撞不是弹性的。还需要添加一个特殊的动态行为来指定各种共享的属性:


UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:_ballBearings];

// Elasticity governs the efficiency of the collisions

itemBehavior.elasticity =1.0;

itemBehavior.allowsRotation =NO;

itemBehavior.resistance =0.5;

[behavior addChildBehavior:itemBehavior];


使用UIDynamicItemBehavior来指定碰撞弹性,还有一些其他的属性,例如阻力(类似于空气阻力)和旋转。如果允许旋转的话,可以指定角阻力。UIDynamicItemBehavior也可以设置线速度和角速度,这在匹配手势的速度时很有用。


现在运行程序将会显示一个牛顿支架,它的行为正是你在真实世界期望的。作为扩展你可以研究拖拽钟摆的细绳和滚珠轴承。


你可能感兴趣的:(iOS7 UIKit Dynamics)