内部绘图旋转 UIView 时出现问题

Problems rotating UIView with drawing inside

我想旋转一个内部有绘图(圆形、矩形或直线)的 UIView。问题是当我旋转视图并刷新绘图时(当我更改绘图的某些属性时需要 ir,即)绘图不跟随视图...

没有旋转的UIView:

带旋转的 UIView:

这是我的简单代码(原始代码的一小部分摘录):

主要ViewController

class TestRotation: UIViewController {

// MARK: - Properties

var drawingView:DrawingView?

// MARK: - Actions

@IBAction func actionSliderRotation(_ sender: UISlider) {

    let degrees = sender.value
    let radians = CGFloat(degrees * Float.pi / 180)
    drawingView?.transform = CGAffineTransform(rotationAngle: radians)

    drawingView?.setNeedsDisplay()
}

// MARK: - Init

override func viewDidLoad() {
    super.viewDidLoad()

    drawingView = DrawingView(frame:CGRect(x:50, y:50, width: 100, height:75))

    self.view.addSubview(drawingView!)

    drawingView?.setNeedsDisplay() 
}

override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    // Dispose of any resources that can be recreated.
}

}

UIView

class DrawingView: UIView {

override func draw(_ rect: CGRect) {

    let start = CGPoint(x: 0, y: 0)
    let end = CGPoint(x: self.frame.size.width, y: self.frame.size.height)

    drawCicrle(start: start, end: end)
}

func drawCicrle(start:CGPoint, end:CGPoint) {

    //Contexto
    let context = UIGraphicsGetCurrentContext()

    if context != nil {

        //Ancho
        context!.setLineWidth(2)

        //Color
        context!.setStrokeColor(UIColor.black.cgColor)
        context!.setFillColor(UIColor.orange.cgColor)

        let rect = CGRect(origin: start, size: CGSize(width: end.x-start.x, height: end.y-start.y))

        let path = UIBezierPath(ovalIn: rect)

        path.lineWidth = 2
        path.fill()
        path.stroke()

    }
}

// MARK: - Init

override init(frame: CGRect) {
    super.init(frame: frame)

    self.backgroundColor = UIColor.gray
}

required init?(coder aDecoder: NSCoder) {
    super.init(coder: aDecoder)
}

}

旋转后不刷新视图似乎暂时解决了问题,但如果由于其他原因(属性更改)稍后必须刷新,问题又出现了。

我能做什么?提前致谢

你在使用 frame 而你应该使用 bounds

frame 是包含 view 的矩形。它是在viewsuperview坐标系中指定的,当您旋转viewframe会发生变化(因为旋转的正方形在X和Y方向比一个non-rotated正方形)。

bounds是包含view内容的矩形。它在 view 本身的坐标系中指定,并且不会随着 view 旋转或移动而改变。

如果您在 draw(_:) 函数中将 frame 更改为 bounds,它将按您预期的那样工作:

override func draw(_ rect: CGRect) {

    let start = CGPoint(x: 0, y: 0)
    let end = CGPoint(x: self.bounds.size.width, y: self.bounds.size.height)

    drawCicrle(start: start, end: end)
}

这是一个演示,显示了随着滑块移动而重新绘制的椭圆。


这是更改后的代码:

class DrawingView: UIView {

    var fillColor = UIColor.orange {
        didSet {
            setNeedsDisplay()
        }
    }

    override func draw(_ rect: CGRect) {

        let start = CGPoint(x: 0, y: 0)
        let end = CGPoint(x: self.bounds.size.width, y: self.bounds.size.height)

        drawCircle(start: start, end: end)
    }

    func drawCircle(start:CGPoint, end:CGPoint) {

        //Contexto
        let context = UIGraphicsGetCurrentContext()

        if context != nil {

            //Ancho
            context!.setLineWidth(2)

            //Color
            context!.setStrokeColor(UIColor.black.cgColor)
            context!.setFillColor(fillColor.cgColor)

            let rect = CGRect(origin: start, size: CGSize(width: end.x-start.x, height: end.y-start.y))

            let path = UIBezierPath(ovalIn: rect)

            path.lineWidth = 2
            path.fill()
            path.stroke()

        }
    }

    // MARK: - Init

    override init(frame: CGRect) {
        super.init(frame: frame)

        self.backgroundColor = UIColor.gray
    }

    required init?(coder aDecoder: NSCoder) {
        super.init(coder: aDecoder)
    }

}

@IBAction func actionSliderRotation(_ sender: UISlider) {

    let degrees = sender.value
    let radians = CGFloat(degrees * Float.pi / 180)
    drawingView?.transform = CGAffineTransform(rotationAngle: radians)

    drawingView?.fillColor = UIColor(hue: CGFloat(degrees)/360.0, saturation: 1.0, brightness: 1.0, alpha: 1.0)

}