Swift:如何设置CAShapeLayer的进度值并实现每秒进度+1的效果
这个需求完全可以实现,基于你已有的CAShapeLayer圆形进度条实现,仅需少量调整即可达到每秒跳跃固定数值的效果。
实现逻辑
你要的无平滑过渡的跳跃进度效果,核心是禁用CAShapeLayer修改strokeEnd属性时的默认隐式动画,再配合定时器每秒更新一次进度值即可。
具体实现步骤
- 第一步:定义所需属性,包含当前进度值、已创建的CAShapeLayer实例、定时器实例
- 第二步:创建每秒触发的定时器,每次触发时将进度值+1
- 第三步:更新进度时关闭隐式动画,直接给strokeEnd赋值,即可实现无过渡的跳跃效果
代码示例
Swift 版本
// 声明属性 private var currentProgress: Int = 0 private let progressLayer = CAShapeLayer() private var progressTimer: Timer? // 启动进度更新定时器 private func startProgressUpdate() { // 按需设置最大进度,这里以100为例 let maxProgress: CGFloat = 100 progressTimer = Timer.scheduledTimer(withTimeInterval: 1, repeats: true) { [weak self] _ in guard let self = self, self.currentProgress < Int(maxProgress) else { self?.progressTimer?.invalidate() self?.progressTimer = nil return } self.currentProgress += 1 // 转换为CAShapeLayer可用的0~1区间值 let strokeEnd = CGFloat(self.currentProgress) / maxProgress // 关闭隐式动画,实现跳跃效果 CATransaction.begin() CATransaction.setDisableActions(true) self.progressLayer.strokeEnd = strokeEnd CATransaction.commit() } // 加入common runloop模式,避免滑动ScrollView时定时器暂停 RunLoop.current.add(progressTimer!, forMode: .common) } // 页面销毁时记得销毁定时器 deinit { progressTimer?.invalidate() }
Objective-C 版本
// 声明属性 @property (nonatomic, assign) NSInteger currentProgress; @property (nonatomic, strong) CAShapeLayer *progressLayer; @property (nonatomic, strong) NSTimer *progressTimer; // 启动进度更新 - (void)startProgressUpdate { CGFloat maxProgress = 100; self.currentProgress = 0; self.progressTimer = [NSTimer scheduledTimerWithTimeInterval:1 repeats:true block:^(NSTimer * _Nonnull timer) { if (self.currentProgress >= maxProgress) { [self.progressTimer invalidate]; self.progressTimer = nil; return; } self.currentProgress += 1; CGFloat strokeEnd = self.currentProgress / maxProgress; [CATransaction begin]; [CATransaction setDisableActions:true]; self.progressLayer.strokeEnd = strokeEnd; [CATransaction commit]; }]; [[NSRunLoop currentRunLoop] addTimer:self.progressTimer forMode:NSRunLoopCommonModes]; } // 页面销毁时销毁定时器 - (void)dealloc { [self.progressTimer invalidate]; }
注意事项
- 如果你需要自定义每次跳跃的数值,只需要修改
currentProgress += 1中的增量即可 - 最大进度可以根据业务需求自由调整,只需要保证strokeEnd的最终计算结果在0~1区间即可
- 定时器必须在页面销毁时手动调用invalidate方法,否则会出现内存泄漏
内容的提问来源于stack exchange,提问作者user17243660
相关产品推荐
相关产品推荐

