利用 CGAffineTransform 縮放,位移,旋轉和鏡像翻轉

利用 CGAffineTransform 我們可以像魔法師般對 view 下魔法,控制 view 的 transform property,要它聽話地縮放,位移和旋轉。(transform 的中文是轉換的意思)

接下來就讓我們好好來認識它,施展魔法讓彼得潘縮放,位移和旋轉吧。

override func viewDidLoad() {
super.viewDidLoad()
let imageView = UIImageView(image: UIImage(named: "peter"))
view.addSubview(imageView)
}

搭配 scale 縮放

利用 CGAffineTransform 的 init(scaleX:y:) 產生縮放的 CGAffineTransform,參數 scaleX & y 分別傳入縮放的比例,因此以下程式將讓圖片的寬高變成原來的兩倍。

imageView.transform = CGAffineTransform(scaleX: 2, y: 2)

我們也可以先用 CGAffineTransform.identity 產生沒有套用任何效果的 CGAffineTransform,然後再呼叫 function scaledBy(x:y:),產生縮放的效果。

imageView.transform = CGAffineTransform.identity.scaledBy(x: 2, y: 2)

鏡像翻轉(mirror)

當我們利用 scale 參數縮放大小時,傳入負數還可以實現有趣的鏡像翻轉效果。比方以下例子的 scaleX 傳入 -1 時,圖片將維持原本的寬度,但變成鏡像左右翻轉。

let imageView = UIImageView(image: UIImage(named: "peter"))
view.addSubview(imageView)

let mirrorImageView = UIImageView(image: UIImage(named: "peter"))
mirrorImageView.frame.origin.x = imageView.frame.maxX + 10
mirrorImageView.transform = CGAffineTransform(scaleX: -1, y: 1)
view.addSubview(mirrorImageView)

若是將 scale 的 y 設為 -1,則會變成圖片維持原本的高度,但變成鏡像上下翻轉。

mirrorImageView.transform = CGAffineTransform(scaleX: 1, y: -1)

搭配 translation 位移

利用 CGAffineTransform 的 init(translationX:y:) 產生位移的 CGAffineTransform,參數 translationX & y 分別傳入水平和垂直移動的距離,因此以下程式將讓圖片向右移動 100,向下移動 300 points。

imageView.transform = CGAffineTransform(translationX: 100, y: 300)

我們也可以先用 CGAffineTransform.identity 產生沒有套用任何效果的 CGAffineTransform,然後再呼叫 function translatedBy(x:y:),產生位移的效果。

imageView.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 300)

搭配 rotationAngle 旋轉

利用 CGAffineTransform 的 init(rotationAngle:) 產生旋轉的 CGAffineTransform,參數 rotationAngle 傳入旋轉的弧度。

角度 1 度對應弧度 π / 180。因此以下程式將讓彼得潘旋轉 45 度,展現最帥氣的角度。

let oneDegree = CGFloat.pi / 180
imageView.transform = CGAffineTransform(rotationAngle: oneDegree * 45)

我們也可以先用 CGAffineTransform.identity 產生沒有套用任何效果的 CGAffineTransform,然後再呼叫 function rotated(by:),產生 旋轉的效果。

let oneDegree = CGFloat.pi / 180
imageView.transform = CGAffineTransform.identity.rotated(by: oneDegree * 45)

結合縮放,位移和旋轉

結合縮放,位移和旋轉時,順序很重要,因為背後牽扯到矩陣的數學運算,所以先位移再縮放跟先縮放再位移是不一樣的。

  • 方法 1
let oneDegree = CGFloat.pi / 180
imageView.transform = CGAffineTransform.identity.translatedBy(x: 100, y: 300).scaledBy(x: 0.5, y: 0.5).rotated(by: oneDegree * 45)
  • 方法 2

使用 concatenating 串接 transform。一樣要特別注意順序問題,以下程式的結果跟方法 1 一樣,不過是用 rotateTransform concatenating scaleTransform,然後再 concatenating translateTransform。

let oneDegree = CGFloat.pi / 180
let translateTransform = CGAffineTransform(translationX: 100, y: 300)
let scaleTransform = CGAffineTransform(scaleX: 0.5, y: 0.5)
let rotateTransform = CGAffineTransform(rotationAngle: oneDegree * 45)
imageView.transform = rotateTransform.concatenating(scaleTransform).concatenating(translateTransform)

沒有任何效果的 CGAffineTransform

讓圖片呈現原本的模樣。

imageView.transform = CGAffineTransform.identity

練習

定義 function 運用 UIBezierPath 繪製可愛圖案,然後在 viewDidLoad 裡呼叫 function 多次,調整圖案的縮放,位移和旋轉。

範例:

參考以下連結 Ting 同學繪製的 Apple,將她的程式寫在 function addAppleView 裡。

func addAppleView(moveX: CGFloat, moveY: CGFloat, rotateDegree: CGFloat, scale: CGFloat) {
// 此處請貼上 Ting 同學繪製 Apple 的程式
let oneDegree = CGFloat.pi / 180
flagBackground.transform = CGAffineTransform.identity.translatedBy(x: moveX, y: moveY).scaledBy(x: scale, y: scale).rotated(by: oneDegree * rotateDegree)
view.addSubview(flagBackground)
}

在 viewDidLoad 裡呼叫 function addAppleView。

override func viewDidLoad() {
super.viewDidLoad()
addAppleView(moveX: -30, moveY: -80, rotateDegree: 45, scale: 2)
addAppleView(moveX: 0, moveY: 20, rotateDegree: 70, scale: 0.75)
addAppleView(moveX: 30, moveY: 100, rotateDegree: 90, scale: 0.5)
}

--

--

彼得潘的 iOS App Neverland
彼得潘的 Swift iOS App 開發問題解答集

彼得潘的iOS App程式設計入門,文組生的iOS App程式設計入門講師,彼得潘的 Swift 程式設計入門,App程式設計入門作者,http://apppeterpan.strikingly.com