UIBezierPath: คืออะไร วิธีการวาด และวิธีการทำงาน

ผู้แต่ง: IT Sectr เผยแพร่เมื่อ: 2026-07-21 เวลาอ่าน: 8 นาที

UIBezierPath คือคลาสจาก UIKit ที่ห่อหุ้มเส้นทางเวกเตอร์สำหรับกราฟิก 2D ใน iOS มันรวมคำอธิบายทางเรขาคณิตของเส้นขอบเข้ากับความสามารถในการวาด ทำให้สามารถสร้างเส้นตรง เส้นโค้งเบซิเอร์ ส่วนโค้ง และสี่เหลี่ยมผืนผ้าได้ ต่างจาก CGPath ตรงที่ UIBezierPath มีวิธีการวาดของตัวเองที่ทำงานโดยตรงในบริบทกราฟิกปัจจุบัน ตาม Apple Developer Documentation, 2026 UIBezierPath รองรับการดำเนินการ Quartz 2D มาตรฐานทั้งหมดในตัวห่อหุ้มเชิงวัตถุ

ประเด็นสำคัญ

  • UIBezierPath เป็นตัวห่อหุ้มเชิงวัตถุของ CGPath สำหรับทำงานกับเส้นทางเวกเตอร์ใน UIKit
  • move(to:) และ addLine(to:) กำหนดส่วนของเส้นตรงของเส้นทาง
  • addQuadCurve(to:controlPoint:) และ addCurve(to:controlPoint1:controlPoint2:) สร้างเส้นโค้งเบซิเอร์
  • addArc(withCenter:radius:startAngle:endAngle:clockwise:) สร้างส่วนโค้งและเซกเตอร์
  • fill และ stroke วาดเส้นทางโดยตรงในบริบทปัจจุบันโดยไม่ต้องใช้วัตถุเพิ่มเติม

UIBezierPath คืออะไร?

UIBezierPath คือคลาสของเฟรมเวิร์ก UIKit ที่สืบทอดจาก NSObject และนำ NSCopying, NSSecureCoding มาใช้ มันให้ API ระดับสูงแบบ Objective-C/Swift สำหรับสร้างและวาดเส้นทางเวกเตอร์ ภายใน UIBezierPath เก็บการอ้างอิงถึง CGPathRef ซึ่งเป็นวัตถุ Core Graphics แต่เพิ่มวิธีการที่สะดวกสำหรับการวาด การปรับเปลี่ยนเรขาคณิต และการจัดการสไตล์

ข้อได้เปรียบหลักของ UIBezierPath เหนือการใช้ CGPath โดยตรงคือ วิธีการวาดในตัว การเรียก fill() หรือ stroke() บนอินสแตนซ์ของ UIBezierPath จะกำหนดค่าบริบทและวาดเส้นทางโดยอัตโนมัติ คลาสยังรองรับคุณสมบัติ lineWidth, lineCapStyle, lineJoinStyle, miterLimit และ flatness ซึ่งช่วยให้ควบคุมลักษณะที่ปรากฏได้โดยไม่ต้องมีวัตถุแยกสำหรับจัดเก็บสไตล์

UIBezierPath ถูกใช้ในแอปพลิเคชัน iOS ส่วนใหญ่สำหรับการวาดแบบกำหนดเองภายใน UIView ตั้งแต่ไอคอนง่ายๆ ไปจนถึงแผนภูมิเคลื่อนไหวที่ซับซ้อน เมธอด draw(_:) ของคลาส UIView เป็นสถานที่หลักที่นักพัฒนาสร้างและวาด 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()

เส้นโค้งเบซิเอร์: กำลังสองและกำลังสาม

addQuadCurve(to:controlPoint:) เพิ่มเส้นโค้งเบซิเอร์กำลังสองด้วยจุดควบคุมหนึ่งจุด เส้นโค้งชนิดนี้ใช้สำหรับโค้งเรียบง่ายเมื่อต้องการลดการคำนวณให้น้อยที่สุด เส้นโค้งกำลังสองเป็นพาราโบลาเสมอและรับประกันว่าอยู่ภายในสามเหลี่ยมที่เกิดจากจุดเริ่มต้น จุดควบคุม และจุดสิ้นสุด

เส้นโค้งเบซิเอร์กำลังสาม

