تصف العلامة Brush
في Compose طريقة رسم عنصر على الشاشة: فهي تحدد الألوان التي يتم رسمها في منطقة الرسم (أي دائرة أو مربع أو مسار). يمكن استخدام بعض الفُرش المدمَجة في الرسم، مثل LinearGradient
أو RadialGradient
أو فرشاة SolidColor
عادية.
يمكن استخدام الفرشاة مع Modifier.background()
أو TextStyle
أو
DrawScope
لرسم طلبات لتطبيق نمط الرسم على المحتوى الذي يتم رسمه.
على سبيل المثال، يمكن استخدام فرشاة التدرج الأفقية لرسم دائرة في DrawScope
:
val brush = Brush.horizontalGradient(listOf(Color.Red, Color.Blue)) Canvas( modifier = Modifier.size(200.dp), onDraw = { drawCircle(brush) } )
فُرش متدرجة
هناك العديد من فُرش تدرّج الألوان المدمجة التي يمكن استخدامها لإنشاء تأثيرات تدرّج مختلفة. تتيح لك هذه الفُرش تحديد قائمة الألوان التي تريد إنشاء تدرج منها.
قائمة بفُرش التدرج المتاحة والمخرجات المقابلة لها:
نوع الفرشاة المتدرجة | ناتج |
---|---|
Brush.horizontalGradient(colorList) |
|
Brush.linearGradient(colorList) |
|
Brush.verticalGradient(colorList) |
|
Brush.sweepGradient(colorList)
ملاحظة: للحصول على انتقال سلس بين الألوان، عليك ضبط اللون الأخير على لون البداية. |
|
Brush.radialGradient(colorList) |
تغيير توزيع الألوان باستخدام colorStops
لتخصيص كيفية ظهور الألوان في التدرج، يمكنك تعديل
قيمة colorStops
لكل لون. يجب تحديد colorStops
ككسر، بين 0 و1. وستؤدي القيم الأكبر من 1 إلى عدم عرض هذه الألوان
كجزء من التدرج.
ويمكنك ضبط مواضع إيقاف الألوان لتظهر بكميات مختلفة، مثلاً أقل أو أكثر من لون واحد:
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) Box( modifier = Modifier .requiredSize(200.dp) .background(Brush.horizontalGradient(colorStops = colorStops)) )
تتوزع الألوان حسب الإزاحة المتوفّرة على النحو المحدّد في زوج colorStop
، ويكون اللون الأصفر أقل من اللون الأحمر والأزرق.
تكرار نقش مع TileMode
تحتوي كل فرشاة تدرج على خيار ضبط TileMode
عليها. قد لا تلاحظ TileMode
إذا لم تضبط بداية ونهاية للتدرج، لأنّه سيتم تلقائيًا ملء المنطقة بالكامل. لن يطبّق TileMode
تجانب على التدرج إلا إذا كان حجم المساحة أكبر من حجم الفرشاة.
سيكرر الرمز التالي نمط التدرج 4 مرات، لأنّه تم ضبط endX
على 50.dp
والحجم على 200.dp
:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val tileSize = with(LocalDensity.current) { 50.dp.toPx() } Box( modifier = Modifier .requiredSize(200.dp) .background( Brush.horizontalGradient( listColors, endX = tileSize, tileMode = TileMode.Repeated ) ) )
في ما يلي جدول يفصّل وظيفة "أوضاع التجانب" المختلفة في مثال HorizontalGradient
أعلاه:
وضع تجانب | ناتج |
---|---|
TileMode.Repeated : يتم تكرار الحافة من اللون الأخير إلى الأول. |
|
TileMode.Mirror : يتم عكس اللون من آخر لون إلى أول لون الحافة. |
|
TileMode.Clamp : يتم تثبيت الحافة باللون النهائي. وبعد ذلك، سترسم أقرب لون لبقية المنطقة. |
|
TileMode.Decal : يتم عرض هذه السمة بحجم يصل إلى حجم الحدود فقط. يستفيد TileMode.Decal من اللون الأسود الشفاف لإنشاء عيّنات من المحتوى خارج الحدود الأصلية، في حين يستخدم TileMode.Clamp عيّنة من لون الحافة. |
تعمل TileMode
بطريقة مماثلة لتدرجات الاتجاه الأخرى، حيث يكون الاختلاف هو اتجاه حدوث التكرار.
تغيير حجم الفرشاة
إذا كنت تعرف حجم المنطقة التي سيتم رسم الفرشاة فيها، يمكنك ضبط المربّع endX
كما هو موضَّح أعلاه في القسم TileMode
. إذا كنت في DrawScope
، يمكنك استخدام السمة size
لمعرفة حجم المنطقة.
إذا كنت لا تعرف حجم مساحة الرسم (مثلاً إذا كانت
Brush
مخصّصة للنص)، يمكنك توسيع Shader
واستخدام حجم
مساحة الرسم في الدالة createShader
.
في هذا المثال، اقسم الحجم على 4 لتكرار النمط 4 مرات:
val listColors = listOf(Color.Yellow, Color.Red, Color.Blue) val customBrush = remember { object : ShaderBrush() { override fun createShader(size: Size): Shader { return LinearGradientShader( colors = listColors, from = Offset.Zero, to = Offset(size.width / 4f, 0f), tileMode = TileMode.Mirror ) } } } Box( modifier = Modifier .requiredSize(200.dp) .background(customBrush) )
يمكنك أيضًا تغيير حجم الفرشاة لأي تدرج آخر، مثل التدرجات الشعاعية. إذا لم تحدّد الحجم والوسط، سيشغل التدرج الحدود الكاملة للسمة DrawScope
، وسيتم ضبط منتصف التدرج الشعاعي تلقائيًا على وسط حدود DrawScope
. ينتج عن هذا ظهور مركز التدرج الشعاعي كمركز للبعد الأصغر (إما العرض أو الارتفاع):
Box( modifier = Modifier .fillMaxSize() .background( Brush.radialGradient( listOf(Color(0xFF2be4dc), Color(0xFF243484)) ) ) )
عندما يتم تغيير التدرج الشعاعي لضبط حجم نصف القطر على أقصى بُعد، يتضح لك أنه ينتج تأثير تدرج شعاعي أفضل:
val largeRadialGradient = object : ShaderBrush() { override fun createShader(size: Size): Shader { val biggerDimension = maxOf(size.height, size.width) return RadialGradientShader( colors = listOf(Color(0xFF2be4dc), Color(0xFF243484)), center = size.center, radius = biggerDimension / 2f, colorStops = listOf(0f, 0.95f) ) } } Box( modifier = Modifier .fillMaxSize() .background(largeRadialGradient) )
الجدير بالذكر أن الحجم الفعلي الذي يتم تمريره إلى إنشاء
التظليل يتم تحديده من حيث تم استدعاؤه. وحسب الإعدادات التلقائية، سيعيد Brush
تخصيص Shader
داخليًا إذا كان الحجم مختلفًا عن آخر عملية إنشاء لـ Brush
أو إذا تغيّر عنصر الحالة المستخدَم في إنشاء أداة التظليل.
تنشئ التعليمة البرمجية التالية أداة التظليل ثلاث مرات مختلفة بأحجام مختلفة، حيث يتغير حجم منطقة الرسم:
val colorStops = arrayOf( 0.0f to Color.Yellow, 0.2f to Color.Red, 1f to Color.Blue ) val brush = Brush.horizontalGradient(colorStops = colorStops) Box( modifier = Modifier .requiredSize(200.dp) .drawBehind { drawRect(brush = brush) // will allocate a shader to occupy the 200 x 200 dp drawing area inset(10f) { /* Will allocate a shader to occupy the 180 x 180 dp drawing area as the inset scope reduces the drawing area by 10 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) inset(5f) { /* will allocate a shader to occupy the 170 x 170 dp drawing area as the inset scope reduces the drawing area by 5 pixels on the left, top, right, bottom sides */ drawRect(brush = brush) } } } )
استخدام صورة كفرشاة
لاستخدام ImageBitmap على هيئة Brush
، يجب تحميل الصورة بتنسيق ImageBitmap
وإنشاء فرشاة ImageShader
:
val imageBrush = ShaderBrush(ImageShader(ImageBitmap.imageResource(id = R.drawable.dog))) // Use ImageShader Brush with background Box( modifier = Modifier .requiredSize(200.dp) .background(imageBrush) ) // Use ImageShader Brush with TextStyle Text( text = "Hello Android!", style = TextStyle( brush = imageBrush, fontWeight = FontWeight.ExtraBold, fontSize = 36.sp ) ) // Use ImageShader Brush with DrawScope#drawCircle() Canvas(onDraw = { drawCircle(imageBrush) }, modifier = Modifier.size(200.dp))
يتم تطبيق الفرشاة على بضعة أنواع مختلفة من الرسم: الخلفية والنص ولوحة الرسم. ينتج عن ذلك ما يلي:
يُرجى العلم أنّه يتم عرض النص الآن أيضًا باستخدام ImageBitmap
لرسم وحدات البكسل للنص.
مثال متقدم: فرشاة مخصصة
فرشاة AGSL RuntimeShader
يوفّر AGSL مجموعة فرعية من إمكانات GLSL Shader. يمكن كتابة التظليلات بلغة AGSL واستخدامها مع الفرشاة في Compose.
لإنشاء فرشاة Shader، حدد أولاً Shader كسلسلة تظليل AGSL:
@Language("AGSL") val CUSTOM_SHADER = """ uniform float2 resolution; layout(color) uniform half4 color; layout(color) uniform half4 color2; half4 main(in float2 fragCoord) { float2 uv = fragCoord/resolution.xy; float mixValue = distance(uv, vec2(0, 1)); return mix(color, color2, mixValue); } """.trimIndent()
تأخذ أداة التظليل أعلاه لونين للإدخال، وتحسب المسافة من أسفل اليسار (vec2(0, 1)
) من منطقة الرسم وتقوم بقيمة mix
بين اللونين بناءً على المسافة. وينتج عن ذلك تأثير التدرج.
بعد ذلك، أنشِئ فرشاة التظليل، واضبط الزي الرسمي لـ resolution
، أي حجم منطقة الرسم والسمتَين color
وcolor2
اللتين تريد استخدامهما كمدخل للتدرج المخصّص:
val Coral = Color(0xFFF3A397) val LightYellow = Color(0xFFF8EE94) @RequiresApi(Build.VERSION_CODES.TIRAMISU) @Composable @Preview fun ShaderBrushExample() { Box( modifier = Modifier .drawWithCache { val shader = RuntimeShader(CUSTOM_SHADER) val shaderBrush = ShaderBrush(shader) shader.setFloatUniform("resolution", size.width, size.height) onDrawBehind { shader.setColorUniform( "color", android.graphics.Color.valueOf( LightYellow.red, LightYellow.green, LightYellow .blue, LightYellow.alpha ) ) shader.setColorUniform( "color2", android.graphics.Color.valueOf( Coral.red, Coral.green, Coral.blue, Coral.alpha ) ) drawRect(shaderBrush) } } .fillMaxWidth() .height(200.dp) ) }
عند تشغيل ذلك، يمكنك رؤية ما يلي على الشاشة:
من الجدير بالذكر أنه يمكنك القيام بالكثير باستخدام أدوات التظليل أكثر من مجرد التدرجات، لأنها كلها عمليات حسابية تستنِد إلى الرياضيات. لمزيد من المعلومات حول AGSL، يمكنك الاطّلاع على وثائق AGSL.
مصادر إضافية
لعرض المزيد من الأمثلة على استخدام الفرشاة في Compose، يمكنك الاطّلاع على المراجع التالية:
- تلوين النص باستخدام فرشاة الرسم في Compose 🖌️
- الرسومات والتصميمات المخصَّصة في Compose (مؤتمر Android Dev Summit) لعام 2022
- نموذج JetLagged - فرشاة RuntimeShader
أفلام مُقترَحة لك
- ملاحظة: يظهر نص الرابط عند إيقاف JavaScript
- معدِّلات الرسومات
- الرسومات في Compose
- نمط النص