iOS滚珠菜单动效

作者: 卟师 | 来源:发表于2016-08-31 21:58 被阅读314次

    原型从网上找的,动效使用了CAAnimation和UIDynamic物理引擎。gitHub 

    大致步骤如下:

    把效果图截取一张,拖到Sketch做背景

    新建图层,使用钢笔工具临摹背景图勾勒出路径

    注意:勾勒时可以选择非镜像的控制点,这样方便调整曲线

    接着点击Sketch右下角的倒出按钮,格式选为SVG格式

    将生成的SVG文件拖入到codePaint中,拖入成功后会直接看到如下界面

    看到代码路径后可以整段copy出来,当然,我建议把所有的点抽离出来,方便做适配

    代码绘制凹槽动画

    demo的AppDelegate.h中有以下这些开关,可以自己调配,方便观察

    单个滚珠动效演示,这样看应该比较容易理解。其实我是盖了一个新的图层专门用来做滚珠动效的。

    控制点就是用普通的UIAniamtion实现的,在动画之行的过程中,通过CADisplayLink实时观察Point的PresentLayer的position来不停的重绘贝塞尔曲线。

    2.滚珠动画该分解成几个步骤

    主要分为以下步骤

    阶段一:滚珠一起滚落下来时到最高点的阶段;

    阶段二:滚珠滚落到最高点后回流的的阶段;

    阶段三:滚珠消失阶段;

    3.如何分解滚珠的物理效果

    UIDynamic有以下物理效果
    UIGravityBehavior:重力行为
    UICollisionBehavior:碰撞行为
    UISnapBehavior:捕捉行为
    UIPushBehavior:推动行为
    UIAttachmentBehavior:附着行为
    UIDynamicItemBehavior:动力元素行为
    UIGravityBehavior:重力行为

    #pragma mark 重力行为 - (UIGravityBehavior *)addGravityBehavior:(id )item { UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] init]; [gravityBehavior addItem:item]; [_animator addBehavior:gravityBehavior]; return gravityBehavior; }

    UICollisionBehavior:碰撞行为

    适用于:UIView和父类view的边界碰撞,以及和其他UIView碰撞

    这里可以配合重力行为来设定小球的运动路径

    #pragma mark  碰撞行为
    - (UICollisionBehavior *)addCollisionBehavior:(id )item
    {
    UICollisionBehavior *collisionBehavior = [[UICollisionBehavior alloc] init];
    [collisionBehavior addItem:item];
    [collisionBehavior addBoundaryWithIdentifier:@"path" forPath:_beizerPath];
    [_animator addBehavior:collisionBehavior];
    return collisionBehavior;
    }
    

    UISnapBehavior:捕捉行为

    顾名思义,不解释

    UIPushBehavior:推动行为

    使用瞬间或持续的力并按照某一方向作用于某个UIView

    用于开始或结束时的小球推动

    #pragma mark  显现动画,第一个球向右的推力
    - (UIPushBehavior *)addPushBehavior_inFirstBtn
    {
    UIButton *tempBtn = _btnArray[0];
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[tempBtn] mode:UIPushBehaviorModeInstantaneous];
    pushBehavior.pushDirection = CGVectorMake(1, 0.3);
    pushBehavior.magnitude = 1.6;
    [_animator addBehavior:pushBehavior];
    return pushBehavior;
    }
    

    UIAttachmentBehavior:附着行为

    UIView和某个UIView的相互吸附行为

    此处用于小球见的相互吸附作用

    #pragma mark  添加球与球之间的附着行为
    - (UIAttachmentBehavior *)addAttachmentBehavior_item:(id )item attachToItem:(id )attachToItem
    {
    SpecialBtn *tempBtn = (SpecialBtn *)item;
    UIAttachmentBehavior *attachmentBehavior = [[UIAttachmentBehavior alloc] initWithItem:item attachedToItem:attachToItem];
    [attachmentBehavior setLength:tempBtn.width + 20];
    [attachmentBehavior setDamping:10.01];
    [attachmentBehavior setFrequency:1];
    [_animator addBehavior:attachmentBehavior];
    return attachmentBehavior;
    }
    

    UIDynamicItemBehavior:动力元素行为

    一些其他的物理元素,比如摩擦力,线速度阻力,角速度阻力等

    #pragma mark  动力元素行为
    - (UIDynamicItemBehavior *)addDynamicItemBehavior:(id )item
    {
    UIDynamicItemBehavior *itemBehavior = [[UIDynamicItemBehavior alloc] initWithItems:@[item]];
    itemBehavior.resistance = 0;
    itemBehavior.allowsRotation = YES;
    itemBehavior.angularResistance = 4.0;
    itemBehavior.friction = 0.8;
    [_animator addBehavior:itemBehavior];
    return itemBehavior;
    }
    

    阶段一:滚珠一起滚落下来时到最高点的阶段球与球之间的附着行为 + 重力行为+碰撞行为+ 动力元素行为+ 第一个球向右的推力#pragma mark 显现动画

    #pragma mark 显现动画
    - (void)showBtnsAnimation
    {
    _animatorStatus = kAnimatorStatus_open;
    [_animator removeAllBehaviors];
    if (showPath) {
    _pathLayer.path = _beizerPath.CGPath;
    _pathLayer.fillColor = [UIColor clearColor].CGColor;
    _pathLayer.strokeColor = [UIColor orangeColor].CGColor;
    _pathLayer.lineWidth = 2.0;
    [self.layer addSublayer:_pathLayer];
    }
    CGFloat btn_gap = [self setXX:16];
    for (int i = 0; i < [_btnArray count]; i++) {
    SpecialBtn *tempBtn = _btnArray[i];
    tempBtn.tag = i;
    [self addSubview:tempBtn];
    //  设定初始位置
    [tempBtn setX:(tempBtn.width + btn_gap) * ([_btnArray count] - 1 - i) + btn_gap];
    [tempBtn setY:-tempBtn.height];
    //  添加球与球之间的附着行为
    if (i > 0) {
    [self addAttachmentBehavior_item:_btnArray[i] attachToItem:_btnArray[i - 1]];
    }
    //  重力行为
    UIGravityBehavior *gravityBehavior = [self addGravityBehavior:tempBtn];
    if (i == [_btnArray count] - 1) {
    //  最后一个球处理重力行为
    [self dealLastBtnGravityBehavior:gravityBehavior tempBtn:tempBtn];
    }
    //  碰撞行为
    [self addCollisionBehavior:tempBtn];
    //  动力元素行为
    UIDynamicItemBehavior *itemBehavior = [self addDynamicItemBehavior:tempBtn];
    if (i == [_btnArray count] - 1) {
    //  最后一个球增加密度,以防止出现的时候,由于惯性的原因导致飞起来
    itemBehavior.density = 1.8;
    }
    }
    //  第一个球向右的推力
    [self addPushBehavior_inFirstBtn];
    }
    

    阶段二:滚珠滚落到最高点后回流的的阶段球与球之间的附着行为 + 重力行为+碰撞行为+ 动力元素行为+ 最后一个球向左pushf

    for (int i = 0; i < [_btnArray count]; i++) {
    //  添加球与球之间的附着行为
    if (i > 0) {
    UIAttachmentBehavior *attachmentBehavior = [self addAttachmentBehavior_item:_btnArray[i] attachToItem:_btnArray[i - 1]];
    [attachmentBehavior setFrequency:5];
    [attachmentBehavior setLength:tempBtn.width + 5];
    }
    //  重力行为
    [self addGravityBehavior:_btnArray[i]];
    //  碰撞行为
    [self addCollisionBehavior:_btnArray[i]];
    //  动力元素行为
    UIDynamicItemBehavior *itemBehavior = [self addDynamicItemBehavior:_btnArray[i]];
    itemBehavior.angularResistance = 15.0;
    }
    //  最后一个球向左push
    UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[tempBtn] mode:UIPushBehaviorModeContinuous];
    pushBehavior.pushDirection = CGVectorMake(-1, -0.5);
    pushBehavior.magnitude = 2.3;
    [_animator addBehavior:pushBehavior];
    

    阶段三:滚珠消失阶段球与球之间的附着行为 + 重力行为+碰撞行为+ 动力元素行为+ 最后一个球向左push(和阶段二几本一致,只是推动的力大了一些)

    #pragma mark 消退动画
    - (void)closeBtnsAniamtion{
               NSLog(@"-- closeBtnsAniamtion");   
               _animatorStatus = kAnimatorStatus_close;    
               SpecialBtn *lastBtn = (SpecialBtn *)[_btnArray lastObject];    
              [_animator removeAllBehaviors];    
              for (int i = 0; i < [_btnArray count]; i++) {        
                         //  添加球与球之间的附着行为        
                        if (i > 0) {            
                                    UIAttachmentBehavior *attachmentBehavior = [self addAttachmentBehavior_item:_btnArray[i] attachToItem:_btnArray[i - 1]];                                               [attachmentBehavior setFrequency:5];           
                                     [attachmentBehavior setLength:lastBtn.width + 5];        
                         }         
                        //  重力行为        
                       UIGravityBehavior *gravityBehavior = [self addGravityBehavior:_btnArray[i]];        
                       if (i == 0) {            
                                 [self dealFirstDisappearBtnGravityBehavior:gravityBehavior tempBtn:_btnArray[i]];       
                       }        
                      //  碰撞行为        
                     [self addCollisionBehavior:_btnArray[i]];        
                       //  动力元素行为        
                     [self addDynamicItemBehavior:_btnArray[i]];    
              }    
             //  最后一个球向左push    
             UIPushBehavior *pushBehavior = [[UIPushBehavior alloc] initWithItems:@[lastBtn] mode:UIPushBehaviorModeContinuous];                          
             pushBehavior.pushDirection = CGVectorMake(-1, -0.5);          
             pushBehavior.magnitude = 10.0;    
           [_animator addBehavior:pushBehavior];
    }
    

    demo地址:https://yunpan.cn/cM5dC6Q8WmwSn 

    作者:熊熊xr

    原文地址:http://code4app.com/forum.php?mod=viewthread&tid=9264&extra=page%3D62%26filter%3Dsortid%26orderby%3Ddateline%26sortid%3D1 

    长按关注:

    QQ群:427763454

    欢迎你的投稿,展示的你的技术文章:812920365@qq.com

    相关文章

      网友评论

        本文标题:iOS滚珠菜单动效

        本文链接:https://www.haomeiwen.com/subject/gflcettx.html