कम्पोज़ में ग्राफ़िक्स

कई ऐप्लिकेशन को स्क्रीन पर दिखने वाले कॉन्टेंट को सटीक तरीके से कंट्रोल करने की ज़रूरत होती है. यह स्क्रीन पर सही जगह पर बॉक्स या सर्कल डालने जितना छोटा हो सकता है या फिर कई अलग-अलग स्टाइल में ग्राफ़िक एलिमेंट की एक बड़ी व्यवस्था हो सकती है.

मॉडिफ़ायर और DrawScope का इस्तेमाल करके बेसिक ड्रॉइंग बनाना

Compose में अपनी पसंद के मुताबिक कुछ ड्रॉ करने का मुख्य तरीका, मॉडिफ़ायर का इस्तेमाल करना है. जैसे, Modifier.drawWithContent, Modifier.drawBehind, और Modifier.drawWithCache.

उदाहरण के लिए, अपने कंपोज़ेबल के पीछे कुछ ड्रॉ करने के लिए, drawBehind मॉडिफ़ायर का इस्तेमाल करके, ड्रॉइंग कमांड को लागू करना शुरू किया जा सकता है:

Spacer(
    modifier = Modifier
        .fillMaxSize()
        .drawBehind {
            // this = DrawScope
        }
)

अगर आपको सिर्फ़ ड्रॉ करने वाला कंपोज़ेबल चाहिए, तो Canvas कंपोज़ेबल का इस्तेमाल किया जा सकता है. Canvas कंपोज़ेबल, Modifier.drawBehind के लिए एक सुविधाजनक रैपर है. Canvas को अपने लेआउट में उसी तरह से रखा जाता है जिस तरह से किसी अन्य Compose यूज़र इंटरफ़ेस (यूआई) एलिमेंट को रखा जाता है. Canvas में, एलिमेंट की स्टाइल और जगह पर पूरा कंट्रोल रखते हुए, उन्हें ड्रॉ किया जा सकता है.

सभी ड्रॉइंग मॉडिफ़ायर, DrawScope को एक्सपोज़ करते हैं. यह एक स्कोप्ड ड्रॉइंग एनवायरमेंट है, जो अपनी स्थिति को बनाए रखता है. इससे आपको ग्राफ़िक एलिमेंट के ग्रुप के लिए पैरामीटर सेट करने की सुविधा मिलती है. DrawScope में कई काम के फ़ील्ड होते हैं, जैसे कि size. यह एक Size ऑब्जेक्ट है, जो DrawScope के मौजूदा डाइमेंशन के बारे में बताता है.

कुछ ड्रॉ करने के लिए, DrawScope पर मौजूद कई ड्रॉ फ़ंक्शन में से किसी एक का इस्तेमाल किया जा सकता है. उदाहरण के लिए, नीचे दिया गया कोड स्क्रीन के सबसे ऊपर बाएं कोने में एक रेक्टैंगल बनाता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasQuadrantSize = size / 2F
    drawRect(
        color = Color.Magenta,
        size = canvasQuadrantSize
    )
}

सफ़ेद बैकग्राउंड पर बना गुलाबी रंग का आयत, जो स्क्रीन का एक चौथाई हिस्सा लेता है
पहली इमेज. Compose में Canvas का इस्तेमाल करके बनाया गया रेक्टैंगल.

ड्रॉइंग मॉडिफ़ायर के बारे में ज़्यादा जानने के लिए, ग्राफ़िक्स मॉडिफ़ायर का दस्तावेज़ देखें.

कोऑर्डिनेट सिस्टम

स्क्रीन पर कुछ ड्रॉ करने के लिए, आपको ऑफ़सेट (x और y) और आइटम के साइज़ की जानकारी होनी चाहिए. DrawScope पर ड्रॉ करने के कई तरीकों में, पोज़िशन और साइज़ की जानकारी, डिफ़ॉल्ट पैरामीटर वैल्यू से मिलती है. डिफ़ॉल्ट पैरामीटर आम तौर पर, आइटम को कैनवस पर [0, 0] पॉइंट पर रखते हैं और डिफ़ॉल्ट size देते हैं, जो पूरे ड्रॉइंग एरिया को भर देता है. जैसा कि ऊपर दिए गए उदाहरण में दिखाया गया है - रेक्टैंगल को सबसे ऊपर बाईं ओर रखा गया है. अपने आइटम के साइज़ और पोज़िशन में बदलाव करने के लिए, आपको Compose में कोऑर्डिनेट सिस्टम को समझना होगा.

