调用计时器来更新swift上的路径



我有这个代码,它运行得很好

class CircleView: UIView {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    func degreesToRadians (number: Int) -> CGFloat {
        return CGFloat(number) * CGFloat(M_PI) / 180.0
    }
    override func drawRect(rect: CGRect) {
        let startAngle: CGFloat = degreesToRadians(0)
        let endAngle: CGFloat = degreesToRadians(270)
        let radius: CGFloat = 40.0
        let path = UIBezierPath(arcCenter: center,
            radius: radius,
            startAngle: startAngle,
            endAngle: endAngle,
            clockwise: true)

        UIColor.greenColor().setFill()
        path.addLineToPoint(center)
        path.fill()
    }
}

但正如你所看到的,这些值是动态的(硬编码的),我想根据计时器来更改值,所以我添加了一个计时器和一个更新值的函数。我的代码变成这样:

class CircleView: UIView {
    required init(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)!

    }
    let startAngle: Double = 0
    var counter = 0
    let numberOfMinutes = 60
    var path: UIBezierPath?
    var endAngle : Double {
        get {
            counter++
            return 360 - Double(360/60 * (counter))
        }
    }
    override init(frame: CGRect) {
        super.init(frame: frame)
    }
    func degreesToRadians (number: Double) -> CGFloat {
        return CGFloat(number) * CGFloat(M_PI) / 180.0
    }
    override func drawRect(rect: CGRect) {
        let startAngleRadiant: CGFloat = degreesToRadians(startAngle)
        let endAngleRadiant: CGFloat = degreesToRadians(endAngle)
        let radius: CGFloat = 40.0
        path = UIBezierPath(arcCenter: center,
            radius: radius,
            startAngle: startAngleRadiant,
            endAngle: endAngleRadiant,
            clockwise: true)
        UIColor.greenColor().setFill()
        path!.addLineToPoint(center)
        path!.fill()
        let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
        timer.fire()
    }
    func update() {
        print("counter = (counter)")
        let startAngleRadiant: CGFloat = degreesToRadians(startAngle)
        let endAngleRadiant: CGFloat = degreesToRadians(endAngle)
        let radius: CGFloat = 40.0
        path = UIBezierPath(arcCenter: center,
            radius: radius,
            startAngle: startAngleRadiant,
            endAngle: endAngleRadiant,
            clockwise: true)
        UIColor.greenColor().setFill()
        path!.addLineToPoint(center)
        path!.fill()
    }
}

我的问题是:首先屏幕上的圆圈没有改变,它是从第一次调用中绘制的,然后它没有改变,

其次,我在日志上有这个:

counter = 1
counter = 2
Nov 17 00:51:51  grab a table[5132] <Error>: CGContextSetFillColorWithColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov 17 00:51:51  grab a table[5132] <Error>: CGContextSaveGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov 17 00:51:51  grab a table[5132] <Error>: CGContextSetFlatness: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov 17 00:51:51  grab a table[5132] <Error>: CGContextAddPath: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov 17 00:51:51  grab a table[5132] <Error>: CGContextDrawPath: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
Nov 17 00:51:51  grab a table[5132] <Error>: CGContextRestoreGState: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
counter = 3

我不知道它为什么在第三次迭代之后抛出这些错误。

我在计时器上做错了什么?我应该在每次调用函数update时构造路径吗?

您需要在drawRect中完成所有绘图。drawRect是将像素推送到屏幕上的函数。如果你想动态更改视图的绘制方式,你应该创建可以设置的属性(很可能是由视图控制器设置的),然后实现它们的didSet函数并调用setNeedsDisplay,这样你的视图就会用新参数重新绘制。例如:

var lineWidth: CGFloat {
        didSet {
            self.setNeedsDisplay()
        }
    }

var circlePath: UIBezierPath {
            didSet {
                self.setNeedsDisplay()
            }
        }

保持circlePath为变量,然后将drawRect更改为

override func drawRect(rect: CGRect) {
        UIColor.greenColor().setFill()
        if self.circlePath !=nil{
          self.circlePath.addLineToPoint(center)
          self.circlePath.fill()
        }
    }

然后移动

func degreesToRadians (number: Int) -> CGFloat {
        return CGFloat(number) * CGFloat(M_PI) / 180.0
    }
let startAngle: Double = 0
    var counter = 0
    let numberOfMinutes = 60
    var endAngle : Double {
        get {
            counter++
            return 360 - Double(360/60 * (counter))
        }
    }
func update() {
        print("counter = (counter)")
        let startAngleRadiant: CGFloat = degreesToRadians(startAngle)
        let endAngleRadiant: CGFloat = degreesToRadians(endAngle)
        let radius: CGFloat = 40.0
        path = UIBezierPath(arcCenter: center,
            radius: radius,
            startAngle: startAngleRadiant,
            endAngle: endAngleRadiant,
            clockwise: true)
        self.circleView.circlePath = path
    }

指向视图所在的视图控制器。获取对它的引用并将其称为circleView。然后在视图DidLoad位置:

let timer = NSTimer.scheduledTimerWithTimeInterval(0.4, target: self, selector: "update", userInfo: nil, repeats: true)
        timer.fire()

最新更新