ग्राफ़िक मॉडिफ़ायर

Canvas कंपोज़ेबल के अलावा, Compose में कई काम के ग्राफ़िक मौजूद हैं Modifiers, जो कस्टम कॉन्टेंट बनाने में मदद करते हैं. ये मॉडिफ़ायर काम के हैं क्योंकि इन्हें किसी भी कंपोज़ेबल में लागू किया जा सकता है.

ड्रॉइंग मॉडिफ़ायर

सभी ड्रॉइंग कमांड, Compose में ड्रॉइंग मॉडिफ़ायर की मदद से पूरे किए जाते हैं. यहां हैं Compose में तीन मुख्य ड्रॉइंग मॉडिफ़ायर:

ड्रॉइंग का बेस मॉडिफ़ायर drawWithContent है, जहां से तय किया जा सकता है कि आपके कंपोज़ेबल का ड्रॉइंग ऑर्डर और कार्रवाई बदलने वाली कुंजी. drawBehind एक drawWithContent के चारों ओर एक सुविधाजनक रैपर है, जिसमें कंपोज़ेबल के कॉन्टेंट के पीछे सेट किया गया ड्रॉइंग ऑर्डर. drawWithCache उसके अंदर से onDrawBehind या onDrawWithContent को कॉल करता है - और बनाए गए ऑब्जेक्ट को कैश मेमोरी में सेव करने का तरीका.

Modifier.drawWithContent: ड्रॉइंग का क्रम चुनें

Modifier.drawWithContent आपको प्रोजेक्ट के कॉन्टेंट से पहले या बाद में DrawScope कार्रवाइयां करनी होंगी कंपोज़ेबल. इसके बाद, इसका असल कॉन्टेंट रेंडर करने के लिए drawContent को कॉल करना न भूलें कंपोज़ेबल. इस मॉडिफ़ायर की मदद से, कार्रवाइयों का क्रम तय किया जा सकता है, अगर आपको अपनी पसंद के मुताबिक बनाई गई ड्रॉइंग से पहले या बाद में कॉन्टेंट बनाना है operations.

उदाहरण के लिए, अगर आपको अपने कॉन्टेंट के ऊपर रेडियल ग्रेडिएंट रेंडर करना है, तो फिर, ये काम किए जा सकते हैं:

var pointerOffset by remember {
    mutableStateOf(Offset(0f, 0f))
}
Column(
    modifier = Modifier
        .fillMaxSize()
        .pointerInput("dragging") {
            detectDragGestures { change, dragAmount ->
                pointerOffset += dragAmount
            }
        }
        .onSizeChanged {
            pointerOffset = Offset(it.width / 2f, it.height / 2f)
        }
        .drawWithContent {
            drawContent()
            // draws a fully black area with a small keyhole at pointerOffset that’ll show part of the UI.
            drawRect(
                Brush.radialGradient(
                    listOf(Color.Transparent, Color.Black),
                    center = pointerOffset,
                    radius = 100.dp.toPx(),
                )
            )
        }
) {
    // Your composables here
}

पहली इमेज: फ़्लैशलाइट टाइप का यूज़र इंटरफ़ेस (यूआई) अनुभव बनाने के लिए, कम्पोज़ेबल के ऊपर Modifier.drawWithContent का इस्तेमाल किया गया.

Modifier.drawBehind: किसी कंपोज़ेबल के पीछे की ड्रॉइंग

Modifier.drawBehind की मदद से, स्क्रीन पर दिखाए गए कंपोज़ेबल कॉन्टेंट के पीछे DrawScope कार्रवाइयां. अगर आपने Canvas को लागू करने पर एक नज़र डालने पर आपको दिखेगा कि Modifier.drawBehind के आस-पास एक सुविधाजनक रैपर है.

Text के पीछे एक गोल आयत बनाने के लिए:

Text(
    "Hello Compose!",
    modifier = Modifier
        .drawBehind {
            drawRoundRect(
                Color(0xFFBBAAEE),
                cornerRadius = CornerRadius(10.dp.toPx())
            )
        }
        .padding(4.dp)
)

इससे यह नतीजा मिलता है:

Modifier.drawBehind का इस्तेमाल करके बनाया गया टेक्स्ट और बैकग्राउंड
दूसरी इमेज: Modifier.drawBehind की मदद से बनाया गया टेक्स्ट और बैकग्राउंड

Modifier.drawWithCache: ड्रॉ ऑब्जेक्ट ड्रॉइंग और कैश मेमोरी में सेव करना

Modifier.drawWithCache ऑब्जेक्ट बनाए रखता है जो इसके कैश मेमोरी में सेव होते हैं. ऑब्जेक्ट, साइज़ के हिसाब से कैश मेमोरी में सेव किए जाते हैं समान या कोई भी स्टेट ऑब्जेक्ट जिन्हें पढ़ा गया है वे बदल दिया गया है. यह मॉडिफ़ायर, कॉल ड्रॉइंग की परफ़ॉर्मेंस को बेहतर बनाने के लिए काम का है यह ऑब्जेक्ट (जैसे: Brush, Shader, Path वगैरह) को फिर से आवंटित करने की ज़रूरत से बचाता है. जो ड्रॉ पर बनाए जाते हैं.

इसके अलावा, remember का इस्तेमाल करके भी ऑब्जेक्ट को कैश मेमोरी में सेव किया जा सकता है. इसके लिए, कार्रवाई बदलने वाली कुंजी. हालांकि, ऐसा हमेशा संभव नहीं होता, क्योंकि आपके पास हमेशा ऐक्सेस नहीं होता संगीत वीडियो से जुड़े हों. drawWithCache का इस्तेमाल करना ज़्यादा बेहतर हो सकता है, अगर ऑब्जेक्ट का इस्तेमाल सिर्फ़ ड्रॉइंग के लिए किया जाता है.

उदाहरण के लिए, अगर आपने Text के पीछे ग्रेडिएंट बनाने के लिए Brush बनाया है, तो drawWithCache, Brush ऑब्जेक्ट को ड्रॉइंग एरिया के साइज़ तक कैश मेमोरी में सेव करता है बदलाव:

Text(
    "Hello Compose!",
    modifier = Modifier
        .drawWithCache {
            val brush = Brush.linearGradient(
                listOf(
                    Color(0xFF9E82F0),
                    Color(0xFF42A5F5)
                )
            )
            onDrawBehind {
                drawRoundRect(
                    brush,
                    cornerRadius = CornerRadius(10.dp.toPx())
                )
            }
        }
)

ड्रॉरविथ कैश मेमोरी की मदद से ब्रश ऑब्जेक्ट को कैश मेमोरी में सेव करना
तीसरी इमेज: ड्रॉफ़्ट कैश की मदद से ब्रश ऑब्जेक्ट को कैश मेमोरी में सेव करना

ग्राफ़िक मॉडिफ़ायर

Modifier.graphicsLayer: कंपोज़ेबल में ट्रांसफ़ॉर्मेशन ऐक्शन लागू करें

Modifier.graphicsLayer एक मॉडिफ़ायर है, जो कंपोज़ेबल ड्रॉ के कॉन्टेंट को ड्रॉ लेयर में बनाता है. ऐप्लिकेशन लेयर में कुछ अलग-अलग फ़ंक्शन होते हैं, जैसे कि:

  • ड्रॉइंग बनाने के निर्देशों के लिए आइसोलेशन (RenderNode से मिलता-जुलता). ड्रॉइंग लेयर के भाग के रूप में कैप्चर किए गए निर्देशों को, ऐप्लिकेशन कोड को फिर से लागू किए बिना रेंडर करने वाले पाइपलाइन को.
  • इसमें मौजूद सभी ड्रॉइंग के निर्देशों पर लागू होने वाले बदलाव लेयर.
  • कंपोज़िशन की क्षमताओं के लिए रास्टराइज़ेशन. जब किसी लेयर को रास्टराइज़ किया जाता है, तो ड्रॉइंग के निर्देशों का पालन किया जाता है और आउटपुट को ऑफ़स्क्रीन में कैप्चर कर दिया जाता है बफ़र. बाद वाले फ़्रेम के लिए इस तरह के बफ़र को कंपोज़िट करना, इससे ज़्यादा तेज़ होता है अलग-अलग निर्देशों का पालन करता है, लेकिन जब यह लागू होता है, तो स्केलिंग या रोटेशन जैसे रूपांतरण लागू किए जाते हैं.