addCurve(to:controlPoint1:controlPoint2:) เพิ่มเส้นโค้งเบซิเอร์กำลังสามด้วยจุดควบคุมสองจุด เส้นโค้งกำลังสามถูกใช้ในโปรแกรมแก้ไขเวกเตอร์สมัยใหม่ทั้งหมดและฟอนต์ TrueType จุดควบคุมสองจุดให้ระดับอิสระมากขึ้นสำหรับการควบคุมรูปร่างที่แม่นยำ เมธอดนี้แนะนำสำหรับการสร้างเส้นขอบที่เป็นธรรมชาติและซับซ้อน

เมื่อสร้างเส้นโค้ง สิ่งสำคัญคือต้องรักษา หลักการความต่อเนื่อง ความเรียบเนียนที่จุดเชื่อมต่อของส่วนต่างๆ สำหรับความต่อเนื่อง C1 (เส้นสัมผัส) จุดควบคุมของเส้นโค้งถัดไปต้องอยู่บนเส้นเดียวกับจุดควบคุมของเส้นโค้งก่อนหน้า สำหรับความต่อเนื่อง C2 (ความโค้ง) จำเป็นต้องมีการประสานงานที่ซับซ้อนมากขึ้น ซึ่งมีให้โดยอัตโนมัติใน CAShapeLayer เมื่อทำอนิเมชันระหว่าง UIBezierPath สองอันที่มีจำนวนจุดควบคุมเท่ากัน

เมธอดประเภทจุดควบคุมดีกรี
addQuadCurveเบซิเอร์กำลังสอง12
addCurveเบซิเอร์กำลังสาม23
addArcส่วนโค้ง

ส่วนโค้งและวงกลม

addArc(withCenter:radius:startAngle:endAngle:clockwise:) เพิ่มส่วนโค้งของวงกลมด้วยพารามิเตอร์ที่กำหนด มุมจะระบุเป็นเรเดียนสัมพันธ์กับศูนย์กลางของวงกลม มุมศูนย์สอดคล้องกับทิศทางไปทางขวา (ตำแหน่ง 3 นาฬิกาบนหน้าปัดนาฬิกา) พารามิเตอร์ clockwise กำหนดทิศทาง: true ตามเข็มนาฬิกา false ทวนเข็มนาฬิกา ส่วนโค้งจำเป็นสำหรับแผนภูมิวงกลม มาตรวัดความเร็ว และวงแหวนความคืบหน้าแบบโต้ตอบ

วงกลมและเซกเตอร์

สำหรับวงกลมเต็ม ให้ใช้ startAngle = 0 และ endAngle = .pi * 2 ในการสร้างเซกเตอร์ (เป็นส่วนหนึ่งของแผนภูมิวงกลม) ให้ใช้ addArc ตามด้วย addLine(to:) ไปยังศูนย์กลางและ close() UIBezierPath ไม่มีเมธอด addCircle ในตัว วงกลมถูกสร้างขึ้นผ่าน init(ovalIn:) ด้วยสี่เหลี่ยมจัตุรัสหรือผ่าน addArc ด้วยมุมเต็ม

เมธอด addArc(withCenter:radius:startAngle:endAngle:clockwise:) จะดำเนินการ move(to:) ไปยังจุดเริ่มต้นของส่วนโค้งโดยอัตโนมัติหากตำแหน่งปัจจุบันไม่ตรงกัน หากตำแหน่งปัจจุบันแตกต่าง เส้นตรงจะถูกลากระหว่างตำแหน่งนั้นกับจุดเริ่มต้นของส่วนโค้ง พฤติกรรมนี้แตกต่างจาก Core Graphics ซึ่งต้องมีการเรียก move(to:) อย่างชัดเจนก่อนแต่ละเส้นขอบใหม่

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 ถูกใช้เพื่อสร้างเส้นขอบวงกลม ซึ่งจากนั้นส่งต่อไปยัง CAShapeLayer ผ่านคุณสมบัติ cgPath การทำอนิเมชัน strokeEnd จาก 0 ถึง 1 แสดงให้เห็นการเติมของวงแหวน วิธีการนี้ใช้ในตัวบ่งชี้การโหลด ตัวติดตามฟิตเนส และวิดเจ็ตความคืบหน้า เมธอด layoutSubviews รับประกันการสร้างเส้นทางใหม่เมื่อขนาดของ View เปลี่ยนไป

