利用 CAShapeLayer 和 mask 將 View 變成任意形狀

將 View 變成三角形

import UIKitlet frame = CGRect(x: 0, y: 0, width: 100, height: 100)let view = UIView(frame: frame)view.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)let trianglePath = UIBezierPath()var point = CGPoint(x: 0, y: 0)trianglePath.move(to: point)point = CGPoint(x: 100, y: 0)trianglePath.addLine(to: point)point = CGPoint(x: 100, y: 100)trianglePath.addLine(to: point)trianglePath.close()let triangleLayer = CAShapeLayer()triangleLayer.path = trianglePath.cgPathview.layer.mask = triangleLayerview

說明:

1 生成 100 * 100 的紅色正方形

let frame = CGRect(x: 0, y: 0, width: 100, height: 100)let view = UIView(frame: frame)view.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)

2 利用 UIBezierPath 繪製三角形的路徑。

let trianglePath = UIBezierPath()var point = CGPoint(x: 0, y: 0)trianglePath.move(to: point)point = CGPoint(x: 100, y: 0)trianglePath.addLine(to: point)point = CGPoint(x: 100, y: 100)trianglePath.addLine(to: point)

UIBezierPath 可幫助我們繪製路徑。 (0, 0) 為左上角的座標,愈向右 x 愈大,愈向下 y 愈大。因此當我們從 (0, 0) 畫線到 (100, 0),再從 (100, 0) 畫線到 (100, 100),將產生以下路徑。

trianglePath.close()

close() 將從目前所在的 (100, 100) 連線回起點,也就是 (0,0),因此將組合出完美的三角形路徑。

有一點要特別注意的,如果從 playground 點選右邊的大眼睛觀看結果,將發現三角形和剛剛說的不太一樣。這是因為 UIBezierPath 的座標系統和 iOS 的 View 不太一樣,UIBezierPath 的 (0, 0) 在左下角,View 的 (0, 0) 在左上角。由於我們最後的目標是 View,所以記得要以 (0, 0) 在左上角來思考圖形的繪製。

3 生成三角形的 CAShapeLayer 。

let triangleLayer = CAShapeLayer()triangleLayer.path = trianglePath.cgPath

顧名思義,CAShapeLayer 可繪製特定的形狀。我們透過設定它的 path 設定形狀。由於 path 型別是 CGPath,所以我們無法將它設為剛剛產生的三角形路徑 trianglePath(型別為 UIBezierPath),而須從 trianglePath 的屬性 path 得到 CGPath 型別的三角形路徑。

4 將 View 變成三角形。

view.layer.mask = triangleLayerview

記得在最後一行打上 view,這樣才能觀看 view 的模樣。

view.layer.mask = triangleLayer 會將剛剛產生的 triangleLayer 設成紅色正方形 view 的 layer.mask。 透過 layer.mask,紅色正方形只會顯示 mask 裡非透明的區塊。在我們的例子,非透明的區塊即為剛剛 (0, 0),(100, 0),(100,100) 繪製的三角形。

mask 的相關說明:

The layer’s alpha channel determines how much of the layer’s content and background shows through. Fully or partially opaque pixels allow the underlying content to show through but fully transparent pixels block that content.

利用 UIBezierPath 繪製圓形的路徑。

let rect = CGRect(x: 40, y: 40, width: 40, height: 40)let circlePath = UIBezierPath(roundedRect: rect, cornerRadius: 20)

在 View 裡顯示圓形跟三角形

我們可將多個路徑繪製的形狀結合,讓 View 裡顯示圓形跟三角形,例如以下例子。

import UIKitlet frame = CGRect(x: 0, y: 0, width: 100, height: 100)let view = UIView(frame: frame)view.backgroundColor = UIColor(red: 1, green: 0, blue: 0, alpha: 1)let trianglePath = UIBezierPath()var point = CGPoint(x: 0, y: 0)trianglePath.move(to: point)point = CGPoint(x: 100, y: 0)trianglePath.addLine(to: point)point = CGPoint(x: 100, y: 100)trianglePath.addLine(to: point)trianglePath.close()let rect = CGRect(x: 0, y: 40, width: 40, height: 40)let circlePath = UIBezierPath(roundedRect: rect, cornerRadius: 20)trianglePath.append(circlePath)let maskLayer = CAShapeLayer()maskLayer.path = trianglePath.cgPathview.layer.mask = maskLayerview

說明:

結合多個路徑繪製的形狀。

trianglePath.append(circlePath)

我們可將多個 UIBezierPath 結合,透過 append 可加入另一個 UIBezierPath。

將 mask 套用到圖片。

layer.mask 可作用在任何 View,所以當然也可以套用到 image view 上。比方我們將剛剛的三角形 + 圓形 mask 套用到正方形的彼得潘圖片。

結果

import UIKitlet frame = CGRect(x: 0, y: 0, width: 100, height: 100)let imageView = UIImageView(frame: frame)imageView.image = UIImage(named: "peter.jpg")let trianglePath = UIBezierPath()var point = CGPoint(x: 0, y: 0)trianglePath.move(to: point)point = CGPoint(x: 100, y: 0)trianglePath.addLine(to: point)point = CGPoint(x: 100, y: 100)trianglePath.addLine(to: point)trianglePath.close()let rect = CGRect(x: 0, y: 40, width: 40, height: 40)let circlePath = UIBezierPath(roundedRect: rect, cornerRadius: 20)trianglePath.append(circlePath)let maskLayer = CAShapeLayer()maskLayer.path = trianglePath.cgPathimageView.layer.mask = maskLayerimageView

進階研究

繪製曲線路徑

--

--

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

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