ट्रांसफ़ॉर्मेशन

Modifier.graphicsLayer, ड्रॉइंग से जुड़े निर्देशों को अलग से उपलब्ध कराता है; इसके लिए उदाहरण के लिए, Modifier.graphicsLayer का इस्तेमाल करके कई ट्रांसफ़ॉर्मेशन ऐक्शन लागू किए जा सकते हैं. इन्हें फिर से इस्तेमाल किए बिना, ऐनिमेट किया जा सकता है या इनमें बदलाव किया जा सकता है लैम्डा.

Modifier.graphicsLayer, आपके वीडियो के मेज़र किए गए साइज़ या प्लेसमेंट में बदलाव नहीं करता कंपोज़ेबल, क्योंकि यह सिर्फ़ ड्रॉ के चरण पर असर डालता है. इसका मतलब है कि आपको कंपोज़ेबल दूसरों को ओवरलैप कर सकता है, अगर वह अपनी लेआउट की सीमाओं से बाहर आ जाता है.

इस मॉडिफ़ायर का इस्तेमाल करके, यहां दिए गए बदलाव लागू किए जा सकते हैं:

स्केल - साइज़ बढ़ाएं

scaleX और scaleY, हॉरिज़ॉन्टल या वर्टिकल फ़ॉर्मैट में कॉन्टेंट को बड़ा या छोटा करते हैं दिशा-निर्देश. 1.0f की वैल्यू का मतलब है कि स्केल में कोई बदलाव नहीं हुआ है 0.5f का मतलब है, डाइमेंशन का आधा हिस्सा.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.scaleX = 1.2f
            this.scaleY = 0.8f
        }
)

चौथी इमेज: नई इमेज जोड़ने के लिए, schemaX औरScaleY का इस्तेमाल किया गया है
अनुवाद

translationX और translationY को graphicsLayer के साथ बदला जा सकता है, translationX, कंपोज़ेबल को बाईं या दाईं ओर ले जाता है. translationY कम या ज़्यादा किया जा सकता है.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.translationX = 100.dp.toPx()
            this.translationY = 10.dp.toPx()
        }
)

इमेज 5: Modifier.graphicslayer के साथ इमेज पर translateX और translateY लागू किया गया
रोटेशन

क्षैतिज रूप से घुमाने के लिए rotationX, लंबवत रूप से घुमाने के लिए rotationY और Z ऐक्सिस (स्टैंडर्ड रोटेशन) पर घुमाने के लिए, rotationZ दबाएं. यह मान बताया गया है डिग्री (0-360) में.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.rotationX = 90f
            this.rotationY = 275f
            this.rotationZ = 180f
        }
)

इमेज 6: Modifier.graphicslayer से इमेज पर रोटेशनX, रोटेशनवाई, और रोटेशनZ सेट किया गया है
Origin

कोई transformOrigin तय किया जा सकता है. इसके बाद, उसका इस्तेमाल उस बिंदु के तौर पर किया जाता है जहां से बदलाव होते रहते हैं. अब तक दिए गए सभी उदाहरणों TransformOrigin.Center, जो (0.5f, 0.5f) पर है. अगर ऑरिजिन के बारे में यहां बताया जाता है (0f, 0f), उसके बाद ट्रांसफ़ॉर्मेशन ऐक्शन, कंपोज़ेबल.

अगर ऑरिजिन को rotationZ ट्रांसफ़ॉर्मेशन से बदला जाता है, तो आपको दिखेगा कि आइटम कंपोज़ेबल के ऊपर बाईं ओर घूमता है:

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.transformOrigin = TransformOrigin(0f, 0f)
            this.rotationX = 90f
            this.rotationY = 275f
            this.rotationZ = 180f
        }
)

सातवीं इमेज: रोटेशन लागू किया गया है और TransformOrigin को 0f, 0f पर सेट किया गया है

क्लिप और आकार

