UIBezierPath: 개념, 드로잉 메서드 및 작동 방식

저자: IT Sectr 게시일: 2026-07-21 읽는 시간: 8 분

UIBezierPath는 iOS에서 2D 그래픽을 위한 벡터 경로를 캡슐화하는 UIKit 클래스입니다. 윤곽선의 기하학적 설명과 그리기 기능을 결합하여 선, 베지어 곡선, 호 및 사각형을 만들 수 있습니다. CGPath와 달리 UIBezierPath는 현재 그래픽 컨텍스트에서 직접 작동하는 자체 그리기 메서드를 포함합니다. Apple Developer Documentation, 2026에 따르면 UIBezierPath는 객체 지향 래퍼에서 모든 표준 Quartz 2D 작업을 지원합니다.

주요 포인트

  • UIBezierPath는 UIKit에서 벡터 경로를 작업하기 위한 CGPath의 객체 지향 래퍼입니다.
  • move(to:)addLine(to:)는 경로의 직선 세그먼트를 정의합니다.
  • addQuadCurve(to:controlPoint:)addCurve(to:controlPoint1:controlPoint2:)는 베지어 곡선을 구성합니다.
  • addArc(withCenter:radius:startAngle:endAngle:clockwise:)는 호와 섹터를 생성합니다.
  • fillstroke는 추가 객체 없이 현재 컨텍스트에서 직접 경로를 그립니다.

UIBezierPath란?

UIBezierPath는 UIKit 프레임워크의 클래스로, NSObject를 상속하고 NSCopying, NSSecureCoding을 구현합니다. 벡터 경로를 생성하고 그리기 위한 고수준 Objective-C/Swift API를 제공합니다. 내부적으로 UIBezierPath는 CGPathRef(Core Graphics 객체)에 대한 참조를 저장하지만 그리기, 지오메트리 수정 및 스타일 관리를 위한 편리한 메서드를 추가합니다.

CGPath를 직접 사용하는 것과 비교한 UIBezierPath의 주요 장점은 내장된 그리기 메서드입니다. UIBezierPath 인스턴스에서 fill() 또는 stroke()를 호출하면 자동으로 컨텍스트가 구성되고 경로가 그려집니다. 이 클래스는 lineWidth, lineCapStyle, lineJoinStyle, miterLimit 및 flatness 속성도 지원하여 스타일 저장을 위한 별도 객체 없이 외관을 제어할 수 있습니다.

UIBezierPath는 대부분의 iOS 애플리케이션에서 UIView 내부의 사용자 정의 그리기에 사용됩니다. 간단한 아이콘부터 복잡한 애니메이션 차트까지 다양합니다. UIView 클래스의 draw(_:) 메서드는 개발자가 UIBezierPath를 생성하고 그리는 주요 위치입니다. 이 클래스는 Core Animation과 완전히 호환되며 CAShapeLayer 및 CABasicAnimation을 통한 경로 애니메이션에 사용할 수 있습니다.

직선과 사각형

move(to:) 메서드는 그리지 않고 경로의 시작점을 지정된 좌표로 이동합니다. 이는 세그먼트를 구성하기 전에 필수 호출입니다. addLine(to:)는 현재 위치에서 지정된 점까지 직선 세그먼트를 추가합니다. close() 메서드는 마지막 점에서 마지막 move(to:)의 첫 번째 점까지 선을 그려 윤곽선을 닫습니다.

둥근 모서리 사각형

UIBezierPath는 기성 도형을 위한 여러 편리한 초기화자를 제공합니다. init(rect:)는 사각형을 만들고 init(roundedRect:cornerRadius:)는 둥근 모서리 사각형을 만듭니다. UIRectCorner 매개변수를 사용하면 topLeft 및 bottomRight와 같은 선택한 모서리만 둥글게 하고 나머지는 직선으로 유지할 수 있습니다. 이는 사용자 정의 버튼과 카드를 만드는 데 널리 사용됩니다.

