#21 運用 UIBezierPath 繪製可愛貓貓蟲咖波
我們要運用 UIBezierPath 來繪製可愛的「貓貓蟲咖波」
上圖是完成圖,雖看起來是線條簡單的插畫,程式碼卻很長很長啊~
說實在為了做這個作業我看了十幾二十篇的文章,這是一個需要耐心的作業。
因為每個線段手刻實在太耗時了,我如果用繪圖軟體做的話二三下就完成了,本來為了偷懶還想直接用 SVG Converter 把 SVG 檔轉成 Swift 的格式。
SVG Converter 把 SVG 檔轉為 Swift 語法的網站
但是!事情永遠沒有那麼簡單,轉簡單的 icon 線條還可以,但是「貓貓蟲咖波」線條太多轉出來都是壞掉的啊啊啊啊~
其實 fontawesome 下載的很多 SVG Icon 檔,透過 SVG Converter 轉存出來都是圖案破碎的。
只好回到原點乖乖拉線,做「貓貓蟲咖波」之前還做了很多熱身練習,例如畫三角形、畫西瓜、直線星星、曲線星星…,然後彼得潘的文章裡沒有畫曲線的星星過程,只有提供方法,只能自己研究摸索畫出的方式。
畫曲線有幾個方式,我用的是 addQuadCurve
來畫曲線星星。
構建路徑用到的幾種語法
func move(to: CGPoint)
將路徑的當前點移動到指定位置。func addLine(to: CGPoint)
在路徑上附加一條直線。func addArc(withCenter: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
在路徑上附加一個弧線。(圓形)func addCurve(to: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
在路徑上附加一條立方貝塞爾曲線。func addQuadCurve(to endPoint:CGPoint, controlPoint:CGPoint)
在路徑上附加一條二次貝塞爾曲線func removeAllPoints()
從路徑中刪除所有點,有效地刪除所有子路徑。func append(UIBezierPath)
將指定路徑對象的內容附加到路徑中。var cgPath: CGPath
路徑的核心圖形表示。var currentPoint: CGPoint
圖形路徑中的當前點。
建立 SwiftUI App 專案
建立專案時,這次 Interface 選擇 SwiftUI。
在 ContentView.swift 貼上以下程式
將 ContentView.swift 原本的程式刪除,貼上以下程式。以下程式將利用 SwiftUI 幫我們預覽繪製的圖案。此次作業的重點在繪圖,所以不懂以下程式沒關係。
以下是基礎架構
import SwiftUI
struct DrawView: UIViewRepresentable {
func makeUIView(context: Context) -> UIView {
let view = UIView()
return view
}
func updateUIView(_ uiView: UIView, context: Context) {
}
}
struct ContentView: View {
var body: some View {
DrawView()
}
}
struct ContentView_Previews: PreviewProvider {
static var previews: some View {
ContentView()
}
}
選擇要模擬的「貓貓蟲咖波」圖片原檔
載入圖片在背景,方便描圖參考
let imageView = UIImageView(frame: CGRect(x: 0, y: 0, width: 330, height: 210))
imageView.image = UIImage(named: "貓貓蟲咖波")
imageView.alpha = 0.0
view.addSubview(imageView)
描繪中
座標參考是把圖片匯入 Figma 取得轉折點座標, 再取得曲線位置的初步座標進去 Swift 調整,因為如果採用繪圖軟體的貝茲曲線座標,曲線會太扁,須在 Swift 慢慢微調
或是將圖片上傳到查詢座標顏色的網站 iview
參考圖片繪圖時最困難的莫過於如何得知圖片裡形狀的座標和顏色。不過別擔心,我們只要將圖片上傳,即可查詢圖片的座標顏色。(ps: 如果覺得圖片太小不容易查座標,可按 cmd + 將網頁放大。)
https://yangcha.github.io/iview/iview.html
整理需要單獨繪製的形狀
- 二隻前腳另外畫,因為線條沒封包
- 頭頂曲線
- 眼睛
- 嘴巴
- 背上的藍線
- 肚子的白色
- 背景裝飾圖案三個曲線和音符和地平線
初步完成身體外框線條繪製
身體外框的程式碼
完整的程式碼請下載下方的 GitHub
// 曲線咖波
let path = UIBezierPath()
path.move(to: CGPoint(x: 118, y: 63))
path.addQuadCurve(to: CGPoint(x: 163, y: 56), controlPoint: CGPoint(x: 153, y: 20))
path.addQuadCurve(to: CGPoint(x: 173, y: 60), controlPoint: CGPoint(x: 168, y: 58))
path.addQuadCurve(to: CGPoint(x: 211, y: 75), controlPoint: CGPoint(x: 218, y: 26))
path.addQuadCurve(to: CGPoint(x: 229, y: 79), controlPoint: CGPoint(x: 216, y: 79))
path.addQuadCurve(to: CGPoint(x: 242, y: 86), controlPoint: CGPoint(x: 236, y: 72))
path.addQuadCurve(to: CGPoint(x: 235, y: 144), controlPoint: CGPoint(x: 246, y: 118))
path.addQuadCurve(to: CGPoint(x: 222, y: 153), controlPoint: CGPoint(x: 240, y: 161))
path.addQuadCurve(to: CGPoint(x: 203, y: 156), controlPoint: CGPoint(x: 211, y: 156))
path.addQuadCurve(to: CGPoint(x: 189, y: 154), controlPoint: CGPoint(x: 185, y: 171))
path.addQuadCurve(to: CGPoint(x: 164, y: 157), controlPoint: CGPoint(x: 175, y: 157))
path.addQuadCurve(to: CGPoint(x: 114, y: 143), controlPoint: CGPoint(x: 130, y: 155))
path.addQuadCurve(to: CGPoint(x: 118, y: 63), controlPoint: CGPoint(x: 66, y: 107))// 填色
let capooLayer = CAShapeLayer()
capooLayer.path = path.cgPath
// 繪製完成前暫時不填色
capooLayer.fillColor = UIColor.clear.cgColor
capooLayer.strokeColor = CGColor(srgbRed: 90/255, green: 80/255, blue: 94/255, alpha: 1)
capooLayer.lineWidth = 5
view.layer.addSublayer(capooLayer)
調整線條端點形狀
最後,有一些開放式的線條端點都是直角的,我們要把它改成圓形
我們可以設定 CAShapeLayer 的 lineCap,調整線條端點的形狀,比方 .round 代表圓形。
percentageLayer.lineCap = .round
本來想讓咖波的腳可以動,但是那又是另一個坑,等以後比較熟悉再來改寫
血汗「貓貓蟲咖波」最終完成的樣子,感動😭
你這可惡又可愛的小東西,讓我花了那麼多時間還笑得這麼開心,果然不能小看咖波。