Notice
Recent Posts
Recent Comments
Link
관리 메뉴

김종권의 iOS 앱 개발 알아가기

[iOS - SwiftUI] 2. Canvas 사용 방법 (fill, stroke) 본문

카테고리 없음

[iOS - SwiftUI] 2. Canvas 사용 방법 (fill, stroke)

jake-kim 2025. 1. 2. 01:10

1. Canvas 개념 (그림 그리기, Path)

2. Canvas 사용 방법 (fill, stroke)

 

이전 글에서 알아본 대로 (아래처럼 Canvas를 선언하여 사용 준비)

struct ContentView: View {
    var body: some View {
        Canvas(
            opaque: true,
            colorMode: .linear,
            rendersAsynchronously: false
        ) { context, size in
            context.opacity = 0.3
            ...
        }
        .frame(width: 300, height: 500)
    }
}

fill을 사용하여 그리기

Canvas로 표현한 사각형

  • context.fill(_:with:)을 사용하면 path만큼 안쪽을 채우는 효과가 있는데, 이것을 사용하면 원하는 도형을 쉽게 표현이 가능
public func fill(_ path: Path, with shading: GraphicsContext.Shading, style: FillStyle = FillStyle())
  • 먼저 rect를 선언하여 그림을 그릴 전체 범위를 준비
struct ContentView: View {
    var body: some View {
        Canvas(
            opaque: true,
            colorMode: .linear,
            rendersAsynchronously: false
        ) { context, size in
            context.opacity = 0.3
            let rect = CGRect(origin: .zero, size: size)
            
        }
        .frame(width: 300, height: 500)
    }
}
  • context.fill을 사용하면 만들어준 path만큼 안쪽을 채우는 효과가 있는 형태
struct ContentView: View {
    var body: some View {
        Canvas(
            opaque: true,
            colorMode: .linear,
            rendersAsynchronously: false
        ) { context, size in
            context.opacity = 0.3
            let rect = CGRect(origin: .zero, size: size)
            
            // 1. size
            let targetRect = rect.applying(.init(scaleX: 1, y: 1))
            // 2. path
            let path = Rectangle().path(in: targetRect)
            // 3. draw
            context.fill(path, with: .color(.green))
        }
        .frame(width: 300, height: 500)
    }
}

stroke를 사용하여 그리기

  • stroke를 사용하면 넣어준 path만큼 그림을 그리기 쉽기 때문에 원하는 그림을 그릴때 사용
public func stroke(_ path: Path, with shading: GraphicsContext.Shading, style: StrokeStyle)

  • 코드를 추가하여 삼각형 그리기

위에서 사각형을 그린 전체 코드)

struct ContentView: View {
    var body: some View {
        Canvas(
            opaque: true,
            colorMode: .linear,
            rendersAsynchronously: false
        ) { context, size in
            context.opacity = 0.3
            
            let rect = CGRect(origin: .zero, size: size)
            
            // # fill
            // size
            let targetRect = rect.applying(.init(scaleX: 1, y: 1))
            // path
            let path = Rectangle().path(in: targetRect)
            // draw
            context.fill(path, with: .color(.green))
            
            // # stroke
            // TODO...
        }
        .frame(width: 300, height: 500)
    }
}
  • 항상 path를 그릴때는 꼭지점을 알면 모두 그릴 수 있으므로, 삼각형 꼭지점 3개를 구하는 것을 목표로 코딩
    • 삼각형 꼭지점 3개를 구하기 위해서, 중앙 좌표를 구한 후, 그 중앙 좌표로 부터 50만큼 떨어져 있는 꼭지점을 구한 후 path로 그리는 것
    • SwiftUI의 Path를 사용하여 구현
// # stroke
let center = CGPoint(x: size.width / 2, y: size.height / 2)
// 반지름 50
let radius: CGFloat = 50
let trianglePath = Path { path in
    // 삼각형의 꼭짓점 계산: 3등분하여 각 꼭지점 각도 구하기
    let points = (0..<3).map { i -> CGPoint in
        let angle = CGFloat(i) * (2.0 * .pi / 3.0) - .pi / 2.0
        return CGPoint(
            x: center.x + radius * cos(angle),
            y: center.y + radius * sin(angle)
        )
    }
    
    path.move(to: points[0])
    for point in points.dropFirst() {
        path.addLine(to: point)
    }
    path.closeSubpath()
}
  • 이 path를 context.stroke에 넘기면 완성
context.stroke(
    trianglePath,
    with: .color(.black),
    style: .init(
        lineWidth: 5,
        lineCap: .round,
        lineJoin: .round
    )
)

 

* 전체 코드

import SwiftUI

struct ContentView: View {
    var body: some View {
        Canvas(
            opaque: true,
            colorMode: .linear,
            rendersAsynchronously: false
        ) { context, size in
            context.opacity = 0.3
            
            let rect = CGRect(origin: .zero, size: size)
            
            // # fill
            // size
            let targetRect = rect.applying(.init(scaleX: 1, y: 1))
            // path
            let path = Rectangle().path(in: targetRect)
            // draw
            context.fill(path, with: .color(.green))
            
            // # stroke
            let center = CGPoint(x: size.width / 2, y: size.height / 2)
            // 반지름 50
            let radius: CGFloat = 50
            let trianglePath = Path { path in
                // 삼각형의 꼭짓점 계산: 3등분하여 각 꼭지점 각도 구하기
                let points = (0..<3).map { i -> CGPoint in
                    let angle = CGFloat(i) * (2.0 * .pi / 3.0) - .pi / 2.0
                    // center기준으로 반지름에
                    return CGPoint(
                        x: center.x + radius * cos(angle),
                        y: center.y + radius * sin(angle)
                    )
                }
                
                // 그림 그리기
                path.move(to: points[0])
                for point in points.dropFirst() {
                    path.addLine(to: point)
                }
                path.closeSubpath()
            }
            
            context.stroke(
                trianglePath,
                with: .color(.black),
                style: .init(
                    lineWidth: 5,
                    lineCap: .round,
                    lineJoin: .round
                )
            )
        }
        .frame(width: 300, height: 500)
    }
}

#Preview {
    ContentView()
}
Comments