iOS开发ios 开发ios框架

iOS 一个提交按钮形变动画设计思路

2016-02-22  本文已影响4511人  David_Do

最近看到一个UI设计效果图,自己尝试做了一下,代码最好还是去github上下载下来看吧:

![(K]QI(_X]8{557@Q)59GUR2.gif](http:https://img.haomeiwen.com/i1504118/622ed4419554c027.gif?imageMogr2/auto-orient/strip)

源码下载地址:https://github.com/DMDavid/SubmitView

初步设计思路

这个submit动画可以分开为3部分设计:

  1. 按钮形变部分:


    0FF8334F-87CA-4178-8109-B47920A51F70.jpg

这部分按钮逐渐缩小自身的宽度,当自身宽度与高度相等时,则停止形变。

2.圆环部分:


6E5CE458-AB61-48C8-8E09-7115030C3A40.jpg

这部分没啥好说的,现在APP上很多loading的效果,基本都是这样的。主要就是2个图层,下面图层是灰色的,上面的绿色图层作为subLayer覆盖在灰色图层上面。

3.完成部分:


CC7C6A13-C7C1-4F26-AF5E-0A112454706C.jpg

这是这个效果的最后部分,即从一个圆逐渐还原成原来按钮的大小样式。然后上面做一个图层动画,画一个“对号”。

代码实现

清楚了基本思路后,就可以着手撸代码了。
你可以全部使用图层来实现,上面效果。但正所谓条条大路通罗马,这边提供的方法可做参考,如果有更好的方法设计,欢迎与我交流。

1.第一部分设计实现:

这里我仍然使用button作为点击的submit按钮,当然你也可以使用其他方法设计。接下来创建一个label来展示文字,为什么不使用button自带的textLabel?是因为如果使用button自带的label的话,执行动画后自带label大小也在改变,不是特别方便。当然,还是那句话,你也可以封装一个button。
之后,我们的层级关系应该如下图所示:


370F910E-B93D-4BF3-903C-591013FE1B20.png

这里注意:蓝色为我们的submitView,红色为btn,浅蓝为label。
而button和label的父视图都为蓝色的submitView。

将按钮设计为圆角:

 self.submitButton.layer.cornerRadius=self.submitButton.bounds.size.height/2;
 self.submitButton.layer.masksToBounds = YES;

没什么好说的

在按钮的点击事件里面,去做一个让按钮宽度缩小的动画,使用UIView 的隐式动画,隐藏label,另外让按钮背景色逐渐变白,并给它添加边境宽度,颜色设为灰色。实现这个效果:


Paste_Image.png

按钮点击事件:

 - (void)submitBtnClick:(UIButton *)submitBtn {
    //缩小动画
    [self scaleLayerAnimtaion];

    [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        //隐藏按钮
        self.showLabel.alpha = 0;
        self.submitButton.backgroundColor = [UIColor whiteColor];
        self.submitButton.layer.borderWidth = 2;
        self.submitButton.layer.borderColor = [UIColor colorWithRed:172.0/255.0 green:172.0/255.0 blue:172.0/255.0 alpha:1].CGColor;
    
} completion:^(BOOL finished) {
        self.submitButton.hidden = YES;
        [self drawProgressLayer]; 
}];

}

//缩放动画
- (void)scaleLayerAnimtaion {
    CABasicAnimation *anima = [CABasicAnimation animation];
    anima.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseIn];
    anima.duration = 1.;
    anima.keyPath = @"bounds";
    anima.toValue = [NSValue valueWithCGRect:CGRectMake(0, 0, _originRect.size.height, _originRect.size.height)];
    anima.removedOnCompletion = NO;
    anima.fillMode = kCAFillModeForwards;
    [self.submitButton.layer addAnimation:anima forKey:nil];
}
注意: 这里UIView隐式动画的duration的时间应该和scaleLayerAnimation的duration相同,否则动画会出现不圆润的情况。

如果一切顺利,你会看到下面效果:


part1111.gif
2.第二部分设计实现:

这里我们已经完成了让按钮变成一个圆环啦。接下来,其实你也可以直接使用button的图层,在它上面创建一个绿色环形图层,执行一个动画,做出loading的效果。当然实现的方法很多,我这里使用的是让这个button隐藏,自己重新创建一个灰色图层,它的大小样式都和button形变后的效果一样,只不过隐式动画比较快,难以区分,我们在动画完成block回调里面创建这个图层。

 - (void)submitBtnClick:(UIButton *)submitBtn {
    //缩小动画
    [self scaleLayerAnimtaion];

    [UIView animateWithDuration:1.0 delay:0.0 options:UIViewAnimationOptionCurveEaseInOut animations:^{
        //隐藏按钮
        self.showLabel.alpha = 0;
        self.submitButton.backgroundColor = [UIColor whiteColor];
        self.submitButton.layer.borderWidth = 2;
        self.submitButton.layer.borderColor = [UIColor colorWithRed:172.0/255.0 green:172.0/255.0 blue:172.0/255.0 alpha:1].CGColor;
    
} completion:^(BOOL finished) {

        //mark - 在这里实现完成block后的操作!

        self.submitButton.hidden = YES;
        [self drawProgressLayer]; 
}];

}

//进度环动画
-(void) drawProgressLayer {  //方法实现:

    _viewCenter = (CGPoint){self.bounds.size.width/2, self.bounds.size.height/2};
    //1. 背景环    
    backProgressLayer = [CAShapeLayer layer];
    backProgressLayer.strokeColor = changedBgColor.CGColor;
    backProgressLayer.fillColor = [UIColor whiteColor].CGColor;
    backProgressLayer.lineCap   = kCALineCapRound;
    backProgressLayer.lineJoin  = kCALineJoinBevel;
    backProgressLayer.lineWidth = 2;

    UIBezierPath *backProgressCircle = [UIBezierPath bezierPath];
    [backProgressCircle addArcWithCenter:_viewCenter radius:self.bounds.size.height/2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
    backProgressLayer.path = backProgressCircle.CGPath;
    [self.layer addSublayer:backProgressLayer];


    //2. 圆环
    CAShapeLayer *progressLayer = [CAShapeLayer layer];
    progressLayer.strokeColor = btnColor.CGColor;
    progressLayer.fillColor = [UIColor whiteColor].CGColor;
    progressLayer.lineCap   = kCALineCapRound;
    progressLayer.lineJoin  = kCALineJoinBevel;
    progressLayer.lineWidth = 4.0;
   progressLayer.strokeEnd = 0.0;

    UIBezierPath *progressCircle = [UIBezierPath bezierPath];
    [progressCircle addArcWithCenter:_viewCenter radius:self.bounds.size.height/2 startAngle:-M_PI_2 endAngle:M_PI_2 * 3 clockwise:YES];
    progressLayer.path = progressCircle.CGPath;
    [backProgressLayer addSublayer:progressLayer];

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    pathAnimation.duration = 3.0;
    pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseOut];
pathAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
    pathAnimation.removedOnCompletion = NO;
    pathAnimation.fillMode = kCAFillModeForwards;
    [progressLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
}

如果一切OK,你会看到下面效果图:


part22222.gif
扩展:

这里画的进度控制,你可以提供参数进行控制。如,当一个progressRatio达到20%时候,让layer的bezierPath endAngle:这个参数为1/5 * (M_PI*2),或者动画的进度定死,让进度条执行帧动画先到20%,然后到60%,最后是否完成通过一个bool来控制,如果false则提示,如果true,则完成最后的环形合并。你可以自定义一个layer,提供一个方法传入progressFloat,之后你在下载回调方法里面调用layer的drawRect:inContent方法,来重绘达到效果。

 这里自己实现下载进度效果使用的是NSURLSession,了解请看源码
3.第三部分设计实现:

其实这里基本已经效果已经出来了,这里使用一个GCD延迟执行。当然你也可以使用NSTimer,CADisplayLink来实现。

Paste_Image.png

注意:这里的时间应该是和上面的CABaseAnimation动画时间一致。
按钮回复原来形状
- (void)expandLayerAnimation { //方法实现:

    [backProgressLayer removeFromSuperlayer];//移除之前图层
    [_submitButton setShowSubmitButton];//显示按钮
    [_showLabel showLabelAnimation];//执行对号动画

    //按钮扩充动画
    CABasicAnimation *anima = [CABasicAnimation animation];
    anima.duration = 1.;
    anima.keyPath = @"bounds";
    anima.toValue = [NSValue valueWithCGRect:_originRect];
    anima.removedOnCompletion = NO;
    anima.fillMode = kCAFillModeForwards;
   [self.submitButton.layer addAnimation:anima forKey:nil];

}

- (void)showLabelAnimation {
    self.text = @"";
    [self creatCompleteAnimation];
    [UIView animateWithDuration:1.0 animations:^{
    self.alpha = 1;
    }];
}

- (void)creatCompleteAnimation {
    CGPoint centerPoint = (CGPoint){self.bounds.size.width/2, self.bounds.size.height/2 + 5};
    CGFloat margin = 10;

    CAShapeLayer *completeLayer = [CAShapeLayer layer];
    completeLayer.fillColor = [UIColor clearColor].CGColor;
    completeLayer.strokeColor = [UIColor whiteColor].CGColor;
   completeLayer.lineCap   = kCALineJoinRound;
    completeLayer.lineJoin  = kCALineJoinRound;
    completeLayer.lineWidth = 4;

    UIBezierPath *completePath = [UIBezierPath bezierPath];
    [completePath moveToPoint:CGPointMake(centerPoint.x - margin, centerPoint.y)];
    [completePath addLineToPoint:CGPointMake(centerPoint.x - 5, centerPoint.y + margin - 5)];
    [completePath addLineToPoint:CGPointMake(centerPoint.x + margin, centerPoint.y - margin)];
    completeLayer.path = completePath.CGPath;

    [self.layer addSublayer:completeLayer];

    CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    pathAnimation.duration = 1.0;
    pathAnimation.timingFunction = [CAMediaTimingFunction functionWithName:kCAMediaTimingFunctionEaseInEaseOut];
    pathAnimation.fromValue = [NSNumber numberWithFloat:0.0];
    pathAnimation.toValue = [NSNumber numberWithFloat:1.0f];
    pathAnimation.removedOnCompletion = NO;
    pathAnimation.fillMode = kCAFillModeForwards;
    [completeLayer addAnimation:pathAnimation forKey:@"strokeEndAnimation"];
}

最终效果:

finishPart.gif

因为时间关系,代码和功能实现还有很多地方没有完善,这里只是希望大家互相分享能够起到共同进步的目的。欢迎指出不足,大家共同交流进步。

上一篇下一篇

猜你喜欢

热点阅读