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 روی صفحه clock). پارامتر 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 باشد، قانون even-odd اعمال می‌شود: یک نقطه در داخل شکل محسوب می‌شود اگر پرتوی از آن کانتور را تعداد فرد بار قطع کند.

پیکربندی خط دور

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 است که نیاز به بازترسیم کل کانتور در هر فریم ندارد. انیمیشن کاملاً روی 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 را بررسی کنید — اگر کانتور خودتقاطع داشته باشد، قانون even-odd ممکن است نواحی را خالی بگذارد. برای قانون پر کردن استاندارد non-zero winding، usesEvenOddFillRule = false تنظیم کنید.

چگونه شکل 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 از سال 2017 برنامه‌های iOS و Android را برای استارتاپ‌ها و کسب‌وکارها ایجاد می‌کند. ما به شما مشاوره می‌دهیم و بهترین راه‌حل را پیشنهاد خواهیم کرد.

بحث درباره پروژه

همچنین بخوانید