Brush در «نوشتن» نحوه رسم چیزی روی صفحه را شرح میدهد: این
رنگ(هایی) را که در ناحیه رسم (یعنی دایره،
مربع، مسیر) رسم میشود تعیین میکند. چند «قلممو» داخلی وجود دارد که برای طراحی مفید هستند،
مانند 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 باید بهصورت کسری بین ۰ و ۱ مشخص شود. مقادیر بزرگتر از ۱ باعث میشود که آن رنگها بهعنوان بخشی از گرادیان پرداز نشوند.
میتوانید ایستگاههای رنگ را پیکربندی کنید تا مقادیر مختلفی داشته باشند، مثلاً مقدار یک رنگ کمتر یا بیشتر باشد:
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 فقط درصورتی گرادیان را کاشیکاری میکند
که اندازه ناحیه بزرگتر از اندازه «برس» باشد.
کد زیر الگوی گرادیان را ۴ بار تکرار میکند، زیرا 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 استفاده کنید.
در این مثال، اندازه را بر ۴ تقسیم کنید تا الگو ۴ بار تکرار شود:
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 با آخرین اندازه ایجادشده متفاوت باشد، یا اگر وضعیت شیء استفادهشده در ایجاد سایهزن تغییر کرده باشد، Brush بهطور داخلی Shader را مجدداً تخصیص میدهد.
کد زیر سایهزن را سه بار با اندازههای مختلف ایجاد میکند، زیرا اندازه ناحیه طراحی تغییر میکند:
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 نوشت و با «قلممو» در «ترکیب» استفاده کرد.
برای ایجاد «قلم موی سایهزن»، ابتدا «سایهزن» را بهعنوان رشته سایهزن 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 را بررسی کنید.
منابع بیشتر
برای نمونههای بیشتر از استفاده از «قلممو» در «نوشتن»، منابع زیر را بررسی کنید:
- رنگآمیزی نوشتار با قلم موی پویانمایی در «نگارش» 🖌️
- گرافیکها و چیدمانهای سفارشی در «نوشتن» - «نشست توسعهدهندگان Android» ۲۰۲۲
- نمونه JetLagged - قلمموی RuntimeShader
توصیهشده برای شما
- توجه: نوشتار پیوند وقتی جاوا اسکریپت خاموش است نمایش داده میشود
- اصلاحکنندههای گرافیک
- گرافیک در Compose
- سبکبندی نوشتار