Swift: 为什么在 touchesBegan() 中将 UIView 的帧大小引用为 (0.0, 0.0)?
Swift: why has referenced UIView its frame size as (0.0, 0.0) inside touchesBegan()?
我只是想在一个愚蠢的 iOS 应用程序中进行一个简单的实验,我想在其中绘制轴作为参考,而可拖动的 UIImageView
在 UIView
上移动.问题是,当我可以 touchesBegan()
方法时,在其上绘制轴的引用 UIView
具有其框架大小 (0.0, 0.0),我收到此错误:
Feb 14 08:44:08 Fishmeter[30272] <Error>: CGContextSetRGBStrokeColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
这是我的可拖动代码 UIImageView
:
class PinImageView: UIImageView {
var viewForAxis:AxisView!
...
init(imageIcon: UIImage?, location:CGPoint, father:UIImageView, name:String, axisView:AxisView) {
...
self.viewForAxis = axisView
print(self.viewForAxis.frame.size)
...
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch: UITouch = touches.first {
print(self.viewForAxis.frame.size)
self.viewForAxis.hidden = false
self.viewForAxis.pin = self
//self.viewForAxis.setNeedsDisplay()
self.viewForAxis.drawAxis(CGPointMake(self.center.x, self.viewForAxis.frame.origin.y), to: (CGPointMake(self.center.x, self.viewForAxis.frame.origin.y + self.viewForAxis.frame.height)))
}
}
}
在第一个 print()
中我得到 (303.0, 414.0)
而在 touchesBegan()
中它变成 (0.0, 0.0)
然后我得到那个错误。
而 class AxisView
是:
class AxisView: UIView {
var pin:PinImageView?
func drawAxis(from:CGPoint, to:CGPoint) {
let context = UIGraphicsGetCurrentContext()
switch (self.pin!.id) {
case "redPinA","redPinB":
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0)
break
case "bluePinA, bluePinB":
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0)
break
default: break
}
/* line width of axes */
CGContextSetLineWidth(context, 0.5)
/* draw vertical axis inside magnifier */
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)
/* draw horizontal axis inside magnifier */
//CGContextMoveToPoint(context, self.zoomedPoint!.x - (self.frame.size.width / 2), self.zoomedPoint!.y)
//CGContextAddLineToPoint(context, self.zoomedPoint!.x + (self.frame.size.width / 2), self.zoomedPoint!.y)
CGContextStrokePath(context)
}
/*override func drawRect(rect: CGRect) {
if (pin != nil) {
self.drawAxis(CGPointMake((self.pin?.center.x)!, self.frame.origin.y), to: CGPointMake(self.pin!.center.x, self.frame.origin.y + self.frame.height))
}
}*/
}
正确的做法是什么?正如您从评论中看到的那样,我也尝试将所有内容都放在 drawRect()
方法中,但是 setNeedsDisplay()
没有被调用,因为大小是 (0.0, 0.0)...谢谢大家。
这是我在主视图控制器中所做的:
self.view.addSubview(self.axisView)
self.axisView.hidden = true
self.redPinA = PinImageView(imageIcon: UIImage(named: "icons/red_pin.png"), location: CGPointMake(40, 110), father: self.imageView, name: "redPinA", axisView: self.axisView)
self.redPinB = PinImageView(imageIcon: UIImage(named: "icons/red_pin.png"), location: CGPointMake(80, 110), father: self.imageView, name: "redPinB", axisView: self.axisView)
self.bluePinA = PinImageView(imageIcon: UIImage(named: "icons/blue_pin.png"), location: CGPointMake(200, 110), father: self.imageView, name: "bluePinA", axisView: self.axisView)
self.bluePinB = PinImageView(imageIcon: UIImage(named: "icons/blue_pin.png"), location: CGPointMake(240, 110), father: self.imageView, name: "bluePinB", axisView: self.axisView)
self.view.addSubview(self.redPinA)
self.view.addSubview(self.redPinB)
self.view.addSubview(self.bluePinA)
self.view.addSubview(self.bluePinB)
该错误正确地指出 touchesBegan
正在调用 drawAxis
,它正在调用 CGContext
函数,但您不在有效上下文中(因此,"invalid context 0x0").
您不应直接从 touchesBegan
调用任何 CGContext
函数。您可以更新状态变量,然后调用 setNeedsDisplay
,这将导致 drawRect
被 OS 调用,您可以在其中绘制坐标轴。但是不要试图自己画它们。
但我尝试了以下方法并且效果很好:
class AxisView: UIView {
var pin:PinImageView?
func drawAxis(from:CGPoint, to:CGPoint) {
let context = UIGraphicsGetCurrentContext()
switch pin!.id {
case "redPinA", "redPinB":
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0)
case "bluePinA", "bluePinB":
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0)
default: break
}
/* line width of axes */
CGContextSetLineWidth(context, 0.5)
/* draw vertical axis inside magnifier */
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)
/* draw horizontal axis inside magnifier */
CGContextStrokePath(context)
}
override func drawRect(rect: CGRect) {
if pin != nil {
drawAxis(CGPointMake(pin!.center.x, frame.origin.y), to: CGPointMake(pin!.center.x, frame.origin.y + frame.height))
}
}
}
class PinImageView: UIImageView {
var lastLocation:CGPoint!
var id:String!
var viewForAxis:AxisView!
init(imageIcon: UIImage?, location:CGPoint, name:String, axisView:AxisView) {
super.init(image: imageIcon)
lastLocation = location
id = name
viewForAxis = axisView
print(viewForAxis.frame.size)
center = location
frame = CGRect(x: location.x, y: location.y, width: 40.0, height: 60.0)
userInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let _ = touches.first {
print(viewForAxis.frame.size)
viewForAxis.hidden = false
viewForAxis.pin = self
viewForAxis.setNeedsDisplay()
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
viewForAxis.hidden = true
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch: UITouch = touches.first {
center = touch.locationInView(superview)
viewForAxis.setNeedsDisplay()
}
}
}
class ViewController: UIViewController {
var axisView: AxisView!
var redPinA: PinImageView!
var redPinB: PinImageView!
var bluePinA: PinImageView!
var bluePinB: PinImageView!
override func viewDidLoad() {
super.viewDidLoad()
axisView = AxisView()
axisView.frame = view.bounds
axisView.backgroundColor = UIColor.clearColor()
view.addSubview(axisView)
axisView.hidden = true
redPinA = PinImageView(imageIcon: UIImage(named: "red_pin.png"), location: CGPointMake(40, 110), name: "redPinA", axisView: axisView)
redPinB = PinImageView(imageIcon: UIImage(named: "red_pin.png"), location: CGPointMake(80, 110), name: "redPinB", axisView: axisView)
bluePinA = PinImageView(imageIcon: UIImage(named: "blue_pin.png"), location: CGPointMake(200, 110), name: "bluePinA", axisView: axisView)
bluePinB = PinImageView(imageIcon: UIImage(named: "blue_pin.png"), location: CGPointMake(240, 110), name: "bluePinB", axisView: axisView)
view.addSubview(redPinA)
view.addSubview(redPinB)
view.addSubview(bluePinA)
view.addSubview(bluePinB)
}
}
我从您的评论中推断,您曾尝试直接调用此代码来解决 setNeedsDisplay
未导致 drawRect
被调用的问题。这听起来像是一个单独的问题。解决方案不是自己调用 drawRect
(或 drawAxis
),而是找出为什么 setNeedsDisplay
没有完成这项工作。但是问题不在于您问题中的代码,而显然是其他问题的结果。
我只是想在一个愚蠢的 iOS 应用程序中进行一个简单的实验,我想在其中绘制轴作为参考,而可拖动的 UIImageView
在 UIView
上移动.问题是,当我可以 touchesBegan()
方法时,在其上绘制轴的引用 UIView
具有其框架大小 (0.0, 0.0),我收到此错误:
Feb 14 08:44:08 Fishmeter[30272] <Error>: CGContextSetRGBStrokeColor: invalid context 0x0. If you want to see the backtrace, please set CG_CONTEXT_SHOW_BACKTRACE environmental variable.
这是我的可拖动代码 UIImageView
:
class PinImageView: UIImageView {
var viewForAxis:AxisView!
...
init(imageIcon: UIImage?, location:CGPoint, father:UIImageView, name:String, axisView:AxisView) {
...
self.viewForAxis = axisView
print(self.viewForAxis.frame.size)
...
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch: UITouch = touches.first {
print(self.viewForAxis.frame.size)
self.viewForAxis.hidden = false
self.viewForAxis.pin = self
//self.viewForAxis.setNeedsDisplay()
self.viewForAxis.drawAxis(CGPointMake(self.center.x, self.viewForAxis.frame.origin.y), to: (CGPointMake(self.center.x, self.viewForAxis.frame.origin.y + self.viewForAxis.frame.height)))
}
}
}
在第一个 print()
中我得到 (303.0, 414.0)
而在 touchesBegan()
中它变成 (0.0, 0.0)
然后我得到那个错误。
而 class AxisView
是:
class AxisView: UIView {
var pin:PinImageView?
func drawAxis(from:CGPoint, to:CGPoint) {
let context = UIGraphicsGetCurrentContext()
switch (self.pin!.id) {
case "redPinA","redPinB":
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0)
break
case "bluePinA, bluePinB":
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0)
break
default: break
}
/* line width of axes */
CGContextSetLineWidth(context, 0.5)
/* draw vertical axis inside magnifier */
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)
/* draw horizontal axis inside magnifier */
//CGContextMoveToPoint(context, self.zoomedPoint!.x - (self.frame.size.width / 2), self.zoomedPoint!.y)
//CGContextAddLineToPoint(context, self.zoomedPoint!.x + (self.frame.size.width / 2), self.zoomedPoint!.y)
CGContextStrokePath(context)
}
/*override func drawRect(rect: CGRect) {
if (pin != nil) {
self.drawAxis(CGPointMake((self.pin?.center.x)!, self.frame.origin.y), to: CGPointMake(self.pin!.center.x, self.frame.origin.y + self.frame.height))
}
}*/
}
正确的做法是什么?正如您从评论中看到的那样,我也尝试将所有内容都放在 drawRect()
方法中,但是 setNeedsDisplay()
没有被调用,因为大小是 (0.0, 0.0)...谢谢大家。
这是我在主视图控制器中所做的:
self.view.addSubview(self.axisView)
self.axisView.hidden = true
self.redPinA = PinImageView(imageIcon: UIImage(named: "icons/red_pin.png"), location: CGPointMake(40, 110), father: self.imageView, name: "redPinA", axisView: self.axisView)
self.redPinB = PinImageView(imageIcon: UIImage(named: "icons/red_pin.png"), location: CGPointMake(80, 110), father: self.imageView, name: "redPinB", axisView: self.axisView)
self.bluePinA = PinImageView(imageIcon: UIImage(named: "icons/blue_pin.png"), location: CGPointMake(200, 110), father: self.imageView, name: "bluePinA", axisView: self.axisView)
self.bluePinB = PinImageView(imageIcon: UIImage(named: "icons/blue_pin.png"), location: CGPointMake(240, 110), father: self.imageView, name: "bluePinB", axisView: self.axisView)
self.view.addSubview(self.redPinA)
self.view.addSubview(self.redPinB)
self.view.addSubview(self.bluePinA)
self.view.addSubview(self.bluePinB)
该错误正确地指出 touchesBegan
正在调用 drawAxis
,它正在调用 CGContext
函数,但您不在有效上下文中(因此,"invalid context 0x0").
您不应直接从 touchesBegan
调用任何 CGContext
函数。您可以更新状态变量,然后调用 setNeedsDisplay
,这将导致 drawRect
被 OS 调用,您可以在其中绘制坐标轴。但是不要试图自己画它们。
但我尝试了以下方法并且效果很好:
class AxisView: UIView {
var pin:PinImageView?
func drawAxis(from:CGPoint, to:CGPoint) {
let context = UIGraphicsGetCurrentContext()
switch pin!.id {
case "redPinA", "redPinB":
CGContextSetRGBStrokeColor(context, 1.0, 0.0, 0.0, 1.0)
case "bluePinA", "bluePinB":
CGContextSetRGBStrokeColor(context, 0.0, 0.0, 1.0, 1.0)
default: break
}
/* line width of axes */
CGContextSetLineWidth(context, 0.5)
/* draw vertical axis inside magnifier */
CGContextMoveToPoint(context, from.x, from.y)
CGContextAddLineToPoint(context, to.x, to.y)
/* draw horizontal axis inside magnifier */
CGContextStrokePath(context)
}
override func drawRect(rect: CGRect) {
if pin != nil {
drawAxis(CGPointMake(pin!.center.x, frame.origin.y), to: CGPointMake(pin!.center.x, frame.origin.y + frame.height))
}
}
}
class PinImageView: UIImageView {
var lastLocation:CGPoint!
var id:String!
var viewForAxis:AxisView!
init(imageIcon: UIImage?, location:CGPoint, name:String, axisView:AxisView) {
super.init(image: imageIcon)
lastLocation = location
id = name
viewForAxis = axisView
print(viewForAxis.frame.size)
center = location
frame = CGRect(x: location.x, y: location.y, width: 40.0, height: 60.0)
userInteractionEnabled = true
}
required init?(coder aDecoder: NSCoder) {
fatalError("init(coder:) has not been implemented")
}
override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let _ = touches.first {
print(viewForAxis.frame.size)
viewForAxis.hidden = false
viewForAxis.pin = self
viewForAxis.setNeedsDisplay()
}
}
override func touchesEnded(touches: Set<UITouch>, withEvent event: UIEvent?) {
viewForAxis.hidden = true
}
override func touchesMoved(touches: Set<UITouch>, withEvent event: UIEvent?) {
if let touch: UITouch = touches.first {
center = touch.locationInView(superview)
viewForAxis.setNeedsDisplay()
}
}
}
class ViewController: UIViewController {
var axisView: AxisView!
var redPinA: PinImageView!
var redPinB: PinImageView!
var bluePinA: PinImageView!
var bluePinB: PinImageView!
override func viewDidLoad() {
super.viewDidLoad()
axisView = AxisView()
axisView.frame = view.bounds
axisView.backgroundColor = UIColor.clearColor()
view.addSubview(axisView)
axisView.hidden = true
redPinA = PinImageView(imageIcon: UIImage(named: "red_pin.png"), location: CGPointMake(40, 110), name: "redPinA", axisView: axisView)
redPinB = PinImageView(imageIcon: UIImage(named: "red_pin.png"), location: CGPointMake(80, 110), name: "redPinB", axisView: axisView)
bluePinA = PinImageView(imageIcon: UIImage(named: "blue_pin.png"), location: CGPointMake(200, 110), name: "bluePinA", axisView: axisView)
bluePinB = PinImageView(imageIcon: UIImage(named: "blue_pin.png"), location: CGPointMake(240, 110), name: "bluePinB", axisView: axisView)
view.addSubview(redPinA)
view.addSubview(redPinB)
view.addSubview(bluePinA)
view.addSubview(bluePinB)
}
}
我从您的评论中推断,您曾尝试直接调用此代码来解决 setNeedsDisplay
未导致 drawRect
被调用的问题。这听起来像是一个单独的问题。解决方案不是自己调用 drawRect
(或 drawAxis
),而是找出为什么 setNeedsDisplay
没有完成这项工作。但是问题不在于您问题中的代码,而显然是其他问题的结果。