iOS开发UIKit动力学——UIKit Dynamics

     UIKit Dynamics其实就是UIKit对一些物理学行为仿真的封装。使用UIKit动力学对常用的iOS动画CoreAnimation、UIView animations进行补充。

我们应该了解的基本概念:

  • UIDynamicItem:用来描述一个力学物体的状态,其实就是实现了UIDynamicItem委托的对象。从iOS 7.0开始,UIView和UICollectionViewLayoutAttributes默认实现该协议。如果自定义的对象实现了该协议,即可通过Dynamic Animator实现物理仿真。
  • UIDynamicBehavior:动力行为的描述,用来指定UIDynamicItem应该如何运动,即定义适用的物理规则。一般我们使用这个类的子类对象来对一组UIDynamicItem应该遵守的行为规则进行描述。
  • UIDynamicAnimator:动画的播放者,动力行为(UIDynamicBehavior)的容器,添加到容器内的行为将发挥作用。
  • ReferenceView:等同于力学参考系,只有当想要添加力学行为的UIView是ReferenceView的子view时,动力UI才发生作用。

     UIKit动力学行为包括:UIGravityBehavior(重力),UICollisionBehavior(碰撞),UIAttachmentBehavior(吸附),UISnapBehavior(捕捉),UIPushBehavior(推动)以及辅助行为UIDynamicItemBehavior。所有的UIDynamicBehavior都是可以独立作用,同时也遵守力的合成。也就是说,组合使用行为可以实现一些较复杂的效果。

1. UIDynamicItemBehavior:辅助的行为,用来设置运动学元素参与物理仿真过程中的参数,如:弹性系数、摩擦系数、密度、阻力、角阻力以及是否允许旋转等。

elasticity(弹性系数):决定了碰撞的弹性程度,比如碰撞时物体的弹性

friction(摩擦系数) :决定了沿接触面滑动时的摩擦力大小

density(密度): 跟size结合使用,计算物体的总质量。质量越大,物体加速或减速就越困难

resistance(阻力):决定线性移动的阻力大小,与摩擦系数不同,摩擦系数只作用于滑动运动

angularResistance(角阻力) :决定旋转运动时的阻力大小

allowsRotation(允许旋转):这个属性很有意思,它在真实的物理世界没有对应的模型。设置这个属性为 NO 物体就完全不会转动,而无论施加多大的转动力

2. UIGravityBehavior:重力行为

// 实例化重力行为
        UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:self.imageViews];
        
        // 将重力行为添加至仿真者
        [self.animator addBehavior:gravityBehavior];


3. UICollisionBehavior:碰撞行为

// 移除所有动力学行为
         [self.animator removeAllBehaviors];
        
        // 添加重力行为
        UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:self.imageViews];
        [self.animator addBehavior:gravityBehavior];
        
        // 初始化碰撞行为
        UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:self.imageViews];
        //
        collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
        
        /* 设置碰撞模式
         UICollisionBehaviorModeItems            与其他对象碰撞
         UICollisionBehaviorModeBoundaries       与设置的边框碰撞
         UICollisionBehaviorModeEverything       上边两种情况都碰撞
         */
        collisionBehavior.collisionMode = UICollisionBehaviorModeEverything;
        
        // 设置碰撞行为代理
        collisionBehavior.collisionDelegate = self;
        [self.animator addBehavior:collisionBehavior];
        
        // 添加附属行为
        UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:self.imageViews];
        
        // 弹力系数 0 ~ 1
        itemBehavior.elasticity = 0.8;
        [self.animator addBehavior:itemBehavior];

3.  UIAttachmentBehavior:附着行为

 1. 附着行为描述一个视图与一个锚点或者另一个视图相连接的情况
 2. 附着行为描述的是两点之间的连接情况,可以模拟刚性或者弹性连接

 3.在多个物体间设定多个UIAttachmentBehavior,可以模拟多物体连接

 4. 属性:

 attachedBehaviorType:连接类型(连接到锚点或视图)

 items:连接视图数组

 anchorPoint:连接锚点

 length:距离连接锚点的距离

 只要设置了以下两个属性,即为弹性连接

 damping:振幅大小

 frequency:振动频率

- (void)performAttachmentBehavior
{
    if (self.animator == nil) {
        self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    } else {
        [self.animator removeAllBehaviors];
    }
    
    for (int i = 0; i < self.imageViews.count; i++) {
        CGRect frame = CGRectMake(20 + i * 60, 400, 50, 50);
        [self.imageViews[i] setFrame:frame];
    }
    
    UIPanGestureRecognizer *panGestureRecognizer = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(attachmentBechaviorPanGesture:)];
    [self.view addGestureRecognizer:panGestureRecognizer];
    
    for (int i = 0; i < self.imageViews.count - 1; i++) {
        UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:self.imageViews[i] attachedToItem:self.imageViews[i + 1]];
        attachmentBehavior.frequency = 0.8;
        attachmentBehavior.damping = 0.5;
        attachmentBehavior.length = 50;
        [self.animator addBehavior:attachmentBehavior];
    }
 }