init(ovalIn:)는 지정된 사각형에 내접하는 타원을 만듭니다. 사각형이 정사각형이면 타원은 원이 됩니다. init(roundedRect:byRoundingCorners:cornerRadii:)는 가장 유연한 옵션으로 각 모서리에 다른 반경을 설정할 수 있습니다. 이 초기화자는 iOS 6에서 도입되었으며 둥근 컨테이너를 만드는 표준으로 남아 있습니다.

swift
let path = UIBezierPath()
path.move(to: CGPoint(x: 50, y: 50))
path.addLine(to: CGPoint(x: 200, y: 50))
path.addLine(to: CGPoint(x: 200, y: 150))
path.addLine(to: CGPoint(x: 125, y: 200))
path.addLine(to: CGPoint(x: 50, y: 150))
path.close()

베지어 곡선: 2차와 3차

addQuadCurve(to:controlPoint:)는 하나의 제어점으로 2차 베지어 곡선을 추가합니다. 이 유형의 곡선은 계산을 최소화해야 할 때 간단한 부드러운 굴곡에 사용됩니다. 2차 곡선은 항상 포물선이며 시작점, 제어점 및 끝점으로 형성된 삼각형 내에 있음이 보장됩니다.

3차 베지어 곡선

addCurve(to:controlPoint1:controlPoint2:)는 두 개의 제어점으로 3차 베지어 곡선을 추가합니다. 3차 곡선은 모든 최신 벡터 편집기와 TrueType 글꼴에서 사용됩니다. 두 개의 제어점은 정확한 형태 제어를 위한 더 많은 자유도를 제공합니다. 이 메서드는 유기적이고 복잡한 윤곽선을 구성하는 데 권장됩니다.

곡선을 구성할 때 연속성 원칙을 유지하는 것이 중요합니다. 세그먼트의 연결 지점에서의 부드러움입니다. C1 연속성(접선)의 경우 다음 곡선의 제어점이 이전 곡선의 제어점과 같은 선상에 있어야 합니다. C2 연속성(곡률)의 경우 더 복잡한 조정이 필요하며, 동일한 수의 제어점을 가진 두 UIBezierPath 간에 애니메이션할 때 CAShapeLayer에서 자동으로 제공됩니다.

메서드유형제어점차수
addQuadCurve2차 베지어12
addCurve3차 베지어23
addArc

호와 원

addArc(withCenter:radius:startAngle:endAngle:clockwise:)는 지정된 매개변수로 원호를 추가합니다. 각도는 원의 중심을 기준으로 라디안으로 지정됩니다. 0도 각도는 오른쪽 방향(시계의 3시 방향)에 해당합니다. clockwise 매개변수는 방향을 결정합니다. true는 시계 방향, false는 반시계 방향입니다. 호는 원형 차트, 속도계 및 대화형 진행 링에 필수적입니다.

원과 섹터

완전한 원의 경우 startAngle = 0, endAngle = .pi * 2를 사용합니다. 섹터(원형 차트의 일부)를 만들려면 중심으로의 addLine(to:) 및 close()와 함께 addArc를 사용합니다. UIBezierPath에는 내장된 addCircle 메서드가 없습니다. 원은 정사각형 사각형으로 init(ovalIn:)을 통해 또는 완전한 각도로 addArc를 통해 만들어집니다.

addArc(withCenter:radius:startAngle:endAngle:clockwise:) 메서드는 현재 위치가 일치하지 않으면 자동으로 호의 시작점으로 move(to:)를 실행합니다. 현재 위치가 다른 경우 해당 위치와 호의 시작점 사이에 직선이 그려집니다. 이 동작은 각각의 새 윤곽선 전에 명시적인 move(to:)가 필요한 Core Graphics와 다릅니다.