lineCap = .round เพิ่มปลายมนให้กับส่วนโค้ง ทำให้ตัวบ่งชี้ดูเรียบร้อยขึ้น คุณสมบัติ strokeEnd เป็นคุณสมบัติที่สามารถทำอนิเมชันได้ของ CAShapeLayer ซึ่งไม่ต้องการวาดเส้นขอบทั้งหมดใหม่ในแต่ละเฟรม อนิเมชันทำงานบน GPU ทั้งหมดผ่าน Core Animation ทำให้มั่นใจได้ถึง 60 FPS โดยไม่โหลด CPU

คำถามที่พบบ่อย

UIBezierPath แตกต่างจาก CGPath อย่างไร?

UIBezierPath เป็นตัวห่อหุ้มเชิงวัตถุรอบ CGPath ที่มีเมธอด fill() และ stroke() ในตัว CGPath เป็นวัตถุ C ที่ไม่สามารถเปลี่ยนแปลงได้ของ Core Graphics ซึ่งต้องวาดอย่างชัดเจนผ่าน CGContext UIBezierPath สะดวกกว่าสำหรับ UIKit ในขณะที่ CGPath มีประสิทธิภาพมากกว่าสำหรับการนำกลับมาใช้ใหม่

จะทำให้เฉพาะมุมบนของสี่เหลี่ยมผืนผ้ามนได้อย่างไร?

ใช้ init(roundedRect:byRoundingCorners:cornerRadii:) ด้วยพารามิเตอร์ .topLeft และ .topRight สำหรับ roundedRect นี่เป็นเมธอดเดียวของ UIBezierPath ที่ช่วยให้เลือกทำให้มุมมนได้โดยไม่ต้องสร้างเส้นทางประกอบที่ซับซ้อน

จะนำ UIBezierPath กลับมาใช้ใหม่กับสไตล์ต่างๆ ได้อย่างไร?

คุณสมบัติ cgPath ส่งคืน CGPathRef ที่ไม่สามารถเปลี่ยนแปลงได้ซึ่งสามารถส่งต่อไปยัง CAShapeLayer หรือใช้กับสีและความหนาต่างๆ การแก้ไข UIBezierPath (การเคลื่อนที่ของจุด) จะไม่ส่งผลต่อ cgPath ที่ได้รับก่อนหน้านี้จนกว่าจะได้รับการอัปเดตอย่างชัดเจน

ทำไม fill() ไม่ครอบคลุมทั้งเส้นทาง?

ตรวจสอบ usesEvenOddFillRule หากเส้นขอบมีการตัดกันเอง กฎคู่-คี่อาจทำให้พื้นที่ไม่ถูกเติม ตั้งค่า usesEvenOddFillRule = false สำหรับกฎการเติม non-zero winding มาตรฐาน

จะทำอนิเมชันรูปร่าง UIBezierPath ได้อย่างไร?

ใช้ CABasicAnimation ด้วยเส้นทางคีย์ “path” บน CAShapeLayer ทั้งสองสถานะของเส้นทางต้องมีจำนวนส่วนและจุดควบคุมเท่ากัน มิฉะนั้นอนิเมชันจะกระตุกหรือล้มเหลว

สรุป

  • UIBezierPath เป็นคลาสเชิงวัตถุของ UIKit สำหรับทำงานกับเส้นทางเวกเตอร์และกราฟิก 2D
  • move(to:) และ addLine(to:) เป็นเมธอดพื้นฐานสำหรับสร้างเส้นตรงและรูปหลายเหลี่ยม
  • addQuadCurve และ addCurve สร้างเส้นโค้งเบซิเอร์กำลังสองและกำลังสามด้วยจุดควบคุมหนึ่งและสองจุด
  • addArc วาดส่วนโค้งของวงกลมด้วยการควบคุมมุมและทิศทางที่ยืดหยุ่น
  • fill() และ stroke() ดำเนินการวาดโดยตรงในบริบทกราฟิกปัจจุบัน
  • ตัวเริ่มต้น init(roundedRect:) และ init(ovalIn:) เร่งการสร้างรูปร่างมาตรฐาน
  • คุณสมบัติ cgPath ช่วยให้รวม UIBezierPath เข้ากับ Core Animation และ CAShapeLayer สำหรับอนิเมชัน

เราจะพัฒนาแอปพลิเคชันบนมือถือแบบครบวงจร

IT Sectr สร้างแอปพลิเคชัน iOS และ Android สำหรับสตาร์ทอัพและธุรกิจตั้งแต่ปี 2017 เราจะให้คำแนะนำและเสนอวิธีแก้ปัญหาที่ดีที่สุดแก่คุณ

ปรึกษาโครงการ

อ่านเพิ่มเติม