UIBezierPath — کلاسی از UIKit که مسیر برداری را برای گرافیک 2D در iOS کپسوله میکند. این کلاس توصیف هندسی کانتور را با قابلیتهای رسم ترکیب میکند و امکان ایجاد خطوط، منحنیهای بزیه، کمانها و مستطیلها را فراهم میکند. برخلاف CGPath، UIBezierPath شامل متدهای رسم داخلی به طور مستقیم در زمینه گرافیکی جاری است. طبق Apple Developer Documentation, 2026، UIBezierPath از تمام عملیات استاندارد Quartz 2D در یک پوشش شیگرا پشتیبانی میکند.
نکات اصلی
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 ظاهر شد و همچنان استاندارد برای ایجاد ظروف گرد است.
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 | بزیه درجه دوم | 1 | 2 |
| addCurve | بزیه مکعبی | 2 | 3 |
| 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:) صریح قبل از هر کانتور جدید لازم است.
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 برای اثر «کشیده شدن» خط از ابتدا تا انتها پشتیبانی میکند.
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 استفاده میشود.
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 شامل متدهای داخلی fill() و stroke(). CGPath — یک شیء C غیرقابل تغییر Core Graphics که نیاز به رسم صریح از طریق CGContext دارد. UIBezierPath برای UIKit راحتتر است، CGPath برای استفاده مجدد کارآمدتر است.
از init(roundedRect:byRoundingCorners:cornerRadii:) با پارامتر .topLeft و .topRight برای roundedRect استفاده کنید. این تنها متد UIBezierPath است که امکان گرد کردن انتخابی گوشهها را بدون ایجاد یک مسیر ترکیبی پیچیده فراهم میکند.
ویژگی cgPath یک CGPathRef غیرقابل تغییر برمیگرداند که میتواند به CAShapeLayer منتقل شود یا با رنگها و ضخامتهای مختلف استفاده شود. تغییرات UIBezierPath (جابجایی نقاط) تا بهروزرسانی صریح بر cgPath قبلی تأثیر نمیگذارد.
usesEvenOddFillRule را بررسی کنید — اگر کانتور خودتقاطع داشته باشد، قانون even-odd ممکن است نواحی را خالی بگذارد. برای قانون پر کردن استاندارد non-zero winding، usesEvenOddFillRule = false تنظیم کنید.
از CABasicAnimation با مسیر کلید «path» روی CAShapeLayer استفاده کنید. هر دو حالت مسیر باید تعداد یکسانی بخش و نقطه کنترل داشته باشند — در غیر این صورت انیمیشن ناپایدار خواهد بود یا کار نخواهد کرد.
خلاصه
ما یک اپلیکیشن موبایل به صورت کلید در دست توسعه خواهیم داد
IT Sectr از سال 2017 برنامههای iOS و Android را برای استارتاپها و کسبوکارها ایجاد میکند. ما به شما مشاوره میدهیم و بهترین راهحل را پیشنهاد خواهیم کرد.
همچنین بخوانید