निर्देशांक सिस्टम ([0,0]) का ऑरिजिन, ड्रॉइंग एरिया में सबसे ऊपर बाईं ओर मौजूद पिक्सल पर होता है. दाईं ओर जाने पर x की वैल्यू बढ़ती है और नीचे की ओर जाने पर y की वैल्यू बढ़ती है.

एक ग्रिड, जिसमें निर्देशांक सिस्टम दिखाया गया है. इसमें सबसे ऊपर बाईं ओर [0, 0] और सबसे नीचे दाईं ओर [चौड़ाई, ऊंचाई] दिखाया गया है
दूसरी इमेज. ड्रॉइंग कोऑर्डिनेट सिस्टम / ड्रॉइंग ग्रिड.

उदाहरण के लिए, अगर आपको कैनवस एरिया के सबसे ऊपर दाएं कोने से सबसे नीचे बाएं कोने तक एक तिरछी लाइन खींचनी है, तो DrawScope.drawLine() फ़ंक्शन का इस्तेमाल किया जा सकता है. साथ ही, x और y की पोज़िशन के हिसाब से, शुरुआती और आखिरी ऑफ़सेट तय किया जा सकता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasWidth = size.width
    val canvasHeight = size.height
    drawLine(
        start = Offset(x = canvasWidth, y = 0f),
        end = Offset(x = 0f, y = canvasHeight),
        color = Color.Blue
    )
}

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

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

स्केल

ड्रॉइंग ऑपरेशन के साइज़ को किसी फ़ैक्टर से बढ़ाने के लिए, DrawScope.scale() का इस्तेमाल करें. scale() जैसे ऑपरेशन, संबंधित लैम्ब्डा के अंदर मौजूद सभी ड्रॉइंग ऑपरेशन पर लागू होते हैं. उदाहरण के लिए, यहां दिया गया कोड scaleX को 10 गुना और scaleY को 15 गुना बढ़ाता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    scale(scaleX = 10f, scaleY = 15f) {
        drawCircle(Color.Blue, radius = 20.dp.toPx())
    }
}

एक सर्कल, जिसे असमान रूप से स्केल किया गया है
तीसरी इमेज. Canvas पर किसी वृत्त को स्केल करने की प्रोसेस.

अनुवाद करें

ड्रॉइंग ऑपरेशन को ऊपर, नीचे, बाएं या दाएं ले जाने के लिए, DrawScope.translate() का इस्तेमाल करें. उदाहरण के लिए, इस कोड से ड्रॉइंग को 100 पिक्सल दाईं ओर और 300 पिक्सल ऊपर ले जाया जा सकता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    translate(left = 100f, top = -300f) {
        drawCircle(Color.Blue, radius = 200.dp.toPx())
    }
}

एक सर्कल, जो सेंटर से हट गया है
चौथी इमेज. Canvas पर किसी सर्कल को अनुवाद करने की कार्रवाई लागू की जा रही है.

घुमाएं

किसी पिवट पॉइंट के आस-पास ड्रॉइंग ऑपरेशन को घुमाने के लिए, DrawScope.rotate() का इस्तेमाल करें. उदाहरण के लिए, यह कोड किसी रेक्टैंगल को 45 डिग्री घुमाता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    rotate(degrees = 45F) {
        drawRect(
            color = Color.Gray,
            topLeft = Offset(x = size.width / 3F, y = size.height / 3F),
            size = size / 3F
        )
    }
}

एक फ़ोन, जिसकी स्क्रीन के बीच में 45 डिग्री पर घुमाया गया रेक्टैंगल दिख रहा है
पांचवीं इमेज. हम rotate() का इस्तेमाल करके, मौजूदा ड्रॉइंग स्कोप को घुमाते हैं. इससे रेक्टैंगल 45 डिग्री घूम जाता है.

