#3 運用 UIBezierPath 繪製可愛圖案,比方雪人,米奇 & 可愛動物

Mike
彼得潘的 Swift iOS / Flutter App 開發教室
5 min readMar 18, 2023

這邊使用SwiftUI 的繪圖path來做練習並記錄一些重點

快速鍵 cmd + option + p 強迫 SwiftUI 更新預覽畫面。

首先嘗試繪製簡單的三角形

第一件事情要記得手機的座標是從左上角開始

UIBezierPath移動繪製的路徑儲存下來

struct DrawView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView()

// path 這邊只是先把我們想要移動繪製的路徑儲存下來,到這邊並不會執行繪圖
let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 100, y: 0))
path.addLine(to: CGPoint(x: 100, y: 100))
path.close() // 從最後的一個點畫回起始點

return view
}

func updateUIView(_ uiView: UIView, context: Context) {
}

CAShapeLayer

CGPath來定義想要繪製的圖形,最後CAShapeLayer就自動渲染出來

layer.addSublayer

把 CAShapeLayer() 加入到view.layer ,但要記得把UIBezierPath 轉型成CGpath

struct DrawView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView()

let path = UIBezierPath()
path.move(to: CGPoint(x: 0, y: 0))
path.addLine(to: CGPoint(x: 100, y: 0))
path.addLine(to: CGPoint(x: 100, y: 100))
path.close()


let triangleLayer = CAShapeLayer()
triangleLayer.path = path.cgPath
view.layer.addSublayer(triangleLayer)
// layer是在view上面的一層東西,所以這邊在layer上面再加一層圖層並繪製
// 接著返回一整個view

return view
}

CAShapeLayer 繪製形狀內的顏色

triangleLayer.fillColor = CGColor(srgbRed: 0, green: 0, blue: 1, alpha: 1)
// alpha 是透明度

triangleLayer.fillColor = UIColor.clear.cgColor
// 直接清除顏色

客製化線條

triangleLayer.strokeColor = CGColor(srgbRed: 0, green: 0, blue: 1, alpha: 1)
triangleLayer.lineWidth = 10

以上是手動繪圖的部分,接著開始進階方法

Convert SVG path to the UIBezierPath

  1. 把SVG下載下來用sublime打開
  2. 找到下圖的path,複製起來丟到這個網站去解析http://svg-converter.kyome.io/
  3. 解析出來的內容放進程式碼

但是到這邊會發現一個問題,不同尺寸大小的圖片會造成跑圖

解決方法:path.close() 後面使用下面程式碼去移動縮放圖面的大小位置

path.apply(CGAffineTransform.identity.scaledBy(x: 0.7, y:0.7).translatedBy(x: -90, y: 0))

但這個方式無法從根本解決擺放的位置與大小會很容易破圖。

進階++

請參考另一篇文章

結論:
花這麼多篇幅研究這個主題,主要是因為開發時可能顧及到太多圖檔都儲存在APP裡會造成容量肥大,其中之一的解決方法就是由APP來繪製圖案或自製按鈕來符合專案需求。

問題:
UIBezierPath 與 cgPath的差別
UIBezierPath要型成cgPath給CAShapeLayer()使用那為何不一開始就用cgPath

--

--