swift
let center = CGPoint(x: 150, y: 150)
let slice = UIBezierPath()
slice.move(to: center)
slice.addArc(
    withCenter: center,
    radius: 100,
    startAngle: 0,
    endAngle: .pi * 0.75,
    clockwise: true
)
slice.close()

경로의 채우기와 스트로크

fill()은 현재 fillColor 또는 setFill()을 통해 그래픽 컨텍스트에 설정된 색상으로 경로의 내부 영역을 채웁니다. 자체 교차하는 경로의 경우 채우기 규칙은 usesEvenOddFillRule 속성에 의해 결정됩니다. true인 경우 짝수-홀수 규칙이 사용됩니다. 점에서 나오는 광선이 윤곽선을 홀수 번 교차하면 해당 점은 도형 내부로 간주됩니다.

스트로크 설정

stroke()는 현재 lineWidth, lineCapStyle 및 lineJoinStyle 설정으로 경로 윤곽선을 그립니다. lineCapStyle은 열린 세그먼트 끝의 모양을 정의합니다. .butt(직선 절단), .round(반원형), .square(돌출부가 있는 정사각형). lineJoinStyle은 모서리 접합부의 모양을 정의합니다. .miter(날카로움), .round(둥글게), .bevel(경사).

점선의 경우 setLineDash(_:count:phase:) 속성을 사용합니다. 교대하는 대시와 간격 길이, 요소 수 및 초기 위상의 배열을 허용합니다. 대시 렌더링은 경로 래스터화 중에 수행됩니다. 복잡한 패턴도 윤곽선의 기하학적 복잡성을 증가시키지 않습니다. CAShapeLayer는 시작부터 끝까지의 “그리기” 효과를 위해 strokeEnd 속성의 애니메이션을 지원합니다.

swift
override func draw(_ rect: CGRect) {
    let path = UIBezierPath(ovalIn: CGRect(x: 50, y: 50, width: 200, height: 200))
    UIColor.blue.setFill()
    UIColor.black.setStroke()
    path.lineWidth = 4
    path.fill()
    path.stroke()
}

복잡한 도형 생성 예제

UIBezierPath를 사용하여 링 형태의 사용자 정의 진행 표시기를 만들어 보겠습니다. 링은 다른 스트로크 색상으로 동일한 반경의 두 호로 구성됩니다. 첫 번째 호는 회색의 완전한 원(배경)이고, 두 번째는 진행 상황을 보여주는 세그먼트입니다. 애니메이션에는 CAShapeLayer와 CABasicAnimation이 사용됩니다.

swift
class RingView: UIView {

    private let progressLayer = CAShapeLayer()

    override func layoutSubviews() {
        super.layoutSubviews()
        let center = CGPoint(x: bounds.midX, y: bounds.midY)
        let radius = bounds.width * 0.4
        let lineWidth: CGFloat = 12

        let backgroundRing = UIBezierPath()
        backgroundRing.addArc(withCenter: center, radius: radius,
                          startAngle: -.pi / 2, endAngle: .pi * 1.5, clockwise: true)

        progressLayer.path = backgroundRing.cgPath
        progressLayer.strokeColor = UIColor.systemBlue.cgColor
        progressLayer.lineWidth = lineWidth
        progressLayer.lineCap = .round
        progressLayer.fillColor = UIColor.clear.cgColor
        progressLayer.strokeEnd = 0
        layer.addSublayer(progressLayer)
    }

    func animateProgress(to value: CGFloat) {
        CABasicAnimation(keyPath: "strokeEnd").apply {
            $0.toValue = value
            $0.duration = 1.5
            $0.timingFunction = CAMediaTimingFunction(name: .easeOut)
            progressLayer.add($0, forKey: nil)
        }
        progressLayer.strokeEnd = value
    }
}

