يصف 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 | الناتج |
|---|---|
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. يمكن كتابة برامج التظليل بلغة AGSL واستخدامها مع Brush في Compose.
لإنشاء فرشاة تظليل، عليك أولاً تحديد التظليل كسلسلة تظليل 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 بين اللونَين
استنادًا إلى المسافة. يؤدي ذلك إلى إنشاء تأثير متدرج.
بعد ذلك، أنشئ Shader Brush واضبط المتغيّرات الموحّدة لـ 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.
مراجع إضافية
لمزيد من الأمثلة على استخدام Brush في Compose، يمكنك الاطّلاع على المراجع التالية:
- تلوين النص باستخدام فرشاة متحركة في Compose 🖌️
- الرسومات والتنسيقات المخصّصة في Compose - مؤتمر Android Dev Summit لعام 2022
- JetLagged Sample - RuntimeShader Brush
التطبيقات المقترَحة لك
- ملاحظة: يتم عرض نص الرابط عندما يكون JavaScript غير مفعَّل
- عناصر تعديل الرسومات
- الرسومات في Compose
- تنسيق النص