يجب أن تكون العديد من التطبيقات قادرة على التحكّم بدقة في ما يتم رسمه على الشاشة. قد يكون ذلك بسيطًا مثل وضع مربّع أو دائرة على الشاشة في المكان المناسب تمامًا، أو قد يكون ترتيبًا متقنًا للعناصر الرسومية بالعديد من الأنماط المختلفة.
رسم أساسي باستخدام عوامل التعديل وDrawScope
إنّ الطريقة الأساسية لرسم شكل مخصّص في ميزة "الإنشاء" هي باستخدام عوامل التعديل، مثل
Modifier.drawWithContent
،
Modifier.drawBehind
، و
Modifier.drawWithCache
.
على سبيل المثال، لرسم شيء خلف العنصر القابل للتجميع، يمكنك استخدام المُعدِّل
drawBehind
لبدء تنفيذ أوامر الرسم:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
إذا كنت بحاجة فقط إلى عنصر تركيبي يرسم، يمكنك استخدام العنصر التركيبي
Canvas
. Canvas
composable هو
حزمة ملائمة حول Modifier.drawBehind
. يمكنك وضع الرمز Canvas
في
تخطيطك بالطريقة نفسها التي تضع بها أي عنصر آخر من عناصر واجهة مستخدم ميزة "الإنشاء". ضمن
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
تلقائية تملأ مساحة الرسم بالكامل، كما هو موضّح في المثال أعلاه. يمكنك رؤية
وضع المستطيل في أعلى يمين اللوحة. لتعديل حجم العنصر وموقعه، عليك فهم نظام الإحداثيات في ميزة "الإنشاء".
تقع نقطة الأصل لنظام الإحداثيات ([0,0]
) في أعلى يمين بكسل في
منطقة الرسم. تزداد قيمة x
عند التحرك لليسار، وتزداد قيمة y
عند التحرك
للأسفل.
على سبيل المثال، إذا كنت تريد رسم خط قطري من أعلى يسار
مساحة اللوحة إلى أسفل يمينها، يمكنك استخدام الدالة
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 ) } }
مساحة داخلية
استخدِم 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()
أكثر فعالية من إجراء طلبات بحث متداخلة لعمليات تحول individual
، لأنّه يتم تنفيذ جميع عمليات التحويل معًا في عملية
واحدة، بدلاً من أن تحتاج 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 ) } }
عمليات الرسم الشائعة
رسم نص
لرسم نص في ميزة "الإنشاء"، يمكنك عادةً استخدام العنصر القابل للتجميع 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() )
يتم الآن رسم النص ضمن القيود مع إضافة علامة حذف في النهاية:
رسم صورة
لرسم ImageBitmap
باستخدام DrawScope
، حمِّل الصورة باستخدام
ImageBitmap.imageResource()
ثم اتصل بالرقم drawImage
:
val dogImage = ImageBitmap.imageResource(id = R.drawable.dog) Canvas(modifier = Modifier.fillMaxSize(), onDraw = { drawImage(dogImage) })
رسم أشكال أساسية
هناك العديد من دوال رسم الأشكال على 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() )
الوصول إلى عنصر 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() )
مزيد من المعلومات
لمزيد من المعلومات حول ميزة "الرسم" في ميزة "الإنشاء"، يمكنك الاطّلاع على المراجع التالية:
- مُعدِّلات الرسومات: تعرَّف على الأنواع المختلفة لمُعدِّلات الرسم.
- الأداة المخصّصة للرسم: تعرَّف على كيفية تخصيص الرسم الخاص بمحتوى الفيديو.
- التنسيقات والرسومات المخصّصة في Compose - مؤتمر Android Dev Summit لعام 2022: تعرَّف على كيفية إنشاء واجهة مستخدم مخصّصة في Compose باستخدام التنسيقات والرسومات.
- عيّنة JetLagged: نموذج تركيب يوضّح كيفية رسم رسم بياني مخصّص.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما تكون لغة JavaScript غير مفعّلة.
- مُعدِّلات الرسومات
- الرسومات في ميزة "إنشاء"
- خطوط المحاذاة في Jetpack Compose