Swift - CGAffineTransform 旋转

发布于 2025-01-13 09:50:41 字数 847 浏览 0 评论 0原文

我有一个 UIImageView 可以在 draw 函数中旋转。

public var progress: CGFloat = 0 {
    didSet {
        setNeedsDisplay()
    }
}

override public func draw(_ rect: CGRect) {
    rotateIcon(by: progress)
}

private func rotateIcon(by angle: CGFloat) {
    if imageView == nil {
        imageView = UIImageView(image: UIImage(named: "bt_info"))
        imageView?.center = center
        imageView?.frame.size = CGSize(width: 24.0, height: 24.0)
        addSubview(imageView!)
    }
    imageView?.transform = CGAffineTransform(rotationAngle: angle)
}

以下是上述代码片段所附的输出。

输入图片此处描述

当我设置帧大小时,imageView 随着旋转而缩小和扩展。我想在 imageView 旋转时保持尺寸。我缺少什么?

I have an UIImageView to rotate in a draw function.

public var progress: CGFloat = 0 {
    didSet {
        setNeedsDisplay()
    }
}

override public func draw(_ rect: CGRect) {
    rotateIcon(by: progress)
}

private func rotateIcon(by angle: CGFloat) {
    if imageView == nil {
        imageView = UIImageView(image: UIImage(named: "bt_info"))
        imageView?.center = center
        imageView?.frame.size = CGSize(width: 24.0, height: 24.0)
        addSubview(imageView!)
    }
    imageView?.transform = CGAffineTransform(rotationAngle: angle)
}

Below is the output attached for the above snippet.

enter image description here

When I set the frame size, the imageView shrink and expands as it rotates. I would like to maintain the size as the imageView rotates. What am I missing?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

淡笑忘祈一世凡恋 2025-01-20 09:50:41

好的 - 您在问题中发布的代码与您的 Dropbox 项目中的代码不匹配...

在您的项目中,您正在执行以下操作:

private func rotateScannerIcon(by angle: CGFloat) {
    if testView == nil {
        testView = UIView()
        testView?.backgroundColor = .red
        addSubview(testView!)
    }
    
    let centerPoint = CGPoint(x: bounds.midX, y: bounds.midY)
    testView?.center = centerPoint
    testView?.frame.size = CGSize(width: 24.0, height: 24.0)

    testView?.transform = CGAffineTransform(rotationAngle: angle)
}

使用该代码,您将在之后更改框架大小已经应用了旋转变换......并且实际视图不再是“正方形”。

如果您在“创建”块内移动位置/大小代码:

private func rotateScannerIcon(by angle: CGFloat) {
    if testView == nil {
        testView = UIView()
        testView?.backgroundColor = .red
        addSubview(testView!)

        let centerPoint = CGPoint(x: bounds.midX, y: bounds.midY)
        testView?.center = centerPoint
        testView?.frame.size = CGSize(width: 24.0, height: 24.0)
    }
    
    testView?.transform = CGAffineTransform(rotationAngle: angle)
}

框架的“挤压”不再发生。

不过,重写draw()可能不是最好的方法。这主要是在 UIKit 视图更新不足以处理布局时完成的 - 例如在路径上使用描边/填充时。

因此,我建议进行一些更改。

初始化自定义视图子类时创建子视图(UIViewUIImageView 或其他),并使用自动布局约束调整其大小/位置。

然后,当您更新 progress 属性时,应用旋转变换。

例如,下面是 TestView 类的修改版本:

public class TestView: UIView {
    
    public var progress: CGFloat = 0 {
        didSet {
            rotateScannerIcon(by: (progress * CGFloat(Double.pi)))
        }
    }
    
    internal var testView: UIView!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        // create the view (or image view)
        testView = UIView()
        testView.backgroundColor = .red
        
        // add it to self
        addSubview(testView)
        
        // let's use auto-layout constraints
        testView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            // constrain the view to 24 x 24, centered in self
            testView.widthAnchor.constraint(equalToConstant: 24.0),
            testView.heightAnchor.constraint(equalTo: testView.widthAnchor),
            testView.centerXAnchor.constraint(equalTo: centerXAnchor),
            testView.centerYAnchor.constraint(equalTo: centerYAnchor),
        ])
        
    }

    private func rotateScannerIcon(by angle: CGFloat) {
        testView.transform = CGAffineTransform(rotationAngle: angle)
    }

}

OK - the code you posted in your question does not match the code in your Dropbox project...

In your project, you're doing this:

private func rotateScannerIcon(by angle: CGFloat) {
    if testView == nil {
        testView = UIView()
        testView?.backgroundColor = .red
        addSubview(testView!)
    }
    
    let centerPoint = CGPoint(x: bounds.midX, y: bounds.midY)
    testView?.center = centerPoint
    testView?.frame.size = CGSize(width: 24.0, height: 24.0)

    testView?.transform = CGAffineTransform(rotationAngle: angle)
}

With that code, you are changing the frame size after a rotation transform has been applied... and the actual view is no longer "square."

If you move the position / size code inside your "create" block:

private func rotateScannerIcon(by angle: CGFloat) {
    if testView == nil {
        testView = UIView()
        testView?.backgroundColor = .red
        addSubview(testView!)

        let centerPoint = CGPoint(x: bounds.midX, y: bounds.midY)
        testView?.center = centerPoint
        testView?.frame.size = CGSize(width: 24.0, height: 24.0)
    }
    
    testView?.transform = CGAffineTransform(rotationAngle: angle)
}

The "squeezing" of the frame no longer happens.

Overriding draw() is probably not the best approach, though. That is primarily done when UIKit view updates are not sufficient to handle the layout - such as when using stroke/fill on paths.

So, I would suggest a couple changes.

Create your subview (UIView or UIImageView or whatever) when the custom view subclass is initialized, and size/position it with auto-layout constraints.

Then, when you update the progress property, apply the rotation transform.

As an example, here's a modified version of your TestView class:

public class TestView: UIView {
    
    public var progress: CGFloat = 0 {
        didSet {
            rotateScannerIcon(by: (progress * CGFloat(Double.pi)))
        }
    }
    
    internal var testView: UIView!
    
    override init(frame: CGRect) {
        super.init(frame: frame)
        commonInit()
    }
    required init?(coder: NSCoder) {
        super.init(coder: coder)
        commonInit()
    }
    func commonInit() {
        // create the view (or image view)
        testView = UIView()
        testView.backgroundColor = .red
        
        // add it to self
        addSubview(testView)
        
        // let's use auto-layout constraints
        testView.translatesAutoresizingMaskIntoConstraints = false
        
        NSLayoutConstraint.activate([
            // constrain the view to 24 x 24, centered in self
            testView.widthAnchor.constraint(equalToConstant: 24.0),
            testView.heightAnchor.constraint(equalTo: testView.widthAnchor),
            testView.centerXAnchor.constraint(equalTo: centerXAnchor),
            testView.centerYAnchor.constraint(equalTo: centerYAnchor),
        ])
        
    }

    private func rotateScannerIcon(by angle: CGFloat) {
        testView.transform = CGAffineTransform(rotationAngle: angle)
    }

}
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文