Compose में 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 को 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 सिर्फ़ ग्रेडिएंट को टाइल करेगा.
यहां दिया गया कोड, ग्रेडिएंट पैटर्न को चार बार दोहराएगा, क्योंकि 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 फ़ंक्शन में ड्रॉइंग एरिया के साइज़ का इस्तेमाल किया जा सकता है.
इस उदाहरण में, पैटर्न को चार बार दोहराने के लिए, साइज़ को चार से भाग दें:
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 शेडर की सुविधाओं का एक सबसेट मिलता है. शेडर को एजीएसएल में लिखा जा सकता है. साथ ही, Compose में ब्रश के साथ इस्तेमाल किया जा सकता है.
शेडर ब्रश बनाने के लिए, पहले शेडर को एजीएसएल शेडर स्ट्रिंग के तौर पर तय करें:
@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) ) }
इसे चलाने पर, आपको स्क्रीन पर यह रेंडर होता हुआ दिखेगा:
यह ध्यान देने वाली बात है कि शेडर की मदद से, ग्रेडिएंट के अलावा और भी बहुत कुछ किया जा सकता है. ऐसा इसलिए, क्योंकि यह पूरी तरह से गणित पर आधारित कैलकुलेशन है. एजीएसएल के बारे में ज़्यादा जानने के लिए, एजीएसएल का दस्तावेज़ देखें.
अन्य संसाधन
Compose में Brush का इस्तेमाल करने के ज़्यादा उदाहरणों के लिए, ये संसाधन देखें:
- Compose में ऐनिमेट होने वाले ब्रश से टेक्स्ट को रंगना 🖌️
- Compose में कस्टम ग्राफ़िक और लेआउट - Android Dev Summit 2022
- JetLagged Sample - RuntimeShader Brush
आपके लिए सुझाव
- ध्यान दें: JavaScript बंद होने पर, लिंक टेक्स्ट दिखता है
- ग्राफ़िक्स मॉडिफ़ायर
- Compose में ग्राफ़िक
- टेक्स्ट को स्टाइल करना