原型从网上找的,动效使用了CAAnimation和UIDynamic物理引擎。 gitHub :https://github.com/BearRan/FlowMenuAnimation
大致步骤如下:
接着点击Sketch右下角的倒出按钮,格式选为SVG格式
将生成的SVG文件拖入到codePaint中,拖入成功后会直接看到如下界面
看到代码路径后可以整段copy出来,当然,我建议把所有的点抽离出来,方便做适配
代码绘制凹槽动画
demo的AppDelegate.h中有以下这些开关,可以自己调配,方便观察
单个滚珠动效演示,这样看应该比较容易理解。其实我是盖了一个新的图层专门用来做滚珠动效的。
控制点就是用普通的UIAniamtion实现的,在动画之行的过程中,通过CADisplayLink实时观察Point的PresentLayer的position来不停的重绘贝塞尔曲线。
2.滚珠动画该分解成几个步骤
主要分为以下步骤
阶段一:滚珠一起滚落下来时到最高点的阶段;
阶段二:滚珠滚落到最高点后回流的的阶段;
阶段三:滚珠消失阶段;
3.如何分解滚珠的物理效果
UIDynamic有以下物理效果
UIGravityBehavior:重力行为
| #pragma mark 重力行为- (UIGravityBehavior *)addGravityBehavior:(id <UIDynamicItem>)item{ UIGravityBehavior *gravityBehavior = [[UIGravityBehavior alloc] init]; [gravityBehavior addItem:item]; [_animator addBehavior:gravityBehavior]; return gravityBehavior;}
|
UICollisionBehavior:碰撞行为
适用于:UIView和父类view的边界碰撞,以及和其他UIView碰撞
这里可以配合重力行为来设定小球的运动路径
#pragma mark 碰撞行为- (UICollisionBehavior *)addCollisionBehavior:(id <UIDynamicItem>)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 <UIDynamicItem>)item attachToItem:(id <UIDynamicItem>)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 <UIDynamicItem>)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;} // 最后一个球向左pushUIPushBehavior *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地址:
作者:熊熊xr
原文地址:http://code4app.com/forum.php?mod=viewthread&tid=9264&extra=page%3D62%26filter%3Dsortid%26orderby%3Ddateline%26sortid%3D1
滚珠菜单动效-b