تكرار السؤال: …
الإجابة المختصرة
تمر بثلاث مراحل متتالية: القياس (Measure) ثم التموضع (Layout) ثم الرسم (Draw).
الشرح
في مرحلة onMeasure يحدد الـ View حجمه بناءً على قيود الأب (MeasureSpec: EXACTLY, AT_MOST, UNSPECIFIED). في مرحلة onLayout يتم حساب إحداثيات الزوايا الأربع للـ View وموضعه بالنسبة للأب. في مرحلة onDraw يقوم الـ View برسم محتواه البصري على كائن الـ Canvas باستخدام الـ Paint.
مثال بالكود
class CircleView(context: Context, attrs: AttributeSet?) : View(context, attrs) {
private val paint = Paint(Paint.ANTI_ALIAS_FLAG).apply { color = Color.BLUE }
override fun onMeasure(widthMeasureSpec: Int, heightMeasureSpec: Int) {
setMeasuredDimension(200, 200) // تحديد الحجم
}
override fun onDraw(canvas: Canvas) {
super.onDraw(canvas)
canvas.drawCircle(width / 2f, height / 2f, width / 2f, paint)
}
}أخطاء شائعة
- إنشاء كائنات جديدة مثل Paint أو Path داخل دالة onDraw مما يرهق الـ Garbage Collector ويسبب تقطيع الإطارات (Jank).
- استدعاء requestLayout بدلاً من invalidate عند الرغبة فقط في تحديث الألوان دون تغيير أبعاد الـ View.