- (void)attachmentBechaviorPanGesture:(UIPanGestureRecognizer *)gesture
{
    CGPoint location = [gesture locationInView:self.view];
    
    if (gesture.state == UIGestureRecognizerStateBegan) {
//       [(UIImageView *) self.imageViews[0] setCenter:loction];
        [self initDragBehaviourWithAnchorPosition:location];
        [self.animator addBehavior:self.dragBehavior];
    }else if (gesture.state == UIGestureRecognizerStateChanged) {
        [self.dragBehavior setAnchorPoint:location];
    } else if (gesture.state == UIGestureRecognizerStateEnded){
        // 移除所有动力学行为
         [self.animator removeAllBehaviors];
        
        // 添加重力行为
        UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:self.imageViews];
        [self.animator addBehavior:gravityBehavior];
        
        // 初始化碰撞行为
        UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] initWithItems:self.imageViews];
        //
        collisionBehavior.translatesReferenceBoundsIntoBoundary = YES;
        
        /* 设置碰撞模式
         UICollisionBehaviorModeItems            与其他对象碰撞
         UICollisionBehaviorModeBoundaries       与设置的边框碰撞
         UICollisionBehaviorModeEverything       上边两种情况都碰撞
         */
        collisionBehavior.collisionMode = UICollisionBehaviorModeEverything;
        
        // 设置碰撞行为代理
        collisionBehavior.collisionDelegate = self;
        [self.animator addBehavior:collisionBehavior];
        
        // 添加附属行为
        UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:self.imageViews];
        
        // 弹力系数 0 ~ 1
        itemBehavior.elasticity = 0.8;
        [self.animator addBehavior:itemBehavior];
    }
}


- (void)initDragBehaviourWithAnchorPosition:(CGPoint)anchorPosition {
    UIView *obj = self.imageViews[0];
    self.dragBehavior = [[UIAttachmentBehavior alloc] initWithItem:obj attachedToAnchor:anchorPosition];
    double length = [self getDistanceBetweenAnchor:anchorPosition andBallView:obj];
    [self.dragBehavior setLength:((CGFloat) length  < 20) ? (CGFloat) length : 20];
}

- (double)getDistanceBetweenAnchor:(CGPoint)anchor andBallView:(UIView *)ballView {
    return sqrt(pow((anchor.x - ballView.center.x), 2.0) + pow((anchor.y - ballView.center.y), 2.0));
}

4. UISnapBehavior:捕捉行为

1.捕捉行为 可以将视图通过动画吸附到某个点上
2. 初始化设定一下 UISnapBehavior initWithItem:snapToPoint: 即可
3. 属性:

damping:振幅大小,默认为0.5f

 self.animator = [[UIDynamicAnimator alloc] initWithReferenceView:self.view];
    UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] initWithItems:@[view]];
    [self.animator addBehavior:gravityBehavior];
    
    UISnapBehavior *snapBehavior = [[UISnapBehavior alloc] initWithItem:view snapToPoint:self.view.center];
    snapBehavior.damping = 0.2;
    [self.animator addBehavior:snapBehavior];

5. 推动行为:UIPushBehavior

 1.  推动行为可以为一个视图施加一个作用力,该力可以是持续的,也可以是一次性的
 2.  可以设置力的大小,方向和作用点等信息
 3.  属性:
 •mode :推动类型(一次性或是持续推)
 •active :是否激活,如果是一次性推,需要激活
 •angle :推动角度
 •magnitude :推动力量

 初始化的时候有两种模式:UIPushBehaviorModeContinuous(这个模型可以忽略)

- (void)performPushBehavior
{
    if (self.centerview == nil) {
        self.centerview = [[UIView alloc] initWithFrame:CGRectMake(0, 0, 50, 150)];
        self.centerview.backgroundColor = [UIColor greenColor];
        self.centerview.center = self.view.center;
        [self.view addSubview:self.centerview];
    }
   

    UIPanGestureRecognizer *panGesture = [[UIPanGestureRecognizer alloc] initWithTarget:self action:@selector(panGestureAction:)];
    [self.view addGestureRecognizer:panGesture];
}

- (void)panGestureAction:(UIPanGestureRecognizer *) recongnizer
{
    CGPoint firsPoint = CGPointZero;
    CGPoint endPoint = CGPointZero;
    
    CGPoint location = [recongnizer locationInView:self.view];
    
    if (recongnizer.state == UIGestureRecognizerStateBegan) {
        firsPoint = location;
    } else if (recongnizer.state == UIGestureRecognizerStateEnded) {
        endPoint = location;;
        
        UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[self.centerview] mode:UIPushBehaviorModeInstantaneous
                                        ];
        
        pushBehavior.active = YES;
        CGFloat distance = sqrtf(powf((endPoint.x - firsPoint.x), 2) + powf(endPoint.y - firsPoint.y, 2));
        CGFloat angle = atan2f(endPoint.y - firsPoint.y, endPoint.x - firsPoint.x);
        pushBehavior.angle = angle;
        
        pushBehavior.magnitude = distance/100;
        //    pushBehavior.pushDirection = CGVectorMake(1, 0);
        //    [pushBehavior setPushDirection:CGVectorMake([recongnizer velocityInView:self.view].x /100.f, 0)];
        [self.animator addBehavior:pushBehavior];
      

    } else if (recongnizer.state == UIGestureRecognizerStateEnded) {
    
    }
}

总结:
1. 实例化UIKit Dynamics所有相关的类都是通过allco,init创建的,没有提供类方法。

2. 使用UIKit Dynamics的步凑:

1. 实例化动画的仿真者UIDynamicAnimator,并设置参考视图用于物理仿真。参考视图表示要仿真的范围。 

注意:UIDynamicAnimator类的实例需作为成员变量,防止方法执行完后被销毁,每个对象拥有一个UIDynamicAnimator管理其动力学行为。

2. 实例化要仿真的行为,并指定哪些对象遵守该行为。

3. 将要仿真的行为添加至仿真者UIDynamicAnimator,仿真立即开始。

参考文章:

http://blog.csdn.net/gandam19/article/details/19498315

http://www.th7.cn/Program/IOS/201312/166139.shtml

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