我有两个并排的函数,它们循环不断地绘制两个UIBezierPath,问题是,它们每个都有不同的颜色,所以我需要不断地重申UIColor.blackColor().setFill()
和UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
,缺点是它使控制台无法读取,因为它不断地向你发送警告消息。
<Error>: CGContextRestoreGState: invalid context 0x0. This is a serious error.
This application, or a library it uses, is using an invalid context and is thereby
contributing to an overall degradation of system stability and reliability. This
notice is a courtesy: please fix this problem. It will become a fatal error in an
upcoming update.
因此,我的问题是,有没有一种方法可以做到这一点,不会向我的控制台发送此警告消息?也许是一种使警告信息不会出现的方法?(搜索时找不到)或者可能是一种省略消息的方法?任何意见都非常感谢,感谢阅读-扎克。
-
如果你需要画functions
,它们在下面
func drawCircle() {
//Setting the draw color
UIColor.blackColor().setFill()
// Creating the rectangle's size
var drawRect = roundDrawRect(10.0, angle: 7)
//Incrementing the coords
++y
++x
//Drawing the rectangle
drawRect.fill()
}
func eraseCircle() {
//Setting the eraser color
UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
//Decrementing the coords
eraseX = x - 2
eraseY = y - 2
// Creating the rectangle's size
var eraseRect = roundEraseRect(10.0, angle: 7)
//Drawing the rectangle
eraseRect.fill()
}
下面的Full CircleView类(我对编程还很陌生,所以可能效率很低)
//Creating a view capable of painting the circle
class CircleView: UIView {
//Starting X Pos
var x: CGFloat = 100
var eraseX: CGFloat = 100
//Starting Y Pos
var y: CGFloat = 100
var eraseY: CGFloat = 100
//Starting the loop of functions
override func drawRect(rect: CGRect) {
//Creating the looping draw timer
NSTimer.scheduledTimerWithTimeInterval(
0.2,
target: self,
selector: Selector("timerDraw"),
userInfo: nil,
repeats: true)
//Creating the looping erase timer
NSTimer.scheduledTimerWithTimeInterval(
0.3,
target: self,
selector: Selector("timerErase"),
userInfo: nil,
repeats: true)
}
func drawCircle() {
//Setting the draw color
UIColor.blackColor().setFill()
// Creating the rectangle's size
var drawRect = roundDrawRect(10.0, angle: 7)
//Incrementing the coords
++y
++x
//Drawing the rectangle
drawRect.fill()
}
func eraseCircle() {
//Setting the eraser color
UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
//Decrementing the coords
eraseX = x - 2
eraseY = y - 2
// Creating the rectangle's size
var eraseRect = roundEraseRect(10.0, angle: 7)
//Drawing the rectangle
eraseRect.fill()
}
func timerDraw(){
//DO DRAW LOOP HERE
drawCircle()
}
func timerErase(){
//DO ERASE LOOP HERE
eraseCircle()
}
//Defining the rounded rect erasing (Circle)
func roundEraseRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
//Creating the rounded rect (Circle)
var roundedRect = UIBezierPath()
roundedRect.moveToPoint(CGPointMake(eraseX,eraseY))
println(CGPointMake(eraseX,eraseY))
roundedRect.addArcWithCenter(CGPointZero, radius: radius,
startAngle: 0, endAngle: angle ,
clockwise: true)
return roundedRect
}
//Defining the rounded rect drawing (Circle)
func roundDrawRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
//Creating the rounded rect (Circle)
var roundedRect = UIBezierPath()
roundedRect.moveToPoint(CGPointMake(x,y))
roundedRect.addArcWithCenter(CGPointZero, radius: radius,
startAngle: 0, endAngle: angle ,
clockwise: true)
return roundedRect
}
}
class ViewController: UIViewController {
苹果iOS版绘图和打印指南解释了所有这些,我强烈建议在进一步使用自定义绘图代码之前阅读它。至少,请阅读有关iOS绘图概念的部分
问题是您正在CircleView
的drawRect
函数中创建并启动NSTimer
。绘图调用只能在正确的上下文中进行(这实际上是你看到的错误试图告诉你的)。通过在从NSTimer
调用的函数中进行绘制,实际上是在drawRect
函数外部进行绘制,并且在这种情况下没有有效的绘制上下文。此外,按照代码的方式,每次系统需要重新绘制视图时,您都会启动新的计时器;随着计时器开始重叠,这种情况可能会很快失控。
然而,只要稍微重新安排一下,我们就能做到这一点。
请注意:这不一定是处理圆形动画的正确方法,但它将解决您所询问的与无效上下文错误有关的特定问题
-
从
drawRect
中取出所有内容,并将其替换为对eraseCircle
和drawCircle
的调用。 -
取必须从
drawCircle
和eraseCircle
中增加x
和y
、eraseX
和eraseY
的逻辑,将其放入timerDraw
和timerErase
中。 -
不要直接在
timerDraw
和timerErase
中调用图形代码,而是通过调用setNeedsDisplay()
告诉视图系统需要重新绘制视图。这将标记您的视图需要重新绘制,视图系统将尽快自动再次调用drawRect
函数。 -
通过覆盖
didMoveToSuperview
并在那里启动计时器,使计时器重新工作;如果它们已经在运行,您还应该添加逻辑来阻止它们。
步骤1和3是消除错误的关键部分
类似这样的东西:
//Creating a view capable of painting the circle
class CircleView: UIView {
// Timers
var drawTimer: NSTimer?
var eraseTimer: NSTimer?
//Starting X Pos
var x: CGFloat = 100
var eraseX: CGFloat = 100
//Starting Y Pos
var y: CGFloat = 100
var eraseY: CGFloat = 100
override func drawRect(rect: CGRect) {
eraseCircle()
drawCircle()
}
override func didMoveToSuperview() {
// If we have active timers, stop them
if var drawTimer = self.drawTimer {
// This stops the timer
drawTimer.invalidate()
self.drawTimer = nil
}
if var eraseTimer = self.eraseTimer {
// This stops the timer
eraseTimer.invalidate()
self.eraseTimer = nil
}
// If we're actually part of the view hierarchy, start the timers
if self.superview != nil {
//Creating the looping draw timer
self.drawTimer = NSTimer.scheduledTimerWithTimeInterval(
0.2,
target: self,
selector: Selector("timerDraw"),
userInfo: nil,
repeats: true)
//Creating the looping erase timer
self.eraseTimer = NSTimer.scheduledTimerWithTimeInterval(
0.3,
target: self,
selector: Selector("timerErase"),
userInfo: nil,
repeats: true)
}
}
func drawCircle() {
//Setting the draw color
UIColor.blackColor().setFill()
// Creating the rectangle's size
var drawRect = roundDrawRect(10.0, angle: 7)
//Drawing the rectangle
drawRect.fill()
}
func eraseCircle() {
//Setting the eraser color
UIColor(patternImage: UIImage(named: "normalpaper.jpg")).setFill()
// Creating the rectangle's size
var eraseRect = roundEraseRect(10.0, angle: 7)
//Drawing the rectangle
eraseRect.fill()
}
func timerDraw(){
//Incrementing the coords
++y
++x
self.setNeedsDisplay()
}
func timerErase(){
//Decrementing the coords
eraseX = x - 2
eraseY = y - 2
self.setNeedsDisplay()
}
//Defining the rounded rect erasing (Circle)
func roundEraseRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
//Creating the rounded rect (Circle)
var roundedRect = UIBezierPath()
roundedRect.moveToPoint(CGPointMake(eraseX,eraseY))
println(CGPointMake(eraseX,eraseY))
roundedRect.addArcWithCenter(CGPointZero, radius: radius,
startAngle: 0, endAngle: angle ,
clockwise: true)
return roundedRect
}
//Defining the rounded rect drawing (Circle)
func roundDrawRect(radius: CGFloat, angle: CGFloat) -> UIBezierPath {
//Creating the rounded rect (Circle)
var roundedRect = UIBezierPath()
roundedRect.moveToPoint(CGPointMake(x,y))
roundedRect.addArcWithCenter(CGPointZero, radius: radius,
startAngle: 0, endAngle: angle ,
clockwise: true)
return roundedRect
}
}
至于实现您尝试的动画的最佳方式,您可以考虑只画一次圆,然后在UIViewController
中在计时器上移动整个视图。或者,使用核心动画可能更好。或者,如果你的最终产品将是一款游戏(甚至类似游戏),也许可以看看雪碧套装。