يجب أن تتمكن العديد من التطبيقات من التحكم بدقة في ما يتم رسمه على الشاشة. قد يكون هذا صغيرًا مثل وضع مربع أو دائرة على الشاشة في المكان المناسب تمامًا، أو قد يكون ترتيبًا متقنًا للعناصر الرسومية في العديد من الأنماط المختلفة.
رسم أساسي باستخدام أدوات تعديل وDrawScope
إنّ الطريقة الأساسية لرسم عنصر مخصّص في Compose هي باستخدام مفاتيح التعديل، مثل
Modifier.drawWithContent
وModifier.drawBehind
وModifier.drawWithCache
.
على سبيل المثال، لرسم عنصر خلف العنصر القابل للإنشاء، يمكنك استخدام
مفتاح التعديل drawBehind
لبدء تنفيذ أوامر الرسم:
Spacer( modifier = Modifier .fillMaxSize() .drawBehind { // this = DrawScope } )
إذا كنت بحاجة إلى عنصر قابل للإنشاء يرسم، يمكنك استخدام Canvas
القابل للإنشاء. يوفر لك "Canvas
" القابل للإنشاء واجهة مناسبة حول Modifier.drawBehind
. عليك وضع Canvas
في التنسيق
بنفس الطريقة التي تضع بها أي عنصر آخر في Compose UI. داخل 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
كلما تحرك
لأسفل.
على سبيل المثال، إذا أردت رسم خط قطري من الزاوية العلوية اليمنى
من مساحة لوحة الرسم إلى الزاوية السفلية اليسرى، يمكنك استخدام
الدالة 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()
أكثر فعالية من إجراء استدعاءات مدمجة لعمليات التحويل الفردية، لأنّه يتم تنفيذ جميع عمليات التحويل معًا في عملية واحدة، بدلاً من الحاجة إلى حساب كل من عمليات التحويل المتداخلة وحفظها.
على سبيل المثال، تطبق التعليمة البرمجية التالية كلاً من الترجمة والتدوير على المستطيل:
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
. على سبيل المثال، يعرض الرمز التالي النص بـ 1⁄3 ارتفاع و1⁄3 عرض المساحة القابلة للإنشاء، ويضبط 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، ألق نظرة على الموارد التالية:
- معدِّلات الرسومات - يمكنك التعرُّف على الأنواع المختلفة لمعدِّلات الرسومات.
- الفرشاة - تعرَّف على كيفية تخصيص طلاء المحتوى.
- التخطيطات والرسومات المخصّصة في Compose في مؤتمر Android Dev Summit لعام 2022: يمكنك التعرّف على كيفية إنشاء واجهة مستخدم مخصّصة في أداة "إنشاء" باستخدام التنسيقات والرسومات.
- نموذج JetLagged - أنشئ عينة تعرض كيفية رسم رسم بياني مخصّص.
أفلام مُقترَحة لك
- ملاحظة: يتم عرض نص الرابط عند إيقاف JavaScript.
- معدِّلات الرسومات
- الرسومات في Compose
- خطوط المحاذاة في Jetpack Compose