इनसेट

मौजूदा DrawScope के डिफ़ॉल्ट पैरामीटर में बदलाव करने के लिए, DrawScope.inset() का इस्तेमाल करें. इससे ड्रॉइंग की सीमाओं में बदलाव किया जा सकता है और ड्रॉइंग का अनुवाद किया जा सकता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    val canvasQuadrantSize = size / 2F
    inset(horizontal = 50f, vertical = 30f) {
        drawRect(color = Color.Green, size = canvasQuadrantSize)
    }
}

यह कोड, ड्रॉइंग कमांड में पैडिंग को असरदार तरीके से जोड़ता है:

एक ऐसा रेक्टैंगल जिसके चारों ओर पैडिंग की गई है
छठी इमेज. ड्रॉइंग कमांड पर इनसेट लागू करना.

एक से ज़्यादा ट्रांसफ़ॉर्मेशन

अपनी ड्रॉइंग में कई ट्रांसफ़ॉर्मेशन लागू करने के लिए, DrawScope.withTransform() फ़ंक्शन का इस्तेमाल करें. यह फ़ंक्शन, एक ऐसा ट्रांसफ़ॉर्मेशन बनाता है और लागू करता है जिसमें आपके सभी मनचाहे बदलाव शामिल होते हैं. withTransform() का इस्तेमाल करना, अलग-अलग ट्रांसफ़ॉर्मेशन के लिए नेस्ट किए गए कॉल करने से ज़्यादा असरदार है. ऐसा इसलिए, क्योंकि सभी ट्रांसफ़ॉर्मेशन एक ही ऑपरेशन में एक साथ किए जाते हैं. इसके बजाय, Compose को नेस्ट किए गए हर ट्रांसफ़ॉर्मेशन का हिसाब लगाने और उसे सेव करने की ज़रूरत नहीं होती.

उदाहरण के लिए, यहां दिया गया कोड, रेक्टैंगल पर ट्रांसलेशन और रोटेशन, दोनों लागू करता है:

Canvas(modifier = Modifier.fillMaxSize()) {
    withTransform({
        translate(left = size.width / 5F)
        rotate(degrees = 45F)
    }) {
        drawRect(
            color = Color.Gray,
            topLeft = Offset(x = size.width / 3F, y = size.height / 3F),
            size = size / 3F
        )
    }
}

एक फ़ोन, जिसकी स्क्रीन पर एक रेक्टैंगल दिख रहा है. यह रेक्टैंगल, स्क्रीन के एक तरफ़ झुका हुआ है
सातवीं इमेज. withTransform का इस्तेमाल करके, रोटेशन और ट्रांसलेशन, दोनों को लागू करें. इससे रेक्टैंगल को घुमाया जा सकता है और उसे बाईं ओर शिफ़्ट किया जा सकता है.

ड्रॉइंग से जुड़ी सामान्य कार्रवाइयां

टेक्स्ट ड्रॉ करना

Compose में टेक्स्ट ड्रॉ करने के लिए, आम तौर पर Text कंपोज़ेबल का इस्तेमाल किया जा सकता है. हालांकि, अगर आप DrawScope में हैं या आपको अपनी पसंद के मुताबिक मैन्युअल तरीके से टेक्स्ट ड्रॉ करना है, तो DrawScope.drawText() तरीके का इस्तेमाल किया जा सकता है.

टेक्स्ट ड्रॉ करने के लिए, rememberTextMeasurer का इस्तेमाल करके TextMeasurer बनाएं और मेज़रर के साथ drawText को कॉल करें:

val textMeasurer = rememberTextMeasurer()

Canvas(modifier = Modifier.fillMaxSize()) {
    drawText(textMeasurer, "Hello")
}

कैनवस पर Hello लिखा हुआ दिख रहा है
आठवीं इमेज. कैनवस पर टेक्स्ट ड्रॉ करना.

टेक्स्ट की लंबाई मापना

