يحتاج العديد من التطبيقات إلى أن تكون قادرًا على التحكم بدقة في ما يتم رسمه على الشاشة. قد يكون ذلك بسيطًا مثل وضع مربّع أو دائرة على الشاشة في المكان المناسب تمامًا، أو قد يكون ترتيبًا متقنًا للعناصر الرسومية بالعديد من الأنماط المختلفة.
رسم أساسي باستخدام عوامل التعديل و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
- مُعدِّلات الرسومات
- الرسومات في Compose
- خطوط المحاذاة في Jetpack Compose