使用内部绘图旋转 UIView 的问题

Posted

技术标签:

【中文标题】使用内部绘图旋转 UIView 的问题【英文标题】:Problems rotating UIView with drawing inside 【发布时间】:2017-01-22 11:33:27 【问题描述】:

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

不带旋转的 UIView:

带有旋转的 UIView:

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

主视图控制器

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.



界面视图

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)



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

我能做什么?提前致谢

【问题讨论】:

【参考方案1】:

当你应该使用bounds时,你正在使用frame

frame 是包含view 的矩形。它在viewsuperview 的坐标系中指定,当您旋转viewframe 会发生变化(因为旋转的正方形在X 和Y 方向上比未旋转的正方形延伸得更远) )。

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)


【讨论】:

谢谢!经过多次战斗,我已经看到了你的答案,在我看到它之前,我发现了关于 rect vs bounds 的问题...... ;) 我假设框架高度/宽度等于边界高度/宽度,但这在旋转时似乎是错误的。致所有阅读者:确保将所有代码使用 frame 替换为 bounds

以上是关于使用内部绘图旋转 UIView 的问题的主要内容,如果未能解决你的问题,请参考以下文章

旋转UIView并使其更改视图大小以适应相对于旋转的空间

长路漫漫,唯剑作伴--Core Animation

UIView 中的 CG 绘图用作 UIImage?

使用触摸平滑旋转 UIView

使用核心动画和块旋转 UIView 对象的问题

如何旋转 UIView?