Swift - CGAffineTransform 旋转

Swift - CGAffineTransform rotation

我有一个 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 旋转时保持大小。我错过了什么?

好的 - 您在问题中发布的代码与您的 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 视图更新不足以处理布局时完成的——例如在路径上使用 stroke/fill 时。

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

当自定义视图 subclass 初始化时创建你的子视图(UIViewUIImageView 或其他),并且 size/position 它带有 auto-layout 约束.

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

例如,这是您的 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)
    }

}