SwiftUIの組み込み形状
SwiftUI’s built-in shapes
SwiftUIには、一般的に使用される5つの組み込み形状(長方形、角丸長方形、円、楕円、カプセル)が用意されています。特に最後の3つは、提供するサイズに基づいて動作が微妙に異なりますが、1つの例ですべてのオプションを示すことができます。
//-----------------------------------
struct ContentView: View {
var body: some View {
ZStack {
Rectangle()
.fill(Color.black)
.frame(width: 200, height: 200)
RoundedRectangle(cornerRadius: 25, style: .continuous)
//RoundedRectangle(cornerRadius: 25, style: .circular)
.fill(Color.red)
.frame(width: 200, height: 200)
Capsule()
.fill(Color.green)
.frame(width: 100, height: 50)
Ellipse()
.fill(Color.blue)
.frame(width: 100, height: 50)
Circle()
.fill(Color.white)
.frame(width: 100, height: 50)
}
}
}
//-----------------------------------
カスタムパスを描画する方法
How to draw a custom path
//-----------------------------------
struct SpiroSquare: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let rotations = 5
let amount = .pi / CGFloat(rotations)
let transform = CGAffineTransform(rotationAngle: amount)
for _ in 0 ..< rotations {
path = path.applying(transform)
path.addRect(CGRect(x: -rect.width / 2, y: -rect.height / 2, width: rect.width, height: rect.height))
}
return path
}
}
//-----------------------------------
//-----------------------------------
struct SpiroSquare: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let rotations = 4
let amount = .pi / CGFloat(rotations)
let transform = CGAffineTransform(rotationAngle: amount)
for _ in 0 ..< rotations {
path = path.applying(transform)
path.addRect(CGRect(x: 0, y: 0, width: rect.width, height: rect.height))
}
return path
}
}
//-----------------------------------
struct ContentView: View {
var body: some View {
VStack{
SpiroSquare()
.stroke()
.frame(width: 100, height: 50)
// SpiroSquare()
// .stroke()
// .frame(width: 50, height: 50)
}
}
}
//-----------------------------------
struct ContentView: View {
var body: some View {
VStack{
HStack{
Spacer()
SpiroSquare()
.stroke()
.frame(width: 200, height: 200)
}
}
}
}
//———————————–
上について、パスの基準点がよく分からなかったので、以下試行。中央に描画された四角形が時計方向に回転する。
//-----------------------------------
struct SpiroSquare: Shape {
func path(in rect: CGRect) -> Path {
var path = Path()
let rotations = 4
let amount = .pi / CGFloat(rotations)
let transform = CGAffineTransform(rotationAngle: amount)
for _ in 0 ..< rotations {
path = path.applying(transform)
path.addRect(CGRect(x: 0, y: 0, width: rect.width, height: rect.height))
}
return path
}
}
//-----------------------------------
struct ContentView: View {
var body: some View {
VStack{
SpiroSquare()
.stroke()
.frame(width: 100, height: 50)
// SpiroSquare()
// .stroke()
// .frame(width: 50, height: 50)
}
}
}
//-----------------------------------
関連リンク
SwiftUIでカスタムパスを作成する
ポリゴンと星の描き方
How to draw polygons and stars
SwiftUIの基本的なパス描画システムを理解すると、あらゆる種類の形状を簡単に追加できます。たとえばStar、ほんの少しの数学で、さまざまな星の形や他のポリゴンを表現できる形を作成できます。
//-----------------------------------
struct Star: Shape {
// store how many corners the star has, and how smooth/pointed it is
let corners: Int
let smoothness: CGFloat
func path(in rect: CGRect) -> Path {
// ensure we have at least two corners, otherwise send back an empty path
guard corners >= 2 else { return Path() }
// draw from the center of our rectangle
let center = CGPoint(x: rect.width / 2, y: rect.height / 2)
// start from directly upwards (as opposed to down or to the right)
var currentAngle = -CGFloat.pi / 2
// calculate how much we need to move with each star corner
let angleAdjustment = .pi * 2 / CGFloat(corners * 2)
// figure out how much we need to move X/Y for the inner points of the star
let innerX = center.x * smoothness
let innerY = center.y * smoothness
// we're ready to start with our path now
var path = Path()
// move to our initial position
path.move(to: CGPoint(x: center.x * cos(currentAngle), y: center.y * sin(currentAngle)))
// track the lowest point we draw to, so we can center later
var bottomEdge: CGFloat = 0
// loop over all our points/inner points
for corner in 0..<corners * 2 {
// figure out the location of this point
let sinAngle = sin(currentAngle)
let cosAngle = cos(currentAngle)
let bottom: CGFloat
// if we're a multiple of 2 we are drawing the outer edge of the star
if corner.isMultiple(of: 2) {
// store this Y position
bottom = center.y * sinAngle
// …and add a line to there
path.addLine(to: CGPoint(x: center.x * cosAngle, y: bottom))
} else {
// we're not a multiple of 2, which means we're drawing an inner point
// store this Y position
bottom = innerY * sinAngle
// …and add a line to there
path.addLine(to: CGPoint(x: innerX * cosAngle, y: bottom))
}
// if this new bottom point is our lowest, stash it away for later
if bottom > bottomEdge {
bottomEdge = bottom
}
// move on to the next corner
currentAngle += angleAdjustment
}
// figure out how much unused space we have at the bottom of our drawing rectangle
let unusedSpace = (rect.height / 2 - bottomEdge) / 2
// create and apply a transform that moves our path down by that amount, centering the shape vertically
let transform = CGAffineTransform(translationX: center.x, y: center.y + unusedSpace)
return path.applying(transform)
}
}
//-----------------------------------
struct ContentView: View {
var body: some View {
Star(corners: 5, smoothness: 0.2)
//.fill(Color.red)
.frame(width: 400, height: 400)
//.background(Color.green)
}
}
//-----------------------------------
チェッカーボードの描き方
How to draw a checkerboard
SwiftUIのパスは、連続した孤立した形状である必要はなく、代わりに複数の長方形、楕円などをすべて1つにまとめることができます。
これを示す簡単な方法として、次のように、設定された数の行と列の一連の長方形を作成することにより、市松模様を作成する形状を作成できます。
//-----------------------------------
struct Checkerboard: Shape {
let rows: Int
let columns: Int
func path(in rect: CGRect) -> Path {
var path = Path()
// figure out how big each row/column needs to be
let rowSize = rect.height / CGFloat(rows)
let columnSize = rect.width / CGFloat(columns)
// loop over all rows and columns, making alternating squares colored
for row in 0 ..< rows {
for column in 0 ..< columns {
//Swift5の新機能 isMultiple
// ある数が別の数の倍数であるかどうかを確認
if (row + column).isMultiple(of: 2) {
// this square should be colored; add a rectangle here
let startX = columnSize * CGFloat(column)
let startY = rowSize * CGFloat(row)
let rect = CGRect(x: startX, y: startY, width: columnSize, height: rowSize)
path.addRect(rect)
}
}
}
return path
}
}
//-----------------------------------
struct ContentView: View {
var body: some View {
Checkerboard(rows: 16, columns: 16)
.fill(Color.red)
.frame(width: 200, height: 200)
}
}
//-----------------------------------
SwiftUIでUIBezierPathとCGPathを使用する方法
How to use UIBezierPath and CGPath in SwiftUI
//-----------------------------------
struct ScaledBezier: Shape {
let bezierPath: UIBezierPath
func path(in rect: CGRect) -> Path {
let path = Path(bezierPath.cgPath)
// Figure out how much bigger we need to make our path in order for it to fill the available space without clipping.
let multiplier = min(rect.width, rect.height)
// Create an affine transform that uses the multiplier for both dimensions equally.
let transform = CGAffineTransform(scaleX: multiplier, y: multiplier)
// Apply that scale and send back the result.
return path.applying(transform)
}
}
//-----------------------------------
struct ContentView: View {
var body: some View {
ScaledBezier(bezierPath: .logo)
.stroke(lineWidth: 2)
.frame(width: 200, height: 200)
}
}
//-----------------------------------
extension UIBezierPath {
/// The Unwrap logo as a Bezier path.
static var logo: UIBezierPath {
let path = UIBezierPath()
// 始点
path.move(to: CGPoint(x: 0.534, y: 0.5816))
// 次のto:が終点 + 二つのコントロールポイント
path.addCurve(to: CGPoint(x: 0.1877, y: 0.088), controlPoint1: CGPoint(x: 0.534, y: 0.5816), controlPoint2: CGPoint(x: 0.2529, y: 0.4205))
path.addCurve(to: CGPoint(x: 0.9728, y: 0.8259), controlPoint1: CGPoint(x: 0.4922, y: 0.4949), controlPoint2: CGPoint(x: 1.0968, y: 0.4148))
path.addCurve(to: CGPoint(x: 0.0397, y: 0.5431), controlPoint1: CGPoint(x: 0.7118, y: 0.5248), controlPoint2: CGPoint(x: 0.3329, y: 0.7442))
path.addCurve(to: CGPoint(x: 0.6211, y: 0.0279), controlPoint1: CGPoint(x: 0.508, y: 1.1956), controlPoint2: CGPoint(x: 1.3042, y: 0.5345))
path.addCurve(to: CGPoint(x: 0.6904, y: 0.3615), controlPoint1: CGPoint(x: 0.7282, y: 0.2481), controlPoint2: CGPoint(x: 0.6904, y: 0.3615))
return path
}
}
//-----------------------------------
addCurveは、形状の右側に表示される曲線を作成するメソッドです。曲線は次のようなものです。
3つの引数が必要です。曲線の最終点(終点)と、線の曲率を実際に定義する2つの制御点です。
始点は1つ前の終点で、今回はposAが始点になります。
【Swift3】UIBezierPathで卵型を書こう【CAShapeLayer】
SwiftUIのビューサイズにあわせてPathを表示する
ベジエパスとシェイプレイヤーのビギナーズガイド






