在SwiftUI中,可以使用“路径”和“形状”实现自定义渲染。 可以通过路径创建形状。 这使“路径”成为基本的绘图元素。
在本教程中,我们将使用Path来创建不同色调的扑克牌。 Path的使用参见《SwiftUI从入门到实战》第2章的第25节:通过Path路径绘制不规则的线条和图形 。
首先,让我们学习可以绘制的路径类型。
- Line 追加一条直线
func addLine(to point: CGPoint)
- Arc 相对于中心附加弧线。 需要角度,半径,中心点和方向。
func addArc(withCenter center: CGPoint, radius: CGFloat, startAngle: CGFloat, endAngle: CGFloat, clockwise: Bool)
- Quad Curve 将曲线添加为二次方程式。 二次方程需要三个点才能绘制路径。
func addQuadCurve(to endPoint: CGPoint, controlPoint: CGPoint)
- Cubic Curve 将曲线添加为三次方程。 三次方程式需要四个点才能绘制路径。
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 }
钻石阴影是最容易绘制的阴影。 我们可以使用简单的直线,Curve或Arc来实现。 对于此演示,我们将使用Arcs。
1.移动到底部的中心或任何居中的边缘(左侧,右侧或顶部) 2.保持拐角为中心,在下一个居中边缘绘制圆弧
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 } }
爱心图形是两条三次曲线和两条弧线的组合。
1.移至中心底部 2.绘制左中心或右中心的三次曲线。 将控件保持在45度角。 3.从最后一点以半径和中心为25%的宽度到宽度和高度为25%绘制180°弧线。 4.反向重复,即3-2
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 } }
.
可以通过将心形阴影形状与矩形合并来构建黑桃阴影。
1.创建高度为90%的心形 2.旋转心脏并获取路径 3.以适当的宽度从中心到底部中心创建矩形 4.合并两条路径
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 } }
梅花底纹,三个圆和一个三角形。
1.将rect分成2x2网格 2.以0-1网格相交处绘制一个圆作为直径 3.画一个圆,以0-2的网格相交为直径 4.画一个与1-3网格相交的圆作为直径 5.从中心到底部绘制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 } }
完整 Demo:
prafullakumar/DemoPlayingCard
译自:https://medium.com/dev-genius/swiftui-how-to-draw-playing-cards-shades-using-path-api-f2d6c5425af1