UIBezierPath: ما هو، طرق الرسم وكيف يعمل

المؤلف: IT Sectr نُشر: 2026-07-21 وقت القراءة: 8 دق

UIBezierPath هي فئة من UIKit تغلف مساراً متجهاً للرسومات ثنائية الأبعاد في 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. توفر واجهة برمجة تطبيقات 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 للعمل مع المسارات المتجهة والرسومات ثنائية الأبعاد.
  • move(to:) و addLine(to:) هما طريقتان أساسيتان لبناء الخطوط المستقيمة والمضلعات.
  • addQuadCurve و addCurve تنشئان منحنيات بيزيه تربيعية وتكعيبية بنقطة ونقطتي تحكم.
  • addArc يرسم أقواساً دائرية مع تحكم مرن بالزوايا والاتجاه.
  • fill() و stroke() تقومان بالرسم مباشرة في سياق الرسم الحالي.
  • المهيئان init(roundedRect:) و init(ovalIn:) يسرعان إنشاء الأشكال القياسية.
  • الخاصية cgPath تسمح بدمج UIBezierPath مع Core Animation و CAShapeLayer للتحريك.

سنقوم بتطوير تطبيق جوال جاهز

تقدم IT Sectr تطبيقات iOS وAndroid للشركات الناشئة والشركات منذ عام 2017. سوف نقدم لك النصح ونقترح أفضل حل.

مناقشة المشروع

اقرأ أيضًا