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