आकार से उस आउटलाइन के बारे में पता चलता है जो clip = true जब कॉन्टेंट क्लिप करता है. तय सीमा में इस उदाहरण में, हम दो अलग-अलग क्लिप के लिए दो बॉक्स सेट करते हैं - एक graphicsLayer क्लिप वैरिएबल और दूसरा आसान रैपर का इस्तेमाल करके क्लिप Modifier.clip.

Column(modifier = Modifier.padding(16.dp)) {
    Box(
        modifier = Modifier
            .size(200.dp)
            .graphicsLayer {
                clip = true
                shape = CircleShape
            }
            .background(Color(0xFFF06292))
    ) {
        Text(
            "Hello Compose",
            style = TextStyle(color = Color.Black, fontSize = 46.sp),
            modifier = Modifier.align(Alignment.Center)
        )
    }
    Box(
        modifier = Modifier
            .size(200.dp)
            .clip(CircleShape)
            .background(Color(0xFF4DB6AC))
    )
}

पहले बॉक्स के कॉन्टेंट (“नमस्ते लिखें” टेक्स्ट) को वृत्त का आकार:

Box कंपोज़ेबल पर क्लिप लागू की गई
आठवीं इमेज: बॉक्स कंपोज़ेबल पर क्लिप का इस्तेमाल किया गया

इसके बाद, अगर सबसे ऊपर दिए गए गुलाबी गोले के ऊपर translationY लागू किया जाता है, तो आपको पता चलता है कि बाउंड कंपोज़ेबल में मौजूद चीज़ें पहले जैसी ही हैं, लेकिन नीचे की ओर सर्कल बना है सर्कल (और इसकी सीमाओं से बाहर) का इस्तेमाल करें.

क्लिप को TranslationY के साथ लागू किया गया है. साथ ही, आउटलाइन के लिए लाल रंग का बॉर्डर लगाया गया है
इमेज 9: ट्रांसलेशनY क्लिप लागू की गई है और आउटलाइन के लिए लाल बॉर्डर लगाया गया है

कंपोज़ेबल को जिस हिस्से में बनाया गया है उस हिस्से में क्लिप बनाने के लिए, दूसरा जोड़ें मॉडिफ़ायर चेन की शुरुआत में Modifier.clip(RectangleShape). कॉन्टेंट फिर मूल सीमाओं के अंदर ही रहता है.

Column(modifier = Modifier.padding(16.dp)) {
    Box(
        modifier = Modifier
            .clip(RectangleShape)
            .size(200.dp)
            .border(2.dp, Color.Black)
            .graphicsLayer {
                clip = true
                shape = CircleShape
                translationY = 50.dp.toPx()
            }
            .background(Color(0xFFF06292))
    ) {
        Text(
            "Hello Compose",
            style = TextStyle(color = Color.Black, fontSize = 46.sp),
            modifier = Modifier.align(Alignment.Center)
        )
    }

    Box(
        modifier = Modifier
            .size(200.dp)
            .clip(RoundedCornerShape(500.dp))
            .background(Color(0xFF4DB6AC))
    )
}

ग्राफ़िक्स लेयर ट्रांसफ़ॉर्मेशन के ऊपर क्लिप लागू की गई
इमेज 10: ग्राफ़िक्स लेयर ट्रांसफ़ॉर्मेशन के ऊपर लागू की गई क्लिप

ऐल्फ़ा

Modifier.graphicsLayer का इस्तेमाल करके, पूरे डेटा के लिए alpha (अपारदर्शिता) सेट किया जा सकता है लेयर. 1.0f पूरी तरह से ओपेक नहीं है और 0.0f दिखाई नहीं दे रहा है.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "clock",
    modifier = Modifier
        .graphicsLayer {
            this.alpha = 0.5f
        }
)

ऐल्फ़ा सुविधा वाली इमेज
इमेज 11: ऐल्फ़ा के साथ इमेज

कंपोज़िटिंग स्ट्रेटजी

