ios - Swift:为什么在 touchesBegan() 中将 UIView 的帧大小引用为 (0.0, 0.0)?

标签 ios swift uiview core-graphics

我只是想在一个愚蠢的 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)然后我得到那个错误。 而类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)...谢谢大家。

这是我在主视图 Controller 中所做的:

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 函数,但您不在有效上下文(因此,“无效上下文 0x0”)。

您不应该直接从 touchesBegan 调用任何 CGContext 函数。您可以更新状态变量,然后调用 setNeedsDisplay,这将导致操作系统调用 drawRect,您可以在其中绘制坐标轴。但不要试图自己画它们。

但我尝试了以下方法并且效果很好:

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 - Swift:为什么在 touchesBegan() 中将 UIView 的帧大小引用为 (0.0, 0.0)?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/35389549/

相关文章:

objective-c - NSStackView 和内容拥抱优先级

ios - 在ios中设置自定义UI的大小

ios - UICollectionView 显示隐藏动画问题

ios - UISearchBar 取消按钮不起作用

ios - Swift 取消 ActivityViewController 导致 fatal error

Swift:表格 View 单元上的 UIPanGesture 不起作用

ios - 如何引用 cellForRowAtIndexPath 之外的单元格

iphone - 崩溃在 actionForLayer :forKey:

ios - 无法生成 newParagraphStyle 崩溃

ios - 在 dispatch_async 中调用委托(delegate)方法