應用 SwiftUI Path API 繪製撲克牌的四種花色!
本篇原文(標題:SwiftUI: How to draw playing Cards shades using Path API?)刊登於作者 Medium,由 Prafulla Singh 所著,並授權翻譯及轉載。
在 SwiftUI 中,我們可以利用 Path 和 Shape 來客製化渲染 (rendering),而 Path 又可以用來製作 Shape,也就是說,Path 就是基本的繪圖元素。
在這篇教學文章中,我們將會使用 SwiftUI Path 來建立撲克牌的四種花色。首先,讓我們來看看可以繪製甚麼類型的 Path。
- Line 會添加一條直線。
func addLine(to point: CGPoint)
- Arc 會從中心添加一條圓弧,需要角度、半徑、中心點、和方向的資料。
func addArc(withCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
- Quad Curve 會添加一元二次方程式的曲線。一元二次方程式需要三個點,來繪製一條 Path。

func addQuadCurve(to endPoint: CGPoint, controlPoint: CGPoint)
- Cubic Curve 會添加三次方程式的曲線。一個三次方程式需要四個點,來繪製一條 Path。

func addCurve(to endPoint: CGPoint, controlPoint1: CGPoint, controlPoint2: CGPoint)
現在,讓我們嘗試使用上面的方法,來創建撲克牌花色的圖案。 但是在開始繪製之前,先來介紹一些我們將會在練習中多次使用的函式。
import SwiftUI extension CGRect { /// center of rect var center: CGPoint { return CGPoint(x: self.midX, y: self.midY) } /// if rect is not square take centered square to draw var centeredSquare: CGRect { let width = ceil(min(size.width, size.height)) let height = width let newOrigin = CGPoint(x: origin.x + (size.width - width) / 2, y: origin.y + (size.height - height) / 2) let newSize = CGSize(width: width, height: height) return CGRect(origin: newOrigin, size: newSize) } func flatten() -> (CGFloat, CGFloat, CGFloat, CGFloat) { return (origin.x, origin.y, size.width, size.height) } } extension Angle { static let A180 = Angle(radians: .pi) //180 static let A90 = Angle(radians: .pi/2) //90 static let A270 = Angle(radians: (.pi/2) * 3) //270 static let A360 = Angle(radians: .pi * 2) //360 }
方塊花色 (diamond shade) 是最容易繪製的花色。我們可以使用簡單的 Line、Curve、或 Arc 來繪製。在這個範例中,我們會使用 Arc。
- 移動到底部的中間,或任何一條邊的中間(左側、右側、或頂部)。
- 以角落為中心,向下一條邊的中心繪製圓弧。
import SwiftUI struct Diamond: Shape { func path(in rect: CGRect) -> Path { let (x, y, width, height) = rect.centeredSquare.flatten() let lowerPoint = CGPoint(x: x + width / 2, y: (y + height )) let path = Path { p in p.move(to: lowerPoint) p.addArc(center: CGPoint(x: x, y: (y + height)), radius: (width / 2), startAngle: .A360, endAngle: .A270, clockwise: true) p.addArc(center: CGPoint(x: x, y: y), radius: (width / 2), startAngle: .A90, endAngle: .zero, clockwise: true) p.addArc(center: CGPoint(x: x + width, y: y), radius: (width / 2), startAngle: .A180, endAngle: .A90, clockwise: true) p.addArc(center: CGPoint(x: x + width, y: y + height), radius: (width / 2), startAngle: .A270 , endAngle: .A180, clockwise: true) } return path } }
紅心花色 (heart shade) 是兩條 Cubic Curve 和兩條 Arc 的組合。
- 移動到底部的中間。
- 向左邊或右邊中間繪製 Cubic Curve,保持角度在45度。
- 從上一點繪製一條 180° 的 Arc,半徑為寬度的 25%,中心則為長度和寬度的 25%。
- 反向重複,也就是重複第三步、第二步。
import SwiftUI struct Heart: Shape { func path(in rect: CGRect) -> Path { let (x, y, width, height) = rect.centeredSquare.flatten() let lowerPoint = CGPoint(x: x + width / 2, y: (y + height )) let path = Path { p in p.move(to: lowerPoint) p.addCurve(to: CGPoint(x: x, y: (y + (height / 4))), control1: CGPoint(x: (x + (width / 2)), y: (y + (height * 3 / 4))), control2: CGPoint(x: x, y: (y + (height / 2)))) p.addArc(center: CGPoint(x: (x + (width / 4)), y: (y + (height / 4))), radius: (width / 4), startAngle: .A180, endAngle: .zero, clockwise: false) p.addArc(center: CGPoint(x: (x + (width * 3 / 4)), y: (y + (height / 4))), radius: (width / 4), startAngle: .A180, endAngle: .zero, clockwise: false) p.addCurve(to: lowerPoint, control1: CGPoint(x: (x + width), y: (y + (height / 2))), control2: CGPoint(x: (x + (width / 2)), y: (y + (height * 3 / 4)))) } return path } }
我們可以組合紅心花色和長方型,來完成黑桃花色 (Spade Shade)。
- 利用 90% 高度建立一個心形。
- 把心形旋轉 180°,並獲取 Path。
- 從中心到底部的中心建立一個長方形,並設定適當的寬度。
- 合併兩條 Path。
import SwiftUI struct Spade: Shape { func path(in rect: CGRect) -> Path { let (x, y, width, height) = rect.centeredSquare.flatten() var heartPath = Heart().rotation(.A180).path(in: CGRect(x: x, y: y, width: width, height: height * 0.9)) //take 10% for bottom rect let rectPath = Rectangle().path(in: CGRect(x: x + width * 0.4, y: y + height * 0.5, width: width * 0.2, height: height * 0.5)) heartPath.addPath(rectPath) return heartPath } }
梅花花色 (Club Shade) 就是由三個圓形和一個三角形組成的。
- 將 rect 分成 2×2 網格
- 以 0-1 網格的交叉點為直徑,繪製一個圓形
- 以 0-2 網格的交叉點為直徑,繪製一個圓形
- 以 1-3 網格的交叉點為直徑,繪製一個圓形
- 從中心到底部繪製一個 60° 的等邊三角形
import SwiftUI struct Club: Shape { func path(in rect: CGRect) -> Path { let (x, y, width, height) = rect.centeredSquare.flatten() let center = rect.centeredSquare.center let center1 = CGPoint(x: x + width / 2, y: (y + height/4 )) let center2 = CGPoint(x: x + width / 4, y: (y + height/2 )) let center3 = CGPoint(x: x + width * 3 / 4, y: (y + height/2 ) ) let radius = (width / 4) let path = Path { p in p.move(to: center) p.addArc(center: center1, radius: radius, startAngle: .A360, endAngle: .zero, clockwise: true) p.addArc(center: center2, radius: radius, startAngle: .A360, endAngle: .zero, clockwise: true) p.addArc(center: center3, radius: radius, startAngle: .A360, endAngle: .zero, clockwise: true) p.move(to: center) p.addLine(to: CGPoint(x: x + width / 4, y: y + height)) p.addLine(to: CGPoint(x: x + width * 3 / 4, y: y + height)) p.addLine(to: center) } return path } }
你可以在 GitHub 上參考完整範例。
本篇原文(標題:SwiftUI: How to draw playing Cards shades using Path API?)刊登於作者 Medium,由 Prafulla Singh 所著,並授權翻譯及轉載。
作者簡介:Prafulla Singh,Block.one 的 iOS 開發者
譯者簡介:Kelly Chan-AppCoda 編輯小姐。
iOS
下一篇
利用 Swift 在 iOS 構建獨特漂亮的 QR code 視圖
iOS