이 예제에서 UIBezierPath는 원형 윤곽선을 만드는 데 사용되며, 그런 다음 cgPath 속성을 통해 CAShapeLayer로 전달됩니다. strokeEnd를 0에서 1로 애니메이션하면 링 채우기가 시각화됩니다. 이 접근 방식은 로딩 표시기, 피트니스 트래커 및 진행 위젯에서 사용됩니다. layoutSubviews 메서드는 View 크기가 변경될 때 경로 재구성을 보장합니다.

lineCap = .round는 호에 둥근 끝을 추가하여 표시기에 더 깔끔한 외관을 제공합니다. strokeEnd 속성은 CAShapeLayer의 애니메이션 가능 속성으로, 매 프레임마다 전체 윤곽선을 다시 그릴 필요가 없습니다. 애니메이션은 Core Animation을 통해 완전히 GPU에서 실행되어 CPU에 부하를 주지 않으면서 60FPS를 보장합니다.

자주 묻는 질문

UIBezierPath와 CGPath의 차이점은?

UIBezierPath는 CGPath를 둘러싼 객체 지향 래퍼로 내장된 fill() 및 stroke() 메서드를 포함합니다. CGPath는 Core Graphics의 변경 불가능한 C 객체로 CGContext를 통한 명시적 그리기가 필요합니다. UIBezierPath는 UIKit에 더 편리하고 CGPath는 재사용에 더 효율적입니다.

사각형의 위쪽 모서리만 둥글게 하려면?

roundedRect에 .topLeft 및 .topRight 매개변수를 사용하여 init(roundedRect:byRoundingCorners:cornerRadii:)를 사용합니다. 이것은 복잡한 복합 경로를 만들지 않고 선택적으로 모서리를 둥글게 할 수 있는 유일한 UIBezierPath 메서드입니다.

다른 스타일로 UIBezierPath를 재사용하려면?

cgPath 속성은 변경 불가능한 CGPathRef를 반환하며 CAShapeLayer에 전달하거나 다른 색상과 두께로 사용할 수 있습니다. UIBezierPath의 수정(점 이동)은 명시적으로 업데이트될 때까지 이전에 얻은 cgPath에 영향을 주지 않습니다.

fill()이 전체 경로를 덮지 않는 이유는?

usesEvenOddFillRule을 확인하세요. 윤곽선에 자체 교차가 있는 경우 짝수-홀수 규칙이 영역을 채우지 않은 상태로 남길 수 있습니다. 표준 non-zero winding 채우기 규칙을 위해 usesEvenOddFillRule = false로 설정합니다.

UIBezierPath 도형을 애니메이션하려면?

CAShapeLayer에서 키 경로 “path”로 CABasicAnimation을 사용합니다. 두 경로 상태 모두 동일한 수의 세그먼트와 제어점을 포함해야 합니다. 그렇지 않으면 애니메이션이 끊기거나 실패합니다.

요약

  • UIBezierPath는 벡터 경로 및 2D 그래픽 작업을 위한 UIKit의 객체 지향 클래스입니다.
  • move(to:)addLine(to:)는 직선과 다각형을 구성하는 기본 메서드입니다.
  • addQuadCurveaddCurve는 하나와 두 개의 제어점으로 2차 및 3차 베지어 곡선을 만듭니다.
  • addArc는 유연한 각도 및 방향 제어로 원호를 그립니다.
  • fill()stroke()는 현재 그래픽 컨텍스트에서 직접 그리기를 수행합니다.
  • 초기화자 init(roundedRect:)init(ovalIn:)는 표준 도형 생성을 가속화합니다.
  • cgPath 속성은 애니메이션을 위해 UIBezierPath를 Core Animation 및 CAShapeLayer와 통합할 수 있게 합니다.

턴키 방식의 모바일 애플리케이션을 개발해 드립니다

IT Sectr는 2017년부터 스타트업과 기업을 위한 iOS 및 Android 애플리케이션을 만듭니다. 저희가 상담해 드리고 최적의 솔루션을 제안하겠습니다.

프로젝트 논의

더 읽어보기