drawRect重绘问题求助:返回页面后圆形计时器未按初始状态重绘
我来帮你搞定这个问题!
问题根源分析
当你从其他页面返回时,这个CountDownTimer视图的绘制状态没有被正确重置——要么是存储进度的变量保留了上次结束时的toValue值,要么是视图重新显示时没有触发初始状态的重绘,导致drawRect用了残留的状态来绘制。
具体解决方案
下面是几种针对性的处理方式,你可以根据自己的代码结构选择:
1. 在视图生命周期中重置状态并触发重绘
给CountDownTimer类添加视图生命周期方法,确保每次视图被添加到父视图(回到当前页面时)都重置进度并重新绘制:
class CountDownTimer: UIView { // 假设你有这些状态变量 public var fromValue: CGFloat = 0.0 public var toValue: CGFloat = 1.0 private var currentProgress: CGFloat = 0.0 override func didMoveToSuperview() { super.didMoveToSuperview() // 当视图被添加到父视图时(返回页面时会触发),重置进度 if superview != nil { currentProgress = fromValue setNeedsDisplay() // 强制触发drawRect重绘 } } override func draw(_ rect: CGRect) { // 你的绘制逻辑,必须完全依赖currentProgress变量 // 示例绘制代码: guard let context = UIGraphicsGetCurrentContext() else { return } let center = CGPoint(x: rect.midX, y: rect.midY) let radius = min(rect.width, rect.height)/2 - 5 // 绘制背景圆 let bgPath = UIBezierPath(arcCenter: center, radius: radius, startAngle: 0, endAngle: 2 * .pi, clockwise: true) UIColor.lightGray.setStroke() bgPath.lineWidth = 3 bgPath.stroke() // 绘制进度圆 let progressAngle = 2 * .pi * currentProgress let progressPath = UIBezierPath(arcCenter: center, radius: radius, startAngle: -.pi/2, endAngle: -.pi/2 + progressAngle, clockwise: true) UIColor.red.setStroke() progressPath.lineWidth = 3 progressPath.stroke() } }
2. 在ViewController层面控制重置
如果你的CountDownTimer是某个ViewController的子视图,也可以在ViewController的viewDidAppear方法里手动重置:
class YourViewController: UIViewController { @IBOutlet weak var countDownTimer: CountDownTimer! override func viewDidAppear(_ animated: Bool) { super.viewDidAppear(animated) // 重置进度并触发重绘 countDownTimer.currentProgress = countDownTimer.fromValue countDownTimer.setNeedsDisplay() // 如果有计时器逻辑,这里也要重启计时器 // countDownTimer.startTimer() } }
3. 管理计时器的生命周期(如果用了计时器)
如果你的倒计时是用CADisplayLink或Timer实现的,一定要在视图消失时停止计时器,显示时重启并重置进度:
class CountDownTimer: UIView { private var displayLink: CADisplayLink? public var fromValue: CGFloat = 0.0 public var toValue: CGFloat = 1.0 private var currentProgress: CGFloat = 0.0 func startTimer() { stopTimer() currentProgress = fromValue // 重置初始值 displayLink = CADisplayLink(target: self, selector: #selector(updateProgress)) displayLink?.add(to: .current, forMode: .common) } func stopTimer() { displayLink?.invalidate() displayLink = nil } @objc private func updateProgress() { // 示例进度更新逻辑,根据你的需求调整 currentProgress += 0.01 if currentProgress >= toValue { stopTimer() } setNeedsDisplay() } override func didMoveToSuperview() { super.didMoveToSuperview() if superview != nil { startTimer() // 视图显示时启动计时器 } else { stopTimer() // 视图被移除时停止计时器 } } }
核心要点
- 确保所有和绘制相关的状态变量(比如
currentProgress)在视图每次显示时都被重置为fromValue - 每次重置状态后必须调用
setNeedsDisplay()触发drawRect重绘 - 如果有计时器逻辑,一定要在视图消失时停止,避免后台继续运行导致状态异常
内容的提问来源于stack exchange,提问作者FS.O6
相关产品推荐
相关产品推荐