ऐल्फ़ा और पारदर्शिता के साथ काम करना इतना आसान नहीं है, जितना कि ऐल्फ़ा वैल्यू. ऐल्फ़ा को बदलने के अतिरिक्त, आपके पास graphicsLayer पर CompositingStrategy. CompositingStrategy तय करता है कि कंपोज़ेबल का कॉन्टेंट एक-दूसरे के साथ कंपोज़िट किया गया (एक साथ रखा गया) जिसे पहले ही स्क्रीन पर बनाया जा चुका है.

ये अलग-अलग रणनीतियां हैं:

अपने-आप चालू और बंद (डिफ़ॉल्ट)

कंपोज़िटिंग की रणनीति, graphicsLayer के बाकी सदस्यों से तय होती है पैरामीटर का इस्तेमाल करें. अगर ऐल्फ़ा का साइज़ इससे कम है, तो यह लेयर को ऑफ़स्क्रीन बफ़र में रेंडर करता है 1.0f या RenderEffect सेट है. जब अल्फ़ा 1f से कम हो, तो कंपोज़िटिंग लेयर, कॉन्टेंट को रेंडर करने और फिर ड्रॉ करने के लिए अपने-आप बन जाती है यह ऑफ़स्क्रीन बफ़र, संबंधित ऐल्फ़ा वाले डेस्टिनेशन के लिए है. सेट किया जा रहा है RenderEffect या ओवरस्क्रोल, कॉन्टेंट को हमेशा ऑफ़स्क्रीन में रेंडर करता है बफ़र, CompositingStrategy सेट पर ध्यान दिए बिना.

ऑफ़स्क्रीन

कंपोज़ेबल के कॉन्टेंट को हमेशा ऑफ़स्क्रीन में रास्टराइज़ किया जाता है टेक्स्चर या बिटमैप का इस्तेमाल करें. यह इनके लिए काम का है कॉन्टेंट को मास्क करने और बेहतर परफ़ॉर्मेंस के लिए, BlendMode कार्रवाइयां लागू की जा रही हैं ड्रॉइंग करने के निर्देशों के जटिल सेट रेंडर करना.

CompositingStrategy.Offscreen का इस्तेमाल करने का एक उदाहरण, BlendModes के साथ है. नीचे दिया गया उदाहरण देखें, मान लें कि आपको किसी Image कंपोज़ेबल के हिस्सों को हटाने के लिए, एक ड्रॉ निर्देश जारी करना है BlendMode.Clear का इस्तेमाल करता है. अगर आप compositingStrategy को इस पर सेट नहीं करते हैं CompositingStrategy.Offscreen, BlendMode सभी कॉन्टेंट के साथ इंटरैक्ट करता है टैप करें.

Image(painter = painterResource(id = R.drawable.dog),
   contentDescription = "Dog",
   contentScale = ContentScale.Crop,
   modifier = Modifier
       .size(120.dp)
       .aspectRatio(1f)
       .background(
           Brush.linearGradient(
               listOf(
                   Color(0xFFC5E1A5),
                   Color(0xFF80DEEA)
               )
           )
       )
       .padding(8.dp)
       .graphicsLayer {
           compositingStrategy = CompositingStrategy.Offscreen
       }
       .drawWithCache {
           val path = Path()
           path.addOval(
               Rect(
                   topLeft = Offset.Zero,
                   bottomRight = Offset(size.width, size.height)
               )
           )
           onDrawWithContent {
               clipPath(path) {
                   // this draws the actual image - if you don't call drawContent, it wont
                   // render anything
                   this@onDrawWithContent.drawContent()
               }
               val dotSize = size.width / 8f
               // Clip a white border for the content
               drawCircle(
                   Color.Black,
                   radius = dotSize,
                   center = Offset(
                       x = size.width - dotSize,
                       y = size.height - dotSize
                   ),
                   blendMode = BlendMode.Clear
               )
               // draw the red circle indication
               drawCircle(
                   Color(0xFFEF5350), radius = dotSize * 0.8f,
                   center = Offset(
                       x = size.width - dotSize,
                       y = size.height - dotSize
                   )
               )
           }

       }
)

CompositingStrategy को Offscreen पर सेट करने पर, एक ऑफ़स्क्रीन बन जाती है टेक्स्चर की मदद से, कमांड को एक्ज़ीक्यूट करें (सिर्फ़ BlendMode को कंपोज़ेबल का कॉन्टेंट). इसके बाद, यह उसे पहले से रेंडर किए गए हिस्से के ऊपर रेंडर करता है जिसका असर पहले से बनाए गए कॉन्टेंट पर नहीं पड़ता.

इमेज पर Modifier.drawWithContent, सर्कल का संकेत दिखा रही है.साथ ही, ऐप्लिकेशन में B C C C C लाकर देखें
इमेज 12: Modifier.drawWithContent वाली इमेज पर सर्कल इंंडिकेशन दिख रहा है. साथ ही, ब्लेंडमोड.Clear और CompositingStrategy.Offscreen ऐप्लिकेशन में उपलब्ध

अगर आपने CompositingStrategy.Offscreen का इस्तेमाल नहीं किया, तो लागू करने के नतीजे BlendMode.Clear, डेस्टिनेशन में मौजूद सभी पिक्सल हटा देता है, भले ही वह कुछ भी हो पहले से सेट था– यानी विंडो का रेंडरिंग बफ़र (काला) दिखता रहेगा. कई जिसमें ऐल्फ़ा शामिल है, वह BlendModes के बिना उम्मीद के मुताबिक काम नहीं करेगा ऑफ़स्क्रीन बफ़र. लाल वृत्त संकेतक के चारों ओर काले रंग के गोले पर ध्यान दें:

एक इमेज पर Modifier.drawWithContent की इमेज, जिसमें सर्कल इंडिकेटर दिख रहा है. इसमें blMode.Clear और कोई CompositingStrategy सेट नहीं है
इमेज 13: एक इमेज पर मौजूद Modifier.drawWithContent, जिसमें सर्कल का संकेत दिख रहा है. इसमें blMode.Clear और कोई CompositingStrategy सेट नहीं है

इसे थोड़ा और समझने के लिए: अगर ऐप्लिकेशन में ट्रांसलूसंट विंडो होती है इस्तेमाल नहीं किया है और आपने CompositingStrategy.Offscreen का इस्तेमाल नहीं किया है, BlendMode पूरे ऐप्लिकेशन से इंटरैक्ट करेगा. इससे दिखाने के लिए सभी पिक्सल हट जाएंगे के नीचे दिया गया है, जैसा कि इस उदाहरण में बताया गया है:

कोई CompositingStrategy सेट नहीं किया गया है और MEMBERMode का इस्तेमाल किया जा रहा है.पारदर्शी विंडो बैकग्राउंड वाले ऐप्लिकेशन के साथ इसे साफ़ करें. गुलाबी वॉलपेपर, लाल स्टेटस वाले सर्कल के आस-पास के इलाके में दिखाया गया है.
इमेज 14: कोई CompositingStrategy सेट नहीं किया गया है और LayoutMode का इस्तेमाल किया जा रहा है.ट्रांसलूसंट विंडो बैकग्राउंड वाले ऐप्लिकेशन की मदद से साफ़ करें. ध्यान दें कि लाल स्टेटस वाले सर्कल के आस-पास के इलाके में, गुलाबी वॉलपेपर कैसे दिखता है.

ध्यान रखें कि CompositingStrategy.Offscreen का इस्तेमाल करते समय, एक ऑफ़स्क्रीन टेक्सचर, जो ड्रॉइंग एरिया का साइज़ होता है उसे बनाया जाता है और उस पर वापस रेंडर किया जाता है स्क्रीन. इस रणनीति का इस्तेमाल करके किए जाने वाले सभी ड्रॉइंग निर्देश, डिफ़ॉल्ट रूप से इस क्षेत्र में क्लिप किया गया. नीचे दिया गया कोड स्निपेट, ऑफ़स्क्रीन टेक्स्चर के इस्तेमाल पर स्विच करना:

@Composable
fun CompositingStrategyExamples() {
   Column(
       modifier = Modifier
           .fillMaxSize()
           .wrapContentSize(Alignment.Center)
   ) {
       /** Does not clip content even with a graphics layer usage here. By default, graphicsLayer
       does not allocate + rasterize content into a separate layer but instead is used
       for isolation. That is draw invalidations made outside of this graphicsLayer will not
       re-record the drawing instructions in this composable as they have not changed **/
       Canvas(
           modifier = Modifier
               .graphicsLayer()
               .size(100.dp) // Note size of 100 dp here
               .border(2.dp, color = Color.Blue)
       ) {
           // ... and drawing a size of 200 dp here outside the bounds
           drawRect(color = Color.Magenta, size = Size(200.dp.toPx(), 200.dp.toPx()))
       }

       Spacer(modifier = Modifier.size(300.dp))

       /** Clips content as alpha usage here creates an offscreen buffer to rasterize content
       into first then draws to the original destination **/
       Canvas(
           modifier = Modifier
               // force to an offscreen buffer
               .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
               .size(100.dp) // Note size of 100 dp here
               .border(2.dp, color = Color.Blue)
       ) {
           /** ... and drawing a size of 200 dp. However, because of the CompositingStrategy.Offscreen usage above, the
           content gets clipped **/
           drawRect(color = Color.Red, size = Size(200.dp.toPx(), 200.dp.toPx()))
       }
   }
}

CompositingStrategy.Auto बनाम CompositingStrategy.ऑफ़स्क्रीन - उस क्षेत्र की ऑफ़स्क्रीन क्लिप, जहां अपने आप नहीं होता है
15वीं इमेज: CompositingStrategy.Auto बनाम CompositingStrategy.ऑफ़स्क्रीन - किसी इलाके की ऑफ़स्क्रीन क्लिप, जहां अपने-आप नहीं दिखती है)
ModulateAlpha

यह कंपोज़िशन रणनीति हर ड्रॉइंग के लिए ऐल्फ़ा को मॉड्यूल करती है graphicsLayer में निर्देश रिकॉर्ड किए गए हैं. इससे, जब तक RenderEffect सेट नहीं होता, तब तक 1.0f से कम के ऐल्फ़ा के लिए ऑफ़स्क्रीन बफ़र, ताकि यह कर सके ऐल्फ़ा रेंडरिंग के लिए बेहतर तरीके से काम करेगा. हालांकि, इसके लिए अलग-अलग नतीजे हो सकते हैं ओवरलैप होने वाले कॉन्टेंट के लिए. ऐसे मामलों में जहां पहले से ही यह जानकारी उपलब्ध हो कि ओवरलैप नहीं कर रहा है, तो वह इससे बेहतर प्रदर्शन प्रदान कर सकता है 1 से कम अल्फ़ा मान वाले CompositingStrategy.Auto.

अलग-अलग कंपोज़िशन रणनीतियों का एक और उदाहरण नीचे दिया गया है - अलग-अलग कंपोज़ेबल के अलग-अलग हिस्सों में ऐल्फ़ा और Modulate लागू करना रणनीति:

@Preview
@Composable
fun CompositingStratgey_ModulateAlpha() {
  Column(
      modifier = Modifier
          .fillMaxSize()
          .padding(32.dp)
  ) {
      // Base drawing, no alpha applied
      Canvas(
          modifier = Modifier.size(200.dp)
      ) {
          drawSquares()
      }

      Spacer(modifier = Modifier.size(36.dp))

      // Alpha 0.5f applied to whole composable
      Canvas(modifier = Modifier
          .size(200.dp)
          .graphicsLayer {
              alpha = 0.5f
          }) {
          drawSquares()
      }
      Spacer(modifier = Modifier.size(36.dp))

      // 0.75f alpha applied to each draw call when using ModulateAlpha
      Canvas(modifier = Modifier
          .size(200.dp)
          .graphicsLayer {
              compositingStrategy = CompositingStrategy.ModulateAlpha
              alpha = 0.75f
          }) {
          drawSquares()
      }
  }
}

private fun DrawScope.drawSquares() {

  val size = Size(100.dp.toPx(), 100.dp.toPx())
  drawRect(color = Red, size = size)
  drawRect(
      color = Purple, size = size,
      topLeft = Offset(size.width / 4f, size.height / 4f)
  )
  drawRect(
      color = Yellow, size = size,
      topLeft = Offset(size.width / 4f * 2f, size.height / 4f * 2f)
  )
}

val Purple = Color(0xFF7E57C2)
val Yellow = Color(0xFFFFCA28)
val Red = Color(0xFFEF5350)

ModulateAlpha, हर व्यक्तिगत ड्रॉ कमांड पर ऐल्फ़ा सेट लागू करता है
इमेज 16: ModulateAlpha, हर अलग-अलग ड्रॉ कमांड पर ऐल्फ़ा सेट लागू करता है

किसी कंपोज़ेबल का कॉन्टेंट बिटमैप में लिखना

सामान्य इस्तेमाल का उदाहरण, किसी कंपोज़ेबल से Bitmap बनाना है. कॉपी करने के लिए किसी Bitmap में आपके कंपोज़ेबल का कॉन्टेंट शामिल है. इसका इस्तेमाल करके GraphicsLayer बनाएं rememberGraphicsLayer().

drawWithContent() का इस्तेमाल करके ड्रॉइंग कमांड को नई लेयर पर रीडायरेक्ट करें graphicsLayer.record{}. फिर इसका इस्तेमाल करके दिखाई देने वाले कैनवस में लेयर बनाएं drawLayer:

val coroutineScope = rememberCoroutineScope()
val graphicsLayer = rememberGraphicsLayer()
Box(
    modifier = Modifier
        .drawWithContent {
            // call record to capture the content in the graphics layer
            graphicsLayer.record {
                // draw the contents of the composable into the graphics layer
                this@drawWithContent.drawContent()
            }
            // draw the graphics layer on the visible canvas
            drawLayer(graphicsLayer)
        }
        .clickable {
            coroutineScope.launch {
                val bitmap = graphicsLayer.toImageBitmap()
                // do something with the newly acquired bitmap
            }
        }
        .background(Color.White)
) {
    Text("Hello Android", fontSize = 26.sp)
}

बिट मैप को डिस्क पर सेव किया जा सकता है और शेयर किया जा सकता है. ज़्यादा जानकारी के लिए, पूरा उदाहरण के तौर पर दिया गया स्निपेट. कोशिश करने से पहले, डिवाइस की अनुमतियों की जांच ज़रूर कर लें डिस्क पर सहेजने के लिए.

कस्टम ड्रॉइंग मॉडिफ़ायर

अपना कस्टम मॉडिफ़ायर बनाने के लिए, DrawModifier इंटरफ़ेस लागू करें. यह आपको ContentDrawScope का ऐक्सेस देता है, जो सार्वजनिक किए गए डेटा की तरह ही है Modifier.drawWithContent() का इस्तेमाल करते समय. इसके बाद, एक ही ड्रॉइंग को एक्सट्रैक्ट किया जा सकता है कोड हटाने और उपलब्ध कराने के लिए कस्टम ड्रॉइंग मॉडिफ़ायर में कार्रवाइयों के विकल्प सुविधाजनक रैपर; उदाहरण के लिए, Modifier.background() DrawModifier.

उदाहरण के लिए, अगर आपको ऐसा Modifier लागू करना था जो वर्टिकल तरीके से फ़्लिप होता हो सामग्री है, तो आप इस तरह से एक बना सकते हैं:

class FlippedModifier : DrawModifier {
    override fun ContentDrawScope.draw() {
        scale(1f, -1f) {
            this@draw.drawContent()
        }
    }
}

fun Modifier.flipped() = this.then(FlippedModifier())

फिर Text पर लागू किए गए इस फ़्लिप किए गए मॉडिफ़ायर का इस्तेमाल करें:

Text(
    "Hello Compose!",
    modifier = Modifier
        .flipped()
)

टेक्स्ट पर, कस्टम फ़्लिप किया गया मॉडिफ़ायर
इमेज 17: टेक्स्ट पर कस्टम फ़्लिप किया गया मॉडिफ़ायर

अन्य संसाधन

graphicsLayer और कस्टम ड्रॉइंग का इस्तेमाल करने वाले ज़्यादा उदाहरणों के लिए, यहां देखें इन संसाधनों की मदद से:

{% endverba नया %} {% verbatim %}