بالإضافة إلى الدالة المركّبة Canvas، تتضمّن أداة Compose العديد من الرسومات المفيدة
Modifiers التي تساعد في رسم محتوى مخصّص. هذه المُعدِّلات مفيدة لأنّه يمكن تطبيقها على أي دالة مركّبة.
معدِّلات الرسم
يتم تنفيذ جميع أوامر الرسم باستخدام معدِّل رسم في Compose. هناك ثلاثة معدِّلات رسم رئيسية في Compose:
المعدِّل الأساسي للرسم هو drawWithContent، حيث يمكنك تحديد ترتيب الرسم للدالة المركّبة وأوامر الرسم الصادرة داخل المعدِّل. drawBehind هو برنامج تضمين مناسب حول drawWithContent تم ضبط ترتيب الرسم فيه ليكون خلف محتوى الدالة المركّبة. drawWithCache
يستدعي إما onDrawBehind أو onDrawWithContent بداخله - ويوفر
آلية لتخزين الكائنات التي تم إنشاؤها فيها مؤقتًا.
Modifier.drawWithContent: اختيار ترتيب الرسم
يتيح لك Modifier.drawWithContent تنفيذ عمليات DrawScope قبل محتوى الدالة المركّبة أو بعده. احرص على استدعاء drawContent لعرض المحتوى الفعلي للدالة المركّبة. باستخدام هذا المُعدِّل، يمكنك تحديد ترتيب العمليات، إذا كنت تريد رسم المحتوى قبل عمليات الرسم المخصّصة أو بعدها.
على سبيل المثال، إذا أردت عرض تدرج شعاعي أعلى المحتوى لإنشاء تأثير ثقب المفتاح لضوء الفلاش على واجهة المستخدم، يمكنك إجراء ما يلي:
var pointerOffset by remember { mutableStateOf(Offset(0f, 0f)) } Column( modifier = Modifier .fillMaxSize() .pointerInput("dragging") { detectDragGestures { change, dragAmount -> pointerOffset += dragAmount } } .onSizeChanged { pointerOffset = Offset(it.width / 2f, it.height / 2f) } .drawWithContent { drawContent() // draws a fully black area with a small keyhole at pointerOffset that’ll show part of the UI. drawRect( Brush.radialGradient( listOf(Color.Transparent, Color.Black), center = pointerOffset, radius = 100.dp.toPx(), ) ) } ) { // Your composables here }
Modifier.drawBehind: الرسم خلف دالة مركّبة
تتيح لك دالة Modifier.drawBehind تنفيذ
عمليات DrawScope خلف المحتوى القابل للإنشاء الذي يتم رسمه على الشاشة. إذا
ألقيت نظرة على تنفيذ Canvas، قد تلاحظ أنّه
مجرّد برنامج تضمين مناسب حول Modifier.drawBehind.
لرسم مستطيل مستدير الزوايا خلف Text:
Text( "Hello Compose!", modifier = Modifier .drawBehind { drawRoundRect( Color(0xFFBBAAEE), cornerRadius = CornerRadius(10.dp.toPx()) ) } .padding(4.dp) )
والذي ينتج عنه النتيجة التالية:
Modifier.drawWithCache: رسم عناصر الرسم وتخزينها مؤقتًا
Modifier.drawWithCache يحتفظ بالكائنات
التي تم إنشاؤها بداخله مخزّنة مؤقتًا. يتم تخزين العناصر مؤقتًا طالما أنّ حجم مساحة الرسم هو نفسه، أو لم تتغيّر أي عناصر حالة تتم قراءتها. يفيد هذا المُعدِّل في تحسين أداء طلبات الرسم لأنّه يتجنّب الحاجة إلى إعادة تخصيص العناصر (مثل: Brush, Shader, Path وما إلى ذلك) التي يتم إنشاؤها عند الرسم.
بدلاً من ذلك، يمكنك أيضًا تخزين العناصر مؤقتًا باستخدام remember، خارج
المعدِّل. ومع ذلك، لا يكون هذا ممكنًا دائمًا لأنّه لا يمكنك دائمًا الوصول إلى المقطوعة الموسيقية. قد يكون من الأفضل استخدام drawWithCache إذا كانت
العناصر تُستخدم للرسم فقط.
على سبيل المثال، إذا أنشأت Brush لرسم تدرج خلف Text، يؤدي استخدام drawWithCache إلى تخزين عنصر Brush مؤقتًا إلى أن يتغيّر حجم مساحة الرسم:
Text( "Hello Compose!", modifier = Modifier .drawWithCache { val brush = Brush.linearGradient( listOf( Color(0xFF9E82F0), Color(0xFF42A5F5) ) ) onDrawBehind { drawRoundRect( brush, cornerRadius = CornerRadius(10.dp.toPx()) ) } } )
معدِّلات الرسومات
Modifier.graphicsLayer: تطبيق عمليات التحويل على الدوال المركّبة
Modifier.graphicsLayer
هو مُعدِّل يجعل محتوى الدالة المركّبة يرسم في طبقة رسم. توفر الطبقة بعض الوظائف المختلفة، مثل:
- عزل تعليمات الرسم (على غرار
RenderNode). يمكن إعادة إصدار تعليمات الرسم التي تم تسجيلها كجزء من طبقة بكفاءة من خلال مسار العرض بدون إعادة تنفيذ الرمز البرمجي للتطبيق. - التحويلات التي تنطبق على جميع تعليمات الرسم الواردة في طبقة.
- تنقيط إمكانيات التركيب عند تنقيط طبقة، يتم تنفيذ تعليمات الرسم الخاصة بها ويتم التقاط الناتج في مخزن مؤقت خارج الشاشة. تركيب هذا المخزن المؤقت للإطارات اللاحقة أسرع من تنفيذ التعليمات الفردية، ولكنه سيتصرف كصورة نقطية عند تطبيق تحويلات مثل القياس أو التدوير.
عمليات التحويل
يوفّر Modifier.graphicsLayer عزلًا لتعليمات الرسم،
على سبيل المثال، يمكن تطبيق عمليات تحويل مختلفة باستخدام
Modifier.graphicsLayer. ويمكن تحريكها أو تعديلها بدون الحاجة إلى
إعادة تنفيذ دالة lambda للرسم.
لا يغيّر Modifier.graphicsLayer الحجم أو الموضع المقاس للدالة المركّبة، لأنّه يؤثر فقط في مرحلة الرسم. هذا يعني أنّ الدالة المركّبة قد تتداخل مع دوال أخرى إذا انتهى بها الأمر بالرسم خارج حدود التنسيق.
يمكن تطبيق عمليات التحويل التالية باستخدام هذا المُعدِّل:
المقياس - زيادة الحجم
يؤدي استخدام scaleX وscaleY إلى تكبير المحتوى أو تصغيره في الاتجاه الأفقي أو العمودي على التوالي. تشير القيمة 1.0f إلى عدم حدوث تغيير في المقياس، بينما تشير القيمة 0.5f إلى نصف البُعد.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.scaleX = 1.2f this.scaleY = 0.8f } )
الترجمة
يمكن تغيير translationX وtranslationY باستخدام graphicsLayer،
translationX ينقل الدالة المركّبة إلى اليسار أو اليمين. يؤدي استخدام translationY إلى نقل الدالة المركّبة للأعلى أو للأسفل.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.translationX = 100.dp.toPx() this.translationY = 10.dp.toPx() } )
تدوير
اضبط rotationX للتدوير أفقيًا، وrotationY للتدوير عموديًا، وrotationZ للتدوير على المحور Z (التدوير العادي). يتم تحديد هذه القيمة بالدرجات (0-360).
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.rotationX = 90f this.rotationY = 275f this.rotationZ = 180f } )
الأصل
يمكن تحديد transformOrigin. ويتم استخدامها بعد ذلك كنقطة
تحدث منها التحويلات. استخدمت جميع الأمثلة حتى الآن
TransformOrigin.Center، وهو في (0.5f, 0.5f). إذا حدّدت نقطة الأصل على أنّها
(0f, 0f)، ستبدأ عمليات التحويل من أعلى يمين
الدالة المركّبة.
إذا غيّرت نقطة الأصل باستخدام تحويل rotationZ، يمكنك ملاحظة أنّ
العنصر يدور حول أعلى يمين الدالة المركّبة:
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "Sunset", modifier = Modifier .graphicsLayer { this.transformOrigin = TransformOrigin(0f, 0f) this.rotationX = 90f this.rotationY = 275f this.rotationZ = 180f } )
القص والشكل
يحدّد الشكل المخطط الذي يتم اقتصاص المحتوى إليه عند استخدام clip = true. في هذا المثال، نضبط مربّعَين ليكون لهما مقطعان مختلفان، أحدهما يستخدم متغيّر المقطع graphicsLayer، والآخر يستخدم برنامج تضمين مناسب Modifier.clip.
Column(modifier = Modifier.padding(16.dp)) { Box( modifier = Modifier .size(200.dp) .graphicsLayer { clip = true shape = CircleShape } .background(Color(0xFFF06292)) ) { Text( "Hello Compose", style = TextStyle(color = Color.Black, fontSize = 46.sp), modifier = Modifier.align(Alignment.Center) ) } Box( modifier = Modifier .size(200.dp) .clip(CircleShape) .background(Color(0xFF4DB6AC)) ) }
يتم اقتصاص محتوى المربّع الأول (النص الذي يقول "مرحبًا Compose") إلى الشكل الدائري:
إذا طبّقت بعد ذلك translationY على الدائرة الوردية العلوية، ستلاحظ أنّ حدود الدالة المركّبة لا تزال كما هي، ولكن يتم رسم الدائرة أسفل الدائرة السفلية (وخارج حدودها).
لاقتصاص الدالة المركّبة إلى المنطقة التي يتم رسمها فيها، يمكنك إضافة Modifier.clip(RectangleShape) آخر في بداية سلسلة المُعدِّلات. يظل المحتوى بعد ذلك
داخل الحدود الأصلية.
Column(modifier = Modifier.padding(16.dp)) { Box( modifier = Modifier .clip(RectangleShape) .size(200.dp) .border(2.dp, Color.Black) .graphicsLayer { clip = true shape = CircleShape translationY = 50.dp.toPx() } .background(Color(0xFFF06292)) ) { Text( "Hello Compose", style = TextStyle(color = Color.Black, fontSize = 46.sp), modifier = Modifier.align(Alignment.Center) ) } Box( modifier = Modifier .size(200.dp) .clip(RoundedCornerShape(500.dp)) .background(Color(0xFF4DB6AC)) ) }
إصدار أولي
يمكن استخدام Modifier.graphicsLayer لضبط alpha (التعتيم) للطبقة بأكملها. 1.0f معتم تمامًا و0.0f غير مرئي.
Image( painter = painterResource(id = R.drawable.sunset), contentDescription = "clock", modifier = Modifier .graphicsLayer { this.alpha = 0.5f } )
استراتيجية التركيب
إنّ العمل مع قناة ألفا والشفافية ليس دائمًا سهلاً مثل تغيير قيمة ألفا واحدة. بالإضافة إلى تغيير إصدار ألفا، يتوفّر أيضًا خيار ضبط CompositingStrategy على graphicsLayer. يحدّد CompositingStrategy كيفية دمج محتوى الدالة المركّبة مع المحتوى الآخر الذي تم رسمه على الشاشة.
في ما يلي الاستراتيجيات المختلفة:
تلقائي (الإعداد التلقائي)
يتم تحديد استراتيجية التركيب من خلال بقية مَعلمات graphicsLayer. يتم عرض الطبقة في مخزن مؤقت خارج الشاشة إذا كانت قيمة ألفا أقل من
1.0f أو تم ضبط RenderEffect. عندما تكون قيمة ألفا أقل من 1f، يتم إنشاء طبقة تركيب تلقائيًا لعرض المحتوى ثم رسم هذا المخزن المؤقت خارج الشاشة إلى الوجهة باستخدام قيمة ألفا المقابلة. يؤدي ضبط السمة
RenderEffect أو تجاوز حد التمرير إلى عرض المحتوى دائمًا في مخزن مؤقت
خارج الشاشة بغض النظر عن السمة CompositingStrategy التي تم ضبطها.
خارج الشاشة
يتم دائمًا تنقيط محتوى الدالة المركّبة إلى مادة عرض أو صورة نقطية خارج الشاشة قبل عرضه في الوجهة. هذا مفيد
لتطبيق عمليات BlendMode لإخفاء المحتوى، ولتحسين الأداء عند
عرض مجموعات معقدة من تعليمات الرسم.
يمكن استخدام CompositingStrategy.Offscreen مع BlendModes.
في المثال التالي، لنفترض أنّك تريد إزالة أجزاء من دالة مركّبة Image من خلال إصدار أمر رسم يستخدم BlendMode.Clear. إذا لم يتم ضبط السمة compositingStrategy على CompositingStrategy.Offscreen، سيتفاعل BlendMode مع كل المحتوى في الخلفية.
Image( painter = painterResource(id = R.drawable.dog), contentDescription = "Dog", contentScale = ContentScale.Crop, modifier = Modifier .size(120.dp) .aspectRatio(1f) .background( Brush.linearGradient( listOf( Color(0xFFC5E1A5), Color(0xFF80DEEA) ) ) ) .padding(8.dp) .graphicsLayer { compositingStrategy = CompositingStrategy.Offscreen } .drawWithCache { val path = Path() path.addOval( Rect( topLeft = Offset.Zero, bottomRight = Offset(size.width, size.height) ) ) onDrawWithContent { clipPath(path) { // this draws the actual image - if you don't call drawContent, it wont // render anything this@onDrawWithContent.drawContent() } val dotSize = size.width / 8f // Clip a white border for the content drawCircle( Color.Black, radius = dotSize, center = Offset( x = size.width - dotSize, y = size.height - dotSize ), blendMode = BlendMode.Clear ) // draw the red circle indication drawCircle( Color(0xFFEF5350), radius = dotSize * 0.8f, center = Offset( x = size.width - dotSize, y = size.height - dotSize ) ) } } )
من خلال ضبط CompositingStrategy على Offscreen، يتم إنشاء مادة عرض خارج الشاشة
لتنفيذ الأوامر (تطبيق BlendMode فقط على
محتوى هذه الدالة المركّبة). ثم يعرضها أعلى ما تم عرضه بالفعل على الشاشة، دون التأثير على المحتوى المرسوم بالفعل.
إذا لم تستخدم CompositingStrategy.Offscreen، فإنّ نتائج تطبيق
BlendMode.Clear ستؤدي إلى محو جميع وحدات البكسل في الوجهة، بغض النظر عمّا تم ضبطه مسبقًا، ما يؤدي إلى ظهور مخزن العرض المؤقت للنافذة (باللون الأسود). العديد من
BlendModes التي تتضمن ألفا لن تعمل كما هو متوقع بدون
مخزن مؤقت خارج الشاشة. لاحظ الحلقة السوداء حول مؤشر الدائرة الحمراء:
لفهم ذلك بشكل أفضل: إذا كان التطبيق يحتوي على خلفية نافذة شفافة، ولم تستخدم CompositingStrategy.Offscreen، سيتفاعل BlendMode مع التطبيق بأكمله. سيؤدي ذلك إلى محو جميع وحدات البكسل لإظهار التطبيق أو الخلفية تحته، كما في هذا المثال:
تجدر الإشارة إلى أنّه عند استخدام CompositingStrategy.Offscreen، يتم إنشاء مادة خارج الشاشة بحجم مساحة الرسم وعرضها مرة أخرى على الشاشة. وأي أوامر رسم يتم تنفيذها باستخدام هذه الاستراتيجية، يتم تلقائيًا
اقتصاصها في هذه المنطقة. يوضّح مقتطف الرمز التالي الاختلافات
عند التبديل إلى استخدام زخارف خارج الشاشة:
@Composable fun CompositingStrategyExamples() { Column( modifier = Modifier .fillMaxSize() .wrapContentSize(Alignment.Center) ) { // Does not clip content even with a graphics layer usage here. By default, graphicsLayer // does not allocate + rasterize content into a separate layer but instead is used // for isolation. That is draw invalidations made outside of this graphicsLayer will not // re-record the drawing instructions in this composable as they have not changed Canvas( modifier = Modifier .graphicsLayer() .size(100.dp) // Note size of 100 dp here .border(2.dp, color = Color.Blue) ) { // ... and drawing a size of 200 dp here outside the bounds drawRect(color = Color.Magenta, size = Size(200.dp.toPx(), 200.dp.toPx())) } Spacer(modifier = Modifier.size(300.dp)) /* Clips content as alpha usage here creates an offscreen buffer to rasterize content into first then draws to the original destination */ Canvas( modifier = Modifier // force to an offscreen buffer .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen) .size(100.dp) // Note size of 100 dp here .border(2.dp, color = Color.Blue) ) { /* ... and drawing a size of 200 dp. However, because of the CompositingStrategy.Offscreen usage above, the content gets clipped */ drawRect(color = Color.Red, size = Size(200.dp.toPx(), 200.dp.toPx())) } } }
ModulateAlpha
تعمل استراتيجية التركيب هذه على تعديل ألفا لكل تعليمات الرسم المسجّلة ضمن graphicsLayer. ولن يتم إنشاء مخزن مؤقت خارج الشاشة لقيمة ألفا أقل من 1.0f ما لم يتم ضبط RenderEffect، لذا يمكن أن يكون أكثر كفاءة في عرض ألفا. ومع ذلك، يمكن أن توفر نتائج
مختلفة للمحتوى المتداخل. في حالات الاستخدام التي يكون فيها معروفًا مسبقًا أنّ المحتوى لا يتداخل، يمكن أن يوفّر ذلك أداءً أفضل من CompositingStrategy.Auto مع قيم ألفا أقل من 1.
يوضّح المثال التالي استراتيجيات تركيب مختلفة، مثل تطبيق قيم ألفا مختلفة على أجزاء مختلفة من الدوال المركّبة، وتطبيق استراتيجية Modulate:
@Preview @Composable fun CompositingStrategy_ModulateAlpha() { Column( modifier = Modifier .fillMaxSize() .padding(32.dp) ) { // Base drawing, no alpha applied Canvas( modifier = Modifier.size(200.dp) ) { drawSquares() } Spacer(modifier = Modifier.size(36.dp)) // Alpha 0.5f applied to whole composable Canvas( modifier = Modifier .size(200.dp) .graphicsLayer { alpha = 0.5f } ) { drawSquares() } Spacer(modifier = Modifier.size(36.dp)) // 0.75f alpha applied to each draw call when using ModulateAlpha Canvas( modifier = Modifier .size(200.dp) .graphicsLayer { compositingStrategy = CompositingStrategy.ModulateAlpha alpha = 0.75f } ) { drawSquares() } } } private fun DrawScope.drawSquares() { val size = Size(100.dp.toPx(), 100.dp.toPx()) drawRect(color = Red, size = size) drawRect( color = Purple, size = size, topLeft = Offset(size.width / 4f, size.height / 4f) ) drawRect( color = Yellow, size = size, topLeft = Offset(size.width / 4f * 2f, size.height / 4f * 2f) ) } @Preview @Composable fun ModifierGraphicsLayerOutsets() { Column( modifier = Modifier .background(Color(0xFF0A0E14)) .padding(48.dp), verticalArrangement = Arrangement.spacedBy(48.dp), horizontalAlignment = Alignment.CenterHorizontally ) { val pillShape = RoundedCornerShape(percent = 50) // Without outsets: alpha = 0.5f creates an offscreen buffer that clips the 24.dp glow Box( modifier = Modifier .size( width = 140.dp, height = 56.dp ) .graphicsLayer( alpha = 0.5f, clip = false ) .dropShadow( shape = pillShape, shadow = Shadow(radius = 24.dp, color = Color.Cyan) ) .background(color = Color(0xFF141824), shape = pillShape), contentAlignment = Alignment.Center ) { Text( text = "✨ Glow", color = Color.White, fontSize = 18.sp ) } Box( modifier = Modifier .size( width = 140.dp, height = 56.dp ) .graphicsLayer( alpha = 0.5f, outsets = LayerOutsets(24.dp), clip = false ) .dropShadow( shape = pillShape, shadow = Shadow(radius = 24.dp, color = Color.Cyan) ) .background(color = Color(0xFF141824), shape = pillShape), contentAlignment = Alignment.Center ) { Text( text = "✨ Glow", color = Color.White, fontSize = 18.sp ) } } } val Purple = Color(0xFF7E57C2) val Yellow = Color(0xFFFFCA28) val Red = Color(0xFFEF5350)
الطبقات الخارجية
عند رسم دالة مركّبة في مخزن مؤقت خارج الشاشة (على سبيل المثال، عندما تكون قيمة alpha
أقل من 1.0f، أو عند ضبط RenderEffect، أو عند استخدام CompositingStrategy.Offscreen)، يتم ضبط مادة العرض خارج الشاشة تلقائيًا على حدود التنسيق المقاسة للدالة المركّبة. يتم تلقائيًا اقتصاص أي رسم أو ظل داخل الطبقة يمتد خارج حدود تنسيق الدالة المركّبة (مثل توهج خارجي مرسوم باستخدام Modifier.dropShadow) عند حدود المخزن المؤقت خارج الشاشة.
بدلاً من إضافة Modifier.padding() (الذي يغيّر قياس التنسيق لعناصر واجهة المستخدم المجاورة)، يمكنك تمرير LayerOutsets إلى المَعلمة outsets في Modifier.graphicsLayer. يؤدي ذلك إلى توسيع الحدود المرئية للمخزن المؤقت خارج الشاشة على
كل جانب بدون تغيير حجم التنسيق الذي تم قياسه للدالة المركّبة. يُرجى العِلم أنّ
LayerOutsets لا يوسّع شكل الاقتصاص أو حدود الظل للطبقة، والتي
تظل مستندة إلى الحجم الأصلي الذي تم قياسه للدالة المركّبة (لذا يجب إبقاء clip = false
على graphicsLayer لتجنُّب الاقتصاص إلى الحدود الأصلية):
Box( modifier = Modifier .size( width = 140.dp, height = 56.dp ) .graphicsLayer( alpha = 0.5f, outsets = LayerOutsets(24.dp), clip = false ) .dropShadow( shape = pillShape, shadow = Shadow(radius = 24.dp, color = Color.Cyan) ) .background(color = Color(0xFF141824), shape = pillShape), contentAlignment = Alignment.Center ) { Text( text = "✨ Glow", color = Color.White, fontSize = 18.sp ) }
LayerOutsets (في الأعلى، تم اقتصاصه عند حدود التنسيق المستطيل للدالة المركّبة) مقارنةً باستخدام LayerOutsets(24.dp) (في الأسفل، بدون اقتصاص)كتابة محتوى دالة مركّبة في صورة نقطية
من حالات الاستخدام الشائعة إنشاء Bitmap من دالة مركّبة. لنسخ محتوى الدالة المركّبة إلى Bitmap، أنشِئ GraphicsLayer باستخدام rememberGraphicsLayer().
يمكنك إعادة توجيه أوامر الرسم إلى الطبقة الجديدة باستخدام drawWithContent() وgraphicsLayer.record{}. بعد ذلك، ارسم الطبقة في اللوحة المرئية باستخدام
drawLayer:
val coroutineScope = rememberCoroutineScope() val graphicsLayer = rememberGraphicsLayer() Box( modifier = Modifier .drawWithContent { // call record to capture the content in the graphics layer graphicsLayer.record { // draw the contents of the composable into the graphics layer this@drawWithContent.drawContent() } // draw the graphics layer on the visible canvas drawLayer(graphicsLayer) } .clickable { coroutineScope.launch { val bitmap = graphicsLayer.toImageBitmap() // do something with the newly acquired bitmap } } .background(Color.White) ) { Text("Hello Android", fontSize = 26.sp) }
يمكنك حفظ الصورة النقطية على القرص ومشاركتها. لمزيد من التفاصيل، يمكنك الاطّلاع على المقتطف الكامل للمثال. تأكَّد من التحقّق من الأذونات على الجهاز قبل محاولة الحفظ على القرص.
معدِّل الرسم المخصّص
لإنشاء معدِّل مخصّص، عليك تنفيذ واجهة DrawModifier. يمنحك هذا الإذن إمكانية الوصول إلى ContentDrawScope، وهو الإذن نفسه الذي يتم منحه عند استخدام Modifier.drawWithContent(). يمكنك بعد ذلك استخراج عمليات الرسم الشائعة
إلى معدِّلات رسم مخصّصة لتنظيف الرمز البرمجي وتوفير
أغلفة ملائمة، على سبيل المثال، Modifier.background() هو DrawModifier
ملائم.
على سبيل المثال، إذا أردت تنفيذ Modifier يقلب المحتوى عموديًا، يمكنك إنشاء واحد على النحو التالي:
class FlippedModifier : DrawModifier { override fun ContentDrawScope.draw() { scale(1f, -1f) { this@draw.drawContent() } } } fun Modifier.flipped() = this.then(FlippedModifier())
ثم استخدِم هذا المُعدِّل المعكوس المطبَّق على Text:
Text( "Hello Compose!", modifier = Modifier .flipped() )
مراجع إضافية
للاطّلاع على المزيد من الأمثلة التي تستخدم graphicsLayer والرسم المخصّص، يُرجى مراجعة
المراجع التالية:
التطبيقات المقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما يكون JavaScript غير مفعَّل
- الرسومات في Compose
- تخصيص صورة {:#customize-image}
- Kotlin لـ Jetpack Compose