如何在 Swift 中应用多个转换
How to apply multiple transforms in Swift
我想对 UIView
(或 UIView
的子类)应用多个变换,例如平移、旋转和缩放。我知道 CGAffineTransformConcat
可以应用两个变换,但如果我有三个或更多变换,我该怎么做?
我看到了这些问题:
- Applying multiple transforms to a UIView / CALayer
- Using Multiple CGAffineTransforms On Text Matrix
但是这些问题问的是不同的东西,给定的答案只是谈论用 CGAffineTransformConcat
应用两个转换。此外,他们使用 Objective-C 而不是 Swift。
您可以通过将它们堆叠在一起来应用多个变换。
var t = CGAffineTransform.identity
t = t.translatedBy(x: 100, y: 300)
t = t.rotated(by: CGFloat.pi / 4)
t = t.scaledBy(x: -1, y: 2)
// ... add as many as you want, then apply it to to the view
imageView.transform = t
或更简洁(但不一定具有可读性):
imageView.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 300).rotated(by: CGFloat.pi / 4).scaledBy(x: -1, y: 2)
这一系列的变换产生了右边的图像:
感谢 this answer 教我怎么做。
备注
应用转换的顺序很重要。例如,如果以相反的顺序进行转换,则会产生以下结果。
t = t.scaledBy(x: -1, y: 2)
t = t.rotated(by: CGFloat.pi / 4)
t = t.translatedBy(x: 100, y: 300)
另见
- CGAffineTransform Reference(文档)
- Transforms(文档)
- Swift: Translating and Rotating a CGContext, A Visual Explanation (iOS/Xcode)
- Demystifying CGAffineTransform
此答案已通过 Swift 4
测试
在 Swift 3 中,这些已被 CGAffineTransform 本身的函数所取代,可以链接。
extension CGAffineTransform {
public func translatedBy(x tx: CGFloat, y ty: CGFloat) -> CGAffineTransform
public func scaledBy(x sx: CGFloat, y sy: CGFloat) -> CGAffineTransform
public func rotated(by angle: CGFloat) -> CGAffineTransform
}
例如
let transform = CGAffineTransform(scaleX: 1.0, y: 3.0).translatedBy(x: 12, y: 9).rotated(by: 17.0)
诀窍在于
view.transform.translatedBy(x: 100, y: 100)
没有改变 view.transform
。它只是 returns 您需要分配回 view.transform
的新 CGAffineTransform
。
view.transform = view.transform.translatedBy(x: 100, y: 100)
您可以根据需要多次或按顺序执行此操作
view.transform = view.transform.translatedBy(x: 100, y: 100).rotated(by: CGFloat.pi / 2).scaledBy(x: 2, y: 2)
我想对 UIView
(或 UIView
的子类)应用多个变换,例如平移、旋转和缩放。我知道 CGAffineTransformConcat
可以应用两个变换,但如果我有三个或更多变换,我该怎么做?
我看到了这些问题:
- Applying multiple transforms to a UIView / CALayer
- Using Multiple CGAffineTransforms On Text Matrix
但是这些问题问的是不同的东西,给定的答案只是谈论用 CGAffineTransformConcat
应用两个转换。此外,他们使用 Objective-C 而不是 Swift。
您可以通过将它们堆叠在一起来应用多个变换。
var t = CGAffineTransform.identity
t = t.translatedBy(x: 100, y: 300)
t = t.rotated(by: CGFloat.pi / 4)
t = t.scaledBy(x: -1, y: 2)
// ... add as many as you want, then apply it to to the view
imageView.transform = t
或更简洁(但不一定具有可读性):
imageView.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 300).rotated(by: CGFloat.pi / 4).scaledBy(x: -1, y: 2)
这一系列的变换产生了右边的图像:
感谢 this answer 教我怎么做。
备注
应用转换的顺序很重要。例如,如果以相反的顺序进行转换,则会产生以下结果。
t = t.scaledBy(x: -1, y: 2) t = t.rotated(by: CGFloat.pi / 4) t = t.translatedBy(x: 100, y: 300)
另见
- CGAffineTransform Reference(文档)
- Transforms(文档)
- Swift: Translating and Rotating a CGContext, A Visual Explanation (iOS/Xcode)
- Demystifying CGAffineTransform
此答案已通过 Swift 4
测试在 Swift 3 中,这些已被 CGAffineTransform 本身的函数所取代,可以链接。
extension CGAffineTransform {
public func translatedBy(x tx: CGFloat, y ty: CGFloat) -> CGAffineTransform
public func scaledBy(x sx: CGFloat, y sy: CGFloat) -> CGAffineTransform
public func rotated(by angle: CGFloat) -> CGAffineTransform
}
例如
let transform = CGAffineTransform(scaleX: 1.0, y: 3.0).translatedBy(x: 12, y: 9).rotated(by: 17.0)
诀窍在于
view.transform.translatedBy(x: 100, y: 100)
没有改变 view.transform
。它只是 returns 您需要分配回 view.transform
的新 CGAffineTransform
。
view.transform = view.transform.translatedBy(x: 100, y: 100)
您可以根据需要多次或按顺序执行此操作
view.transform = view.transform.translatedBy(x: 100, y: 100).rotated(by: CGFloat.pi / 2).scaledBy(x: 2, y: 2)