IOS使用progssview仿滴滴打车圆形计时

实现类似在微信中使用的滴滴打车的progressview,实现效果如图

//
// CCProgressView.h
// HurricaneConsumer
//
// Created by wangcong on 15-3-25.
// Copyright (c) 2015年 WangCong. All rights reserved.
//

#import <UIKit/UIKit.h>
#import <QuartzCore/QuartzCore.h>

/**
 * 动画开始
 */
typedef void(^block_progress_start)();

/**
 * 动画正在进行
 * @param NSTimeInterval
 */
typedef void(^block_progress_animing)(NSTimeInterval);

/**
 * 动画结束
 */
typedef void(^block_progress_stop)();

@interface CCProgressView : UIView
{
  NSTimeInterval _animationTime;
}

@property (nonatomic, strong) UILabel *centerLabel;    // 中心Label

@property (nonatomic, copy) block_progress_start start;   // 动画开始回调
@property (nonatomic, copy) block_progress_animing animing; // 动画进行
@property (nonatomic, copy) block_progress_stop stop;    // 动画结束回调

- (void) setAnimationTime:(NSTimeInterval)animationTime;

- (void)startAnimation;

- (void)stopAnimation;

@end

//
// CCProgressView.m
// HurricaneConsumer
//
// Created by wangcong on 15-3-25.
// Copyright (c) 2015年 WangCong. All rights reserved.
//

#import "CCProgressView.h"

#define kProgressThumbWh 30

// 计时器间隔时长
#define kAnimTimeInterval 0.1

/**
 * 圆圈layer上旋转的layer
 */
@interface CCProgressThumb : CALayer
{
  NSTimeInterval _animationTime;
}

@property (assign, nonatomic) double startAngle;
@property (nonatomic, strong) UILabel *timeLabel;      // 显示时间Label

@end

@implementation CCProgressThumb

- (instancetype)init
{
  if ((self = [super init])) {
    [self setupLayer];
  }
  return self;
}

- (void)layoutSublayers
{
  _timeLabel.frame = self.bounds;

  [_timeLabel sizeToFit];
  _timeLabel.center = CGPointMake(CGRectGetMidX(self.bounds) - _timeLabel.frame.origin.x,
                  CGRectGetMidY(self.bounds) - _timeLabel.frame.origin.y);
}

- (void)setupLayer
{
  // 绘制圆
  UIGraphicsBeginImageContext(CGSizeMake(kProgressThumbWh, kProgressThumbWh));
  CGContextRef ctx = UIGraphicsGetCurrentContext();
  CGContextSetLineWidth(ctx, 1);
  CGContextSetFillColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
  CGContextSetStrokeColorWithColor(ctx, [UIColor lightGrayColor].CGColor);
  CGContextAddEllipseInRect(ctx, CGRectMake(1, 1, kProgressThumbWh - 2, kProgressThumbWh - 2));
  CGContextDrawPath(ctx, kCGPathFillStroke);
  UIImage *circle = UIGraphicsGetImageFromCurrentImageContext();
  UIGraphicsEndImageContext();

  UIImageView *circleView = [[UIImageView alloc] initWithImage:circle];
  circleView.frame = CGRectMake(0, 0, kProgressThumbWh, kProgressThumbWh);
  circleView.image = circle;
  [self addSublayer:circleView.layer];

  _timeLabel = [[UILabel alloc] initWithFrame:self.bounds];
  _timeLabel.textColor = [UIColor redColor];
  _timeLabel.font = [UIFont systemFontOfSize:10];
  _timeLabel.textAlignment = NSTextAlignmentCenter;
  _timeLabel.text = @"00:00";
  [self addSublayer:_timeLabel.layer];

  _startAngle = - M_PI / 2;
}

- (void)setAnimationTime:(NSTimeInterval)animationTime
{
  _animationTime = animationTime;
}

- (double)calculatePercent:(NSTimeInterval)fromTime toTime:(NSTimeInterval)toTime
{
  double progress = 0.0f;
  if ((toTime > 0) && (fromTime > 0)) {
    progress = fromTime / toTime;
    if ((progress * 100) > 100) {
      progress = 1.0f;
    }
  }
  return progress;
}

- (void)startAnimation
{
  CAKeyframeAnimation *pathAnimation = [CAKeyframeAnimation animationWithKeyPath:@"position"];
  pathAnimation.calculationMode = kCAAnimationPaced;
  pathAnimation.fillMode = kCAFillModeForwards;
  pathAnimation.removedOnCompletion = YES;
  pathAnimation.duration = kAnimTimeInterval;
  pathAnimation.repeatCount = 0;
  pathAnimation.autoreverses = YES;

  CGMutablePathRef arcPath = CGPathCreateMutable();
  CGPathAddPath(arcPath, NULL, [self bezierPathFromParentLayerArcCenter]);
  pathAnimation.path = arcPath;
  CGPathRelease(arcPath);
  [self addAnimation:pathAnimation forKey:@"position"];
}

/**
 * 根据父Layer获取到一个移动路径
 * @return
 */
- (CGPathRef)bezierPathFromParentLayerArcCenter
{
  CGFloat centerX = CGRectGetWidth(self.superlayer.frame) / 2.0;
  CGFloat centerY = CGRectGetHeight(self.superlayer.frame) / 2.0;
  double tmpStartAngle = _startAngle;
  _startAngle = _startAngle + (2 * M_PI) * kAnimTimeInterval / _animateTime;
  return [UIBezierPath bezierPathWithArcCenter:CGPointMake(centerX, centerY)
                     radius:centerX
                   startAngle:tmpStartAngle
                    endAngle:_startAngle
                    clockwise:YES].CGPath;
}

- (void)stopAnimation
{
  [self removeAllAnimations];
}

- (void)dealloc
{
  [[NSNotificationCenter defaultCenter] removeObserver:self];
}

@end

/**
 * 圆圈layer
 */
@interface CCProgress : CAShapeLayer
{
  NSTimeInterval _animationTime;
}

@property (assign, nonatomic) double initialProgress;
@property (nonatomic) NSTimeInterval elapsedTime;                   //已使用时间
@property (assign, nonatomic) double percent;
@property (nonatomic, strong) UIColor *circleColor;
@property (nonatomic, strong) CAShapeLayer *progress;
@property (nonatomic, strong) CCProgressThumb *thumb;
@property (nonatomic, assign) CGRect frame;

@end

@implementation CCProgress

- (instancetype) init
{
  if ((self = [super init])) {
    [self setupLayer];
  }
  return self;
}

- (void)layoutSublayers
{
  self.path = [self bezierPathWithArcCenter];
  self.progress.path = self.path;

  self.thumb.frame = CGRectMake((320 - kProgressThumbWh) / 2.0f, 180, kProgressThumbWh, kProgressThumbWh);
  [super layoutSublayers];
}

- (void)setupLayer
{
  // 绘制圆
  self.path = [self bezierPathWithArcCenter];
  self.fillColor = [UIColor clearColor].CGColor;
  self.strokeColor = [UIColor colorWithRed:0.86f green:0.86f blue:0.86f alpha:0.4f].CGColor;
  self.lineWidth = 2;

  // 添加可以变动的滚动条
  self.progress = [CAShapeLayer layer];
  self.progress.path = self.path;
  self.progress.fillColor = [UIColor clearColor].CGColor;
  self.progress.strokeColor = [UIColor whiteColor].CGColor;
  self.progress.lineWidth = 4;
  self.progress.lineCap = kCALineCapSquare;
  self.progress.lineJoin = kCALineCapSquare;
  [self addSublayer:self.progress];

  // 添加可以旋转的ThumbLayer
  self.thumb = [[CCProgressThumb alloc] init];
  [self addSublayer:self.thumb];
}

/**
 * 得到bezier曲线路劲
 * @return
 */
- (CGPathRef)bezierPathWithArcCenter
{
  CGFloat centerX = CGRectGetWidth(self.frame) / 2.0;
  CGFloat centerY = CGRectGetHeight(self.frame) / 2.0;
  return [UIBezierPath bezierPathWithArcCenter:CGPointMake(centerX, centerY)
                     radius:centerX
                   startAngle:(- M_PI / 2)
                    endAngle:(3 * M_PI / 2)
                    clockwise:YES].CGPath;
}

- (void)setCircleColor:(UIColor *)circleColor
{
  self.progress.strokeColor = circleColor.CGColor;
}

- (void)setAnimtionTime:(NSTimeInterval)animtionTime
{
  _animationTime = animtionTime;
  [self.thumb setAnimationTime:animtionTime];
}

- (void)setElapsedTime:(NSTimeInterval)elapsedTime
{
  _initialProgress = [self calculatePercent:_elapsedTime toTime:_animationTime];
  _elapsedTime = elapsedTime;

  self.progress.strokeEnd = self.percent;
  [self startAnimation];
}

- (double)percent
{
  _percent = [self calculatePercent:_elapsedTime toTime:_animationTime];
  return _percent;
}

- (double)calculatePercent:(NSTimeInterval)fromTime toTime:(NSTimeInterval)toTime
{
  double progress = 0.0f;
  if ((toTime > 0) && (fromTime > 0)) {
    progress = fromTime / toTime;
    if ((progress * 100) > 100) {
      progress = 1.0f;
    }
  }
  return progress;
}

- (void)startAnimation
{
  CABasicAnimation *pathAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
  pathAnimation.duration = kAnimTimeInterval;
  pathAnimation.fromValue = @(self.initialProgress);
  pathAnimation.toValue = @(self.percent);
  pathAnimation.removedOnCompletion = YES;
  [self.progress addAnimation:pathAnimation forKey:nil];

  [self.thumb startAnimation];
  self.thumb.timeLabel.text = [self stringFromTimeInterval:_elapsedTime shorTime:YES];
}

- (void)stopAnimation
{
  _elapsedTime = 0;
  self.progress.strokeEnd = 0.0;
  [self removeAllAnimations];
  [self.thumb stopAnimation];
}

/**
 * 时间格式转换
 * @param interval NSTimeInterval
 * @param shortTime BOOL
 * @return
 */
- (NSString *)stringFromTimeInterval:(NSTimeInterval)interval shorTime:(BOOL)shortTime
{
  NSInteger ti = (NSInteger)interval;
  NSInteger seconds = ti % 60;
  NSInteger minutes = (ti / 60) % 60;
  NSInteger hours = (ti / 3600);
  if (shortTime) {
    return [NSString stringWithFormat:@"%02ld:%02ld", (long)hours, (long)seconds];
  } else {
    return [NSString stringWithFormat:@"%02ld:%02ld:%02ld", (long)hours, (long)minutes, (long)seconds];
  }
}

@end

@interface CCProgressView ()

@property (nonatomic, strong) CCProgress *progressLayer;
@property (nonatomic, strong) NSTimer *timer;

@end

@implementation CCProgressView

- (instancetype)init
{
  if ((self = [super init])) {
    [self setupView];
  }
  return self;
}

- (instancetype)initWithFrame:(CGRect)frame
{
  if ((self = [super initWithFrame:frame])) {
    [self setupView];
  }
  return self;
}

- (void)layoutSubviews
{
  [super layoutSubviews];
  self.progressLayer.frame = self.bounds;

  [self.centerLabel sizeToFit];
  self.centerLabel.center = CGPointMake(self.center.x - self.frame.origin.x, self.center.y- self.frame.origin.y);
}

- (void)setupView
{
  self.backgroundColor = [UIColor clearColor];
  self.clipsToBounds = false;

  self.progressLayer = [[CCProgress alloc] init];
  self.progressLayer.frame = self.bounds;
  [self.layer addSublayer:self.progressLayer];

  _centerLabel = [[UILabel alloc] initWithFrame:self.bounds];
  _centerLabel.font = [UIFont systemFontOfSize:18];
  _centerLabel.textAlignment = NSTextAlignmentCenter;
  _centerLabel.textColor = [UIColor whiteColor];
  _centerLabel.text = @"已推送至 3 家";
  [self.layer addSublayer:_centerLabel.layer];
}

- (void)setAnimationTime:(NSTimeInterval)animationTime
{
  _animationTime = animationTime;
  [self.progressLayer setAnimtionTime:animationTime];
}

- (void)startAnimation
{
  if (!_timer) {
    _timer = [NSTimer timerWithTimeInterval:kAnimTimeInterval target:self selector:@selector(doTimerSchedule) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
  }
  self.progressLayer.elapsedTime = 0;
  if (_start) _start();
}

- (void)doTimerSchedule
{
  self.progressLayer.elapsedTime = self.progressLayer.elapsedTime + kAnimTimeInterval;;
  if (_animing) _animing(self.progressLayer.elapsedTime);

  if (self.progressLayer.elapsedTime >= _animationTime) {
    [self stopAnimation];
  }
}

- (void)stopAnimation
{
  if (_stop) _stop();
  if (_timer) {
    [_timer invalidate];
    _timer = nil;
  }
  [_progressLayer stopAnimation];
}

@end

使用实例
_progressView = [[CCProgressView alloc] initWithFrame:CGRectMake((APP_WIDTH - 240) / 2.0f, (APP_HEIGHT - 240) / 2.0f, 240, 240)];
  [_progressView setAnimationTime:60];
  _progressView.start = ^() {
    NSLog(@"开始");
  };
  _progressView.animing = ^ (NSTimeInterval currentTime) {
    NSLog(@"进行中");
  };
  __block id weakSelf = self;
  _progressView.stop = ^ () {
    NSLog(@"结束");
    [weakSelf dismiss];
  };
  [self addSubview:_progressView];

  [_progressView startAnimation];

以上所述就是本文的全部内容了,希望大家能够喜欢

(0)

相关推荐

  • iOS开发中Quartz2D控制圆形缩放和实现刷帧效果

    Quartz2D简要回顾 一.什么是Quartz2D Quartz 2D是⼀个二维绘图引擎,同时支持iOS和Mac系统 Quartz 2D能完成的工作: 绘制图形 : 线条\三角形\矩形\圆\弧等 绘制文字 绘制\生成图片(图像) 读取\生成PDF 截图\裁剪图片 自定义UI控件 二.Quartz2D在iOS开发中的价值 为了便于搭建美观的UI界面,iOS提供了UIKit框架,⾥⾯有各种各样的UI控件 UILabel:显⽰文字 UIImageView:显示图片 UIButton:同时显示图片和⽂

  • iOS开发之随机生成两圆之间的标准圆

    前言 相信很多社交产品中,肯定会存在寻找附近人或者附近商家的需求,类似下图,在大圆和小圆之间(橘色区域)生成一系列的随机圆,并且所有随机圆之间也不能有交集,我暂且称这种圆为标准圆. 关于这样的需要以前在做项目中有同事做过,虽然可以实现了上面的效果图,但是坐标及半径都是写死,从写死的数据随机取值,看上去是满足了,但是对于用户来说多次使用该功能时,肯定有一定的视觉疲倦,且写死的一些数据真的不好写,如果大圆或者小圆半径变化了,或者需要更多的标准圆,那怎么办呢?一脸懵逼???? 实现思路 思路一: 对于

  • iOS如何裁剪圆形头像

    本文实例为大家介绍了iOS裁剪圆形头像的详细代码,供大家参考,具体内容如下 - (void)viewDidLoad { [super viewDidLoad]; //加载图片 UIImage *image = [UIImage imageNamed:@"菲哥"]; //获取图片尺寸 CGSize size = image.size; //开启位图上下文 UIGraphicsBeginImageContextWithOptions(size, NO, 0); //创建圆形路径 UIBez

  • IOS实现圆形图片效果的两种方法

    先来看看效果图 ↓ 这个显示效果的做法有很多: 方法一: 使用两张图片, 作为边框的背景图片和中间的图片,然后使用imageView的cornerRadius来做圆, 具体代码如下: backImageView.layer.cornerRadius = backImageView.frame.size.width / 2; backImageView.layer.masksToBounds = YES; frontImageView.layer.cornerRadius = frontImage

  • 利用iOS绘制图片生成随机验证码示例代码

    先来看看效果图 实现方法 .h文件 @property (nonatomic, retain) NSArray *changeArray; @property (nonatomic, retain) NSMutableString *changeString; @property (nonatomic, retain) UILabel *codeLabel; -(void)changeCode; @end .m文件 @synthesize changeArray = _changeArray;

  • iOS实现带文字的圆形头像效果

    下面就来实现一下这种效果   圆形头像的绘制 先来看一下效果图 分析一下: 1.首先是需要画带有背景色的圆形头像 2.然后是需要画文字 3.文字是截取的字符串的一部分 4.不同的字符串,圆形的背景色是不一样的 5.对于中英文同样处理,英文的一个字符和中文的一个汉字同样算作一个字符 6.文字总是居中显示 好 有了这样几点 我们就可以开始画图了 看一下最终实现的效果图 首先 ,我们需要自定义一个view当做自定义头像,在view的drawRect方法中进行图像的绘制 @interface Round

  • 浅谈iOS中三种生成随机数方法

    ios 有如下三种随机数方法: //第一种 srand((unsigned)time(0)); //不加这句每次产生的随机数不变 int i = rand() % 5; //第二种 srandom(time(0)); int i = random() % 5; //第三种 int i = arc4random() % 5 ; 注: ① rand()和random()实际并不是一个真正的伪随机数发生器,在使用之前需要先初始化随机种子,否则每次生成的随机数一样. ② arc4random() 是一个

  • IOS使用progssview仿滴滴打车圆形计时

    实现类似在微信中使用的滴滴打车的progressview,实现效果如图 // // CCProgressView.h // HurricaneConsumer // // Created by wangcong on 15-3-25. // Copyright (c) 2015年 WangCong. All rights reserved. // #import <UIKit/UIKit.h> #import <QuartzCore/QuartzCore.h> /** * 动画开始

  • iOS开发中仿Tumblr点赞心破碎动画效果

    最近Tumblr轻博客无论是web端还是移动端,都非常受欢迎,简单调研了一下,其中动画是我感兴趣的,特此写了个仿Tumblr点赞心破碎动画: 1.首先看下效果: 2.模仿Tumblr中的效果应用如下: 原理:使用按钮点击Action增加两个事件,通过改变背景hidden和frame,切换图片,增加动画效果等: setupUI及touch Action: <span style="font-size:14px;">- (void)setupUI { // 点击的btn UIB

  • iOS 中Swift仿微信添加提示小红点功能(无数字)

    具体内容详情如下所示: 以分类的方式实现 代码 UITabBar+Extenstion.swift fileprivate let lxfFlag: Int = 666 extension UITabBar { // MARK:- 显示小红点 func showBadgOn(index itemIndex: Int, tabbarItemNums: CGFloat = 4.0) { // 移除之前的小红点 self.removeBadgeOn(index: itemIndex) // 创建小红点

  • Android自定义View仿华为圆形加载进度条

    View仿华为圆形加载进度条效果图 实现思路 可以看出该View可分为三个部分来实现 最外围的圆,该部分需要区分进度圆和底部的刻度圆,进度部分的刻度需要和底色刻度区分开来 中间显示的文字进度,需要让文字在View中居中显示 旋转的小圆点,小圆点需要模拟小球下落运动时的加速度效果,开始下落的时候慢,到最底部时最快,上来时速度再逐渐减慢 具体实现 先具体细分讲解,博客最后面给出全部源码 (1)首先为View创建自定义的xml属性 在工程的values目录下新建attrs.xml文件 <resourc

  • IOS中Swift仿QQ最新版抽屉侧滑和弹框视图

    导读 简单用Swift写了一个抽屉效果,可以直接使用并且简单; 很多软件都运了抽屉效果,比如qq的左抽屉,英雄联盟,滴滴打车,和uber等等都运用了抽屉; 效果 iOS抽屉式结构实现分析 主要是在控制器的View上添加了两个View,一个左侧leftView和一个mainView.这里我们自定义一个DrawerViewController,init(mainVC: UIViewController, leftMenuVC: UIViewController, leftWidth: CGFloat

  • 微信小程序开发之圆形菜单 仿建行圆形菜单实例

    建行APP首页有个圆形菜单.仿了个玩具出来. 功能介绍: 1.一个圆形背景.六个item菜单.中间是微信用户的头像; 2.触摸滚动.速度较小时,随手指滚动,手指抬起,滚动停止;速度较大时,随手指滚动,手指抬起,还会自动滚动一段时间; 上一张真机截图: 上代码: 1.index.js var app = getApp() Page({ data: { userInfo: {}, menuList: {},//菜单集合 animationData: {}, startPoint: {},//触摸开始

  • Android仿QQ圆形头像个性名片

    先看看效果图: 中间的圆形头像和光环波形讲解请看:http://www.jb51.net/article/96508.htm 周围的气泡布局,因为布局RatioLayout是继承自ViewGroup,所以布局layout就可以根据自己的需求来布局其子view,view.layout(int l,int t,int r,int b);用于布局子view在父ViewGroup中的位置(相对于父容器),所以在RatioLayout中计算所有子view的left,top,right,bottom.那么头

  • iOS中WKWebView仿微信加载进度条

    本文实例为大家分享了WKWebView仿微信加载进度条的具体代码,供大家参考,具体内容如下 WKWebView添加了estimatedProgress属性(double类型),我们可以利用该属性来设置UIProgressView github代码仓库上存放的Demo 为页面添加UIProgressView属性 @property (nonatomic, strong) WKWebView *mywebView; @property (nonatomic, strong) UIProgressVi

随机推荐