टेक्स्ट ड्रॉ करने का तरीका, ड्रॉ करने के अन्य निर्देशों से थोड़ा अलग होता है. आम तौर पर, ड्रॉइंग कमांड को साइज़ (चौड़ाई और ऊंचाई) दिया जाता है, ताकि वह उसी साइज़ में शेप/इमेज बना सके. टेक्स्ट के साथ कुछ पैरामीटर होते हैं, जो रेंडर किए गए टेक्स्ट के साइज़ को कंट्रोल करते हैं. जैसे, फ़ॉन्ट साइज़, फ़ॉन्ट, लिगेचर, और अक्षरों के बीच की स्पेसिंग.

Compose की मदद से, TextMeasurer का इस्तेमाल करके, ऊपर बताए गए फ़ैक्टर के आधार पर टेक्स्ट के मेज़र किए गए साइज़ को ऐक्सेस किया जा सकता है. अगर आपको टेक्स्ट के पीछे बैकग्राउंड बनाना है, तो मेज़र की गई जानकारी का इस्तेमाल करके, टेक्स्ट के लिए इस्तेमाल की गई जगह का साइज़ पता किया जा सकता है:

val textMeasurer = rememberTextMeasurer()

Spacer(
    modifier = Modifier
        .drawWithCache {
            val measuredText =
                textMeasurer.measure(
                    AnnotatedString(longTextSample),
                    constraints = Constraints.fixedWidth((size.width * 2f / 3f).toInt()),
                    style = TextStyle(fontSize = 18.sp)
                )

            onDrawBehind {
                drawRect(pinkColor, size = measuredText.size.toSize())
                drawText(measuredText)
            }
        }
        .fillMaxSize()
)

इस कोड स्निपेट से, टेक्स्ट पर गुलाबी बैकग्राउंड दिखता है:

कई लाइनों वाला टेक्स्ट, जो पूरे एरिया का ⅔ हिस्सा लेता है. इसमें बैकग्राउंड में एक रेक्टैंगल होता है
नौवीं इमेज. कई लाइनों वाला टेक्स्ट, जो पूरे एरिया का ⅔ हिस्सा लेता है. इसमें बैकग्राउंड में एक रेक्टैंगल होता है.

कंस्ट्रेंट, फ़ॉन्ट साइज़ या मेज़र किए गए साइज़ पर असर डालने वाली किसी भी प्रॉपर्टी में बदलाव करने पर, नया साइज़ रिपोर्ट किया जाता है. width और height, दोनों के लिए एक तय साइज़ सेट किया जा सकता है. इसके बाद, टेक्स्ट सेट किए गए TextOverflow के हिसाब से दिखता है. उदाहरण के लिए, यहां दिया गया कोड, कंपोज़ेबल एरिया की ऊंचाई के ⅓ हिस्से और चौड़ाई के ⅓ हिस्से में टेक्स्ट रेंडर करता है. साथ ही, TextOverflow को TextOverflow.Ellipsis पर सेट करता है:

val textMeasurer = rememberTextMeasurer()

Spacer(
    modifier = Modifier
        .drawWithCache {
            val measuredText =
                textMeasurer.measure(
                    AnnotatedString(longTextSample),
                    constraints = Constraints.fixed(
                        width = (size.width / 3f).toInt(),
                        height = (size.height / 3f).toInt()
                    ),
                    overflow = TextOverflow.Ellipsis,
                    style = TextStyle(fontSize = 18.sp)
                )

            onDrawBehind {
                drawRect(pinkColor, size = measuredText.size.toSize())
                drawText(measuredText)
            }
        }
        .fillMaxSize()
)

अब टेक्स्ट को कंस्ट्रेंट में ड्रॉ किया जाता है. इसके आखिर में एलिप्सिस होता है:

गुलाबी बैकग्राउंड पर टेक्स्ट दिखाया गया है. इसमें टेक्स्ट को एलिप्सिस से काटा गया है.
10वीं इमेज. TextOverflow.Ellipsis, जिसमें टेक्स्ट को मेज़र करने के लिए तय की गई पाबंदियां शामिल हैं.

इमेज ड्रॉ करें

DrawScope की मदद से ImageBitmap बनाने के लिए, ImageBitmap.imageResource() का इस्तेमाल करके इमेज लोड करें. इसके बाद, drawImage को कॉल करें:

val dogImage = ImageBitmap.imageResource(id = R.drawable.dog)

Canvas(modifier = Modifier.fillMaxSize(), onDraw = {
    drawImage(dogImage)
})

कैनवस पर बनाई गई कुत्ते की इमेज
11वीं इमेज. कैनवस पर ImageBitmap की ड्रॉइंग बनाई जा रही है.

बुनियादी आकार बनाना

DrawScope पर, शेप ड्रॉ करने के लिए कई फ़ंक्शन उपलब्ध हैं. कोई आकार बनाने के लिए, पहले से तय किए गए ड्रॉ फ़ंक्शन में से किसी एक का इस्तेमाल करें. जैसे, drawCircle:

val purpleColor = Color(0xFFBA68C8)
Canvas(
    modifier = Modifier
        .fillMaxSize()
        .padding(16.dp),
    onDraw = {
        drawCircle(purpleColor)
    }
)

एपीआई

आउटपुट

drawCircle()

सर्कल बनाएं

drawRect()

रेक्टैंगल बनाएं

drawRoundedRect()

गोलाकार कोनों वाला आयत बनाएं

drawLine()

लाइन ड्रॉ करें

drawOval()

अंडाकार आकृति बनाओ

drawArc()

आर्क ड्रॉ करें

drawPoints()

ड्रॉ पॉइंट

पाथ ड्रॉ करना

पाथ, गणित के निर्देशों की एक सीरीज़ होती है. इसे लागू करने पर, एक ड्रॉइंग बनती है. DrawScope, DrawScope.drawPath() तरीके का इस्तेमाल करके पाथ बना सकता है.

उदाहरण के लिए, मान लें कि आपको एक त्रिभुज बनाना है. ड्रॉइंग एरिया के साइज़ का इस्तेमाल करके, lineTo() और moveTo() जैसे फ़ंक्शन की मदद से पाथ जनरेट किया जा सकता है. इसके बाद, इस नए पाथ के साथ drawPath() को कॉल करें, ताकि आपको एक त्रिकोण मिल सके.

Spacer(
    modifier = Modifier
        .drawWithCache {
            val path = Path()
            path.moveTo(0f, 0f)
            path.lineTo(size.width / 2f, size.height / 2f)
            path.lineTo(size.width, 0f)
            path.close()
            onDrawBehind {
                drawPath(path, Color.Magenta, style = Stroke(width = 10f))
            }
        }
        .fillMaxSize()
)

Compose पर बैंगनी रंग का एक उल्टा त्रिकोण बनाया गया है
इमेज 12. ईमेल लिखने की सुविधा में, Path को बनाने और ड्रॉ करने की सुविधा.

Canvas ऑब्जेक्ट को ऐक्सेस किया जा रहा है

DrawScope में, आपके पास Canvas ऑब्जेक्ट का सीधा ऐक्सेस नहीं होता. DrawScope.drawIntoCanvas() का इस्तेमाल करके, Canvas ऑब्जेक्ट को ऐक्सेस किया जा सकता है. इस ऑब्जेक्ट पर फ़ंक्शन को कॉल किया जा सकता है.

उदाहरण के लिए, अगर आपके पास कोई कस्टम Drawable है जिसे आपको कैनवस पर ड्रॉ करना है, तो कैनवस को ऐक्सेस करें और Drawable#draw() को कॉल करें. इसके बाद, Canvas ऑब्जेक्ट को पास करें:

val drawable = ShapeDrawable(OvalShape())
Spacer(
    modifier = Modifier
        .drawWithContent {
            drawIntoCanvas { canvas ->
                drawable.setBounds(0, 0, size.width.toInt(), size.height.toInt())
                drawable.draw(canvas.nativeCanvas)
            }
        }
        .fillMaxSize()
)

एक अंडाकार काले रंग का ShapeDrawable, जो पूरी स्क्रीन पर दिख रहा है
इमेज 13. Drawable ड्रॉ करने के लिए, कैनवस को ऐक्सेस किया जा रहा है.

ज़्यादा जानें

Compose में ड्रॉइंग बनाने के बारे में ज़्यादा जानने के लिए, ये संसाधन देखें: