تحتاج العديد من التطبيقات إلى التحكّم بدقة في المحتوى المعروض على الشاشة. قد يكون ذلك بسيطًا مثل وضع مربّع أو دائرة على الشاشة في المكان المناسب تمامًا، أو قد يكون ترتيبًا معقّدًا للعناصر الرسومية بأنماط مختلفة.
رسم أساسي باستخدام المعدِّلات وDrawScope
الطريقة الأساسية لرسم عناصر مخصّصة في Compose هي استخدام المعدِّلات، مثل
Modifier.drawWithContent
و
Modifier.drawBehind
و
Modifier.drawWithCache
.
على سبيل المثال، لرسم عنصر خلف العنصر القابل للإنشاء، يمكنك استخدام المعدِّل drawBehind
لبدء تنفيذ أوامر الرسم:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
إذا كنت تحتاج فقط إلى عنصر قابل للإنشاء يرسم، يمكنك استخدام العنصر القابل للإنشاء
Canvas
. إنّ العنصر القابل للإنشاء Canvas
هو
غلاف مناسب حول Modifier.drawBehind
. يمكنك وضع Canvas
في التنسيق بالطريقة نفسها التي تضع بها أي عنصر آخر من عناصر واجهة مستخدم Compose. ضمن
Canvas
، يمكنك رسم عناصر مع التحكّم بدقة في نمطها وموقعها.
تعرض جميع معدِّلات الرسومات DrawScope
، وهي بيئة رسم ذات نطاق محدّد
تحتفظ بحالتها الخاصة. يتيح لك ذلك ضبط المَعلمات لمجموعة من العناصر الرسومية. يوفر العنصر DrawScope
عدة حقول مفيدة، مثل size
،
وهو عنصر Size
يحدّد الأبعاد الحالية للعنصر DrawScope
.
لرسم شيء ما، يمكنك استخدام إحدى دوال الرسم العديدة في DrawScope
. على سبيل المثال، يرسم الرمز التالي مستطيلاً في الزاوية العلوية اليمنى من الشاشة:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F drawRect( color = Color.Magenta, size = canvasQuadrantSize ) }

لمزيد من المعلومات حول أدوات تعديل الرسومات المختلفة، يُرجى الاطّلاع على مستندات أدوات تعديل الرسومات.
نظام الإحداثيات
لرسم عنصر على الشاشة، عليك معرفة الإزاحة (x
وy
) وحجم العنصر. مع العديد من طرق الرسم في DrawScope
، يتم توفير الموضع والحجم من خلال قيم المَعلمات التلقائية. تضع المَعلمات التلقائية العنصر بشكل عام في النقطة [0, 0]
على لوحة الرسم، وتوفّر size
تلقائيًا يملأ مساحة الرسم بأكملها، كما هو الحال في المثال أعلاه، حيث يمكنك ملاحظة أنّ المستطيل موضوع في أعلى اليمين. لتعديل حجم العنصر وموضعه، عليك فهم نظام الإحداثيات في Compose.
تقع نقطة الأصل لنظام الإحداثيات ([0,0]
) في أعلى بكسل على اليمين في مساحة الرسم. تزداد قيمة x
كلما تحرّكنا إلى اليمين، وتزداد قيمة y
كلما تحرّكنا إلى الأسفل.
![شبكة تعرض نظام الإحداثيات الذي يعرض أعلى اليمين [0, 0] وأسفل اليسار [العرض، الارتفاع]](https://developer.android.com/static/develop/ui/compose/images/graphics/introduction/compose_coordinate_system_drawing.png?authuser=8&hl=ar)
على سبيل المثال، إذا أردت رسم خط قطري من أعلى يسار مساحة لوحة العرض إلى أسفل يمينها، يمكنك استخدام الدالة DrawScope.drawLine()
وتحديد إزاحة البداية والنهاية باستخدام موضعَي x وy المناسبَين:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasWidth = size.width val canvasHeight = size.height drawLine( start = Offset(x = canvasWidth, y = 0f), end = Offset(x = 0f, y = canvasHeight), color = Color.Blue ) }
عمليات التحويل الأساسية
توفّر DrawScope
عمليات تحويل لتغيير مكان أو طريقة تنفيذ أوامر الرسم.
تغيير الحجم
استخدِم
DrawScope.scale()
لزيادة حجم عمليات الرسم بمعامل. تنطبق عمليات مثل
scale()
على جميع عمليات الرسم ضمن دالة lambda المقابلة. على سبيل المثال، تزيد التعليمة البرمجية التالية قيمة scaleX
بمقدار 10 مرات وقيمة scaleY
بمقدار 15 مرة:
Canvas(modifier = Modifier.fillMaxSize()) { scale(scaleX = 10f, scaleY = 15f) { drawCircle(Color.Blue, radius = 20.dp.toPx()) } }

ترجمة
استخدِم
DrawScope.translate()
لتحريك عمليات الرسم للأعلى أو للأسفل أو لليمين أو لليسار. على سبيل المثال، ينقل الرمز التالي الرسم بمقدار 100 بكسل إلى اليمين و300 بكسل إلى الأعلى:
Canvas(modifier = Modifier.fillMaxSize()) { translate(left = 100f, top = -300f) { drawCircle(Color.Blue, radius = 200.dp.toPx()) } }

تدوير
استخدِم
DrawScope.rotate()
لتدوير عمليات الرسم حول نقطة محورية. على سبيل المثال، يدير الرمز التالي مستطيلاً بزاوية 45 درجة:
Canvas(modifier = Modifier.fillMaxSize()) { rotate(degrees = 45F) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }

rotate()
لتطبيق دوران على نطاق الرسم الحالي، ما يؤدي إلى تدوير المستطيل بمقدار 45 درجة.
مساحة داخلية
استخدِم DrawScope.inset()
لضبط المَعلمات التلقائية DrawScope
الحالية، وتغيير حدود الرسم وترجمة الرسومات وفقًا لذلك:
Canvas(modifier = Modifier.fillMaxSize()) { val canvasQuadrantSize = size / 2F inset(horizontal = 50f, vertical = 30f) { drawRect(color = Color.Green, size = canvasQuadrantSize) } }
يضيف هذا الرمز مساحة متروكة بشكل فعّال إلى أوامر الرسم:

عمليات تحويل متعدّدة
لتطبيق عمليات تحويل متعددة على الرسومات، استخدِم الدالة
DrawScope.withTransform()
، التي تنشئ عملية تحويل واحدة وتطبّقها، وتجمع كل التغييرات المطلوبة. يُعدّ استخدام
withTransform()
أكثر فعالية من إجراء طلبات متداخلة لعمليات تحويل فردية، لأنّ جميع عمليات التحويل يتم تنفيذها معًا في عملية واحدة، بدلاً من أن يحتاج Compose إلى حساب كل عملية من عمليات التحويل المتداخلة وحفظها.
على سبيل المثال، يطبّق الرمز البرمجي التالي كلاً من الترجمة والتدوير على المستطيل:
Canvas(modifier = Modifier.fillMaxSize()) { withTransform({ translate(left = size.width / 5F) rotate(degrees = 45F) }) { drawRect( color = Color.Gray, topLeft = Offset(x = size.width / 3F, y = size.height / 3F), size = size / 3F ) } }

withTransform
لتطبيق كل من الدوران والترجمة، وتدوير المستطيل ونقله إلى اليسار.عمليات الرسم الشائعة
رسم نص
لرسم نص في Compose، يمكنك عادةً استخدام العنصر القابل للإنشاء Text
. ومع ذلك، إذا كنت في DrawScope
أو أردت رسم النص يدويًا مع التخصيص، يمكنك استخدام طريقة DrawScope.drawText()
.
لرسم نص، أنشئ TextMeasurer
باستخدام rememberTextMeasurer
واستدعِ drawText
باستخدام أداة القياس:
val textMeasurer = rememberTextMeasurer() Canvas(modifier = Modifier.fillMaxSize()) { drawText(textMeasurer, "Hello") }

نص القياس
يختلف رسم النص قليلاً عن أوامر الرسم الأخرى. عادةً، يتم تحديد حجم (العرض والارتفاع) الأمر الخاص بالرسم لرسم الشكل/الصورة. في ما يتعلق بالنص، هناك بعض المَعلمات التي تتحكّم في حجم النص المعروض، مثل حجم الخط ونوعه والوصلات والمسافة بين الأحرف.
باستخدام Compose، يمكنك استخدام TextMeasurer
للوصول إلى حجم النص الذي تم قياسه، وذلك استنادًا إلى العوامل المذكورة أعلاه. إذا أردت رسم خلفية
خلف النص، يمكنك استخدام المعلومات المقاسة للحصول على حجم
المساحة التي يشغلها النص:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()), style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
ينتج عن مقتطف الرمز هذا خلفية وردية على النص:

يؤدي تعديل القيود أو حجم الخط أو أي خاصية تؤثر في الحجم المقاس إلى عرض حجم جديد. يمكنك ضبط حجم ثابت لكل من width
وheight
، ثم يتبع النص TextOverflow
الذي تم ضبطه. على سبيل المثال، يعرض الرمز التالي النص في ثلث الارتفاع وثلث العرض الخاصين بالمساحة القابلة للإنشاء، ويضبط TextOverflow
على TextOverflow.Ellipsis
:
val textMeasurer = rememberTextMeasurer() Spacer( modifier = Modifier .drawWithCache { val measuredText = textMeasurer.measure( AnnotatedString(longTextSample), constraints = Constraints.fixed( width = (size.width / 3f).toInt(), height = (size.height / 3f).toInt() ), overflow = TextOverflow.Ellipsis, style = TextStyle(fontSize = 18.sp) ) onDrawBehind { drawRect(pinkColor, size = measuredText.size.toSize()) drawText(measuredText) } } .fillMaxSize() )
يتم الآن رسم النص في القيود مع علامة حذف في النهاية:

TextOverflow.Ellipsis
مع قيود ثابتة على قياس النصرسم صورة
لرسم ImageBitmap
باستخدام DrawScope
، حمِّل الصورة باستخدام
ImageBitmap.imageResource()
ثم استدعِ drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })

ImageBitmap
على لوحة الرسمرسم الأشكال الأساسية
تتوفّر العديد من دوال رسم الأشكال على DrawScope
. لرسم شكل، استخدِم إحدى دوال الرسم المحدّدة مسبقًا، مثل drawCircle
:
val purpleColor = Color(0xFFBA68C8) Canvas( modifier = Modifier .fillMaxSize() .padding(16.dp), onDraw = { drawCircle(purpleColor) } )
واجهة برمجة التطبيقات |
الإخراج |
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
|
![]() |
رسم مسار
المسار هو سلسلة من التعليمات الرياضية التي تؤدي إلى رسم عند تنفيذها. يمكن لـ DrawScope
رسم مسار باستخدام الطريقة DrawScope.drawPath()
.
على سبيل المثال، لنفترض أنّك تريد رسم مثلث. يمكنك إنشاء مسار باستخدام دوال مثل lineTo()
وmoveTo()
باستخدام حجم مساحة الرسم.
بعد ذلك، استخدِم drawPath()
مع هذا المسار الذي تم إنشاؤه حديثًا للحصول على مثلث.
Spacer( modifier = Modifier .drawWithCache { val path = Path() path.moveTo(0f, 0f) path.lineTo(size.width / 2f, size.height / 2f) path.lineTo(size.width, 0f) path.close() onDrawBehind { drawPath(path, Color.Magenta, style = Stroke(width = 10f)) } } .fillMaxSize() )

Path
ورسمه في وضع "الكتابة"الوصول إلى العنصر "Canvas
"
باستخدام DrawScope
، لا يمكنك الوصول مباشرةً إلى عنصر Canvas
. يمكنك استخدام
DrawScope.drawIntoCanvas()
للوصول إلى
الكائن Canvas
نفسه الذي يمكنك استدعاء الدوال عليه.
على سبيل المثال، إذا كان لديك Drawable
مخصّص تريد رسمه على لوحة الرسم، يمكنك الوصول إلى لوحة الرسم واستدعاء Drawable#draw()
، مع تمرير عنصر Canvas
:
val drawable = ShapeDrawable(OvalShape()) Spacer( modifier = Modifier .drawWithContent { drawIntoCanvas { canvas -> drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt()) drawable.draw(canvas.nativeCanvas) } } .fillMaxSize() )

Drawable
مزيد من المعلومات
لمزيد من المعلومات حول الرسم في Compose، يُرجى الاطّلاع على المراجع التالية:
- معدّلات الرسومات: معلومات حول الأنواع المختلفة من معدّلات الرسومات
- الفرشاة: تعرَّف على كيفية تخصيص طريقة طلاء المحتوى.
- التصاميم والرسومات المخصّصة في Compose - مؤتمر Android Dev Summit 2022: تعرَّف على كيفية إنشاء واجهة مستخدم مخصّصة في Compose باستخدام التصاميم والرسومات.
- نموذج JetLagged: نموذج Compose يوضّح كيفية رسم رسم بياني مخصّص.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون JavaScript غير مفعّلة
- معدِّلات الرسومات
- الرسومات في "إنشاء"
- خطوط المحاذاة في Jetpack Compose