Compose में शेप

Compose की मदद से, पॉलीगॉन से बने आकार बनाए जा सकते हैं. उदाहरण के लिए, इन तरह के आकार बनाए जा सकते हैं:

ड्रॉइंग एरिया के बीच में नीला हेक्सागॉन
पहली इमेज. ग्राफ़िक-आकार वाली लाइब्रेरी
की मदद से बनाए जा सकने वाले अलग-अलग आकारों के उदाहरण

Compose में कस्टम राउंड पॉलीगॉन बनाने के लिए, अपने app/build.gradle में graphics-shapes डिपेंडेंसी जोड़ें:

implementation "androidx.graphics:graphics-shapes:1.0.0-rc01"

इस लाइब्रेरी की मदद से, पॉलीगॉन से बने आकार बनाए जा सकते हैं. पॉलीगॉन आकार में सिर्फ़ सीधे किनारे और नुकीले कोने होते हैं. हालांकि, इन आकारों में गोल कोने भी हो सकते हैं. इससे, दो अलग-अलग आकारों के बीच आसानी से मॉर्फ़ किया जा सकता है. अलग-अलग आकार के बीच मॉर्फ़ करना मुश्किल होता है. यह डिज़ाइन के समय की समस्या होती है. हालांकि, यह लाइब्रेरी इन आकारों को एक जैसे पॉलीगॉन स्ट्रक्चर में बदलकर, इसे आसान बनाती है.

पॉलीगॉन बनाना

नीचे दिया गया स्निपेट, ड्रॉइंग एरिया के बीच में छह पॉइंट वाला बुनियादी पॉलीगॉन बनाता है:

Box(
    modifier = Modifier
        .drawWithCache {
            val roundedPolygon = RoundedPolygon(
                numVertices = 6,
                radius = size.minDimension / 2,
                centerX = size.width / 2,
                centerY = size.height / 2
            )
            val roundedPolygonPath = roundedPolygon.toPath().asComposePath()
            onDrawBehind {
                drawPath(roundedPolygonPath, color = Color.Blue)
            }
        }
        .fillMaxSize()
)

ड्रॉइंग एरिया के बीच में नीला हेक्सागॉन
दूसरी इमेज. ड्रॉइंग एरिया के बीच में नीला हेक्सागॉन.

इस उदाहरण में, लाइब्रेरी एक RoundedPolygon बनाती है, जिसमें अनुरोध किए गए आकार को दिखाने वाली ज्यामिति होती है. Compose ऐप्लिकेशन में उस आकार को खींचने के लिए, आपको उससे Path ऑब्जेक्ट पाना होगा, ताकि आकार को उस फ़ॉर्म में लाया जा सके जिसे Compose ऐप्लिकेशन खींच सकता है.

पॉलीगॉन के कोनों को गोल करना

पॉलीगॉन के कोनों को गोल करने के लिए, CornerRounding पैरामीटर का इस्तेमाल करें. इसमें दो पैरामीटर, radius और smoothing होते हैं. हर गोल कोने में एक से तीन घन वक्र होते हैं. इनमें से बीच का वक्र गोलाकार आर्क होता है, जबकि दोनों तरफ़ के वक्र ("फ़्लैंकिंग") आकृति के किनारे से बीच के वक्र तक ट्रांज़िशन करते हैं.

दायरा

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

उदाहरण के लिए, यहां दिए गए राउंड किए गए कोने वाले त्रिकोण को इस तरह बनाया गया है:

गोल कोनों वाला त्रिभुज
तीसरी इमेज. गोल कोनों वाला त्रिभुज.
'राउंडिंग त्रिज्या' पैरामीटर से, राउंड किए गए कोनों के सर्कुलर राउंडिंग साइज़ का पता चलता है
चौथी इमेज. राउंडिंग त्रिज्या r से, राउंड किए गए कोनों के सर्कुलर राउंडिंग साइज़ का पता चलता है.

कोमल करना

स्मूद करने की सुविधा से यह तय होता है कि कोने के गोल आकार वाले हिस्से से किनारे तक पहुंचने में कितना समय लगेगा. 0 के स्मूद करने वाले फ़ैक्टर (बिना स्मूद किए, CornerRounding के लिए डिफ़ॉल्ट वैल्यू) से, पूरी तरह से गोलाकार कोने राउंड होते हैं. ज़ीरो से ज़्यादा (ज़्यादा से ज़्यादा 1.0) की वैल्यू वाले स्मूद करने वाले फ़ैक्टर की वजह से, कोने को तीन अलग-अलग कर्व से राउंड किया जाता है.

'नर्म करने वाला फ़ैक्टर' 0 (नर्म नहीं किया गया) होने पर, एक क्यूबिक कर्व बनता है. यह कर्व, पहले दिए गए उदाहरण की तरह, कोने के चारों ओर सर्कल के हिसाब से होता है.
पांचवीं इमेज. स्मूद करने की सुविधा के लिए 0 (बिना स्मूद किया गया) का इस्तेमाल करने पर, एक क्यूबिक कर्व बनता है. यह कर्व, पहले दिए गए उदाहरण की तरह, कोने के आस-पास सर्कल के हिसाब से राउंडिंग त्रिज्या के साथ चलता है.
शून्य से ज़्यादा की वैल्यू वाला स्मूद करने वाला फ़ैक्टर, वर्टिक्स को गोल करने के लिए तीन घन वक्र बनाता है: पहले की तरह ही अंदरूनी सर्कुलर कर्व के साथ-साथ दो फ़्लैंकिंग कर्व, जो अंदरूनी कर्व और पॉलीगॉन के किनारों के बीच ट्रांज़िशन करते हैं.
छठी इमेज. शून्य से ज़्यादा की वैल्यू वाला स्मूद करने वाला फ़ैक्टर, वर्टिक्स को गोल करने के लिए तीन घन कर्व बनाता है: पहले की तरह ही अंदरूनी सर्कुलर कर्व के साथ-साथ दो फ़्लैंकिंग कर्व, जो अंदरूनी कर्व और पॉलीगॉन के किनारों के बीच ट्रांज़िशन करते हैं.

उदाहरण के लिए, नीचे दिए गए स्निपेट में, स्मूद करने की सेटिंग को 0 बनाम 1 पर सेट करने में होने वाले छोटे अंतर को दिखाया गया है:

Box(
    modifier = Modifier
        .drawWithCache {
            val roundedPolygon = RoundedPolygon(
                numVertices = 3,
                radius = size.minDimension / 2,
                centerX = size.width / 2,
                centerY = size.height / 2,
                rounding = CornerRounding(
                    size.minDimension / 10f,
                    smoothing = 0.1f
                )
            )
            val roundedPolygonPath = roundedPolygon.toPath().asComposePath()
            onDrawBehind {
                drawPath(roundedPolygonPath, color = Color.Black)
            }
        }
        .size(100.dp)
)

दो काले त्रिकोण, स्मूद करने वाले पैरामीटर में अंतर दिखा रहे हैं.
सातवीं इमेज. दो काले त्रिकोण, जो स्मूद करने वाले पैरामीटर में अंतर दिखा रहे हैं.

साइज़ और पोज़िशन

डिफ़ॉल्ट रूप से, आकार को केंद्र (0, 0) के आस-पास 1 के रेडियस के साथ बनाया जाता है. यह रेडियस, उस पॉलीगॉन के केंद्र और बाहरी वर्टिसेस के बीच की दूरी दिखाता है जिस पर आकार आधारित होता है. ध्यान दें कि कोनों को गोल करने पर आकार छोटा हो जाता है, क्योंकि गोल किए गए कोने, वर्टिसेस के मुकाबले केंद्र के ज़्यादा करीब होंगे. पॉलीगॉन का साइज़ बदलने के लिए, radius की वैल्यू में बदलाव करें. पोज़िशन में बदलाव करने के लिए, पॉलीगॉन के centerX या centerY को बदलें. इसके अलावा, ऑब्जेक्ट का साइज़, पोज़िशन, और रोटेशन बदलने के लिए, DrawScope ट्रांसफ़ॉर्मेशन फ़ंक्शन का इस्तेमाल करें. जैसे, DrawScope#translate().

आकृतियों को मॉर्फ़ करना

Morph ऑब्जेक्ट एक नया आकार है, जो दो पॉलीगॉन आकारों के बीच ऐनिमेशन दिखाता है. दो आकारों के बीच मॉर्फ़ करने के लिए, दो RoundedPolygons और एक Morph ऑब्जेक्ट बनाएं, जो इन दोनों आकारों में बदल जाए. शुरुआत और आखिर में मौजूद आकारों के बीच के आकार का हिसाब लगाने के लिए, progress वैल्यू को शून्य और एक के बीच रखें. इससे, शुरुआत (0) और आखिर (1) में मौजूद आकार के बीच के आकार का पता चलता है:

Box(
    modifier = Modifier
        .drawWithCache {
            val triangle = RoundedPolygon(
                numVertices = 3,
                radius = size.minDimension / 2f,
                centerX = size.width / 2f,
                centerY = size.height / 2f,
                rounding = CornerRounding(
                    size.minDimension / 10f,
                    smoothing = 0.1f
                )
            )
            val square = RoundedPolygon(
                numVertices = 4,
                radius = size.minDimension / 2f,
                centerX = size.width / 2f,
                centerY = size.height / 2f
            )

            val morph = Morph(start = triangle, end = square)
            val morphPath = morph
                .toPath(progress = 0.5f).asComposePath()

            onDrawBehind {
                drawPath(morphPath, color = Color.Black)
            }
        }
        .fillMaxSize()
)

ऊपर दिए गए उदाहरण में, प्रोग्रेस दो आकारों (राउंड किए गए त्रिकोण और वर्ग) के बीच ठीक आधी है. इससे यह नतीजा मिलता है:

गोल आकार वाले त्रिकोण और स्क्वेयर के बीच 50% का फ़र्क़
आठवीं इमेज. यह गोल आकार वाले त्रिकोण और स्क्वेयर के बीच 50% का फ़र्क़ होता है.

ज़्यादातर मामलों में, मॉर्फ़िंग को ऐनिमेशन के हिस्से के तौर पर किया जाता है, न कि सिर्फ़ स्टैटिक रेंडरिंग के तौर पर. इन दोनों वैल्यू के बीच ऐनिमेशन जोड़ने के लिए, Compose में स्टैंडर्ड ऐनिमेशन एपीआई का इस्तेमाल किया जा सकता है. इससे, समय के साथ प्रोग्रेस वैल्यू बदली जा सकती है. उदाहरण के लिए, इन दोनों आकारों के बीच, अनलिमिटेड ऐनिमेशन के तौर पर मॉर्फ़ किया जा सकता है. इसके लिए, यह तरीका अपनाएं:

val infiniteAnimation = rememberInfiniteTransition(label = "infinite animation")
val morphProgress = infiniteAnimation.animateFloat(
    initialValue = 0f,
    targetValue = 1f,
    animationSpec = infiniteRepeatable(
        tween(500),
        repeatMode = RepeatMode.Reverse
    ),
    label = "morph"
)
Box(
    modifier = Modifier
        .drawWithCache {
            val triangle = RoundedPolygon(
                numVertices = 3,
                radius = size.minDimension / 2f,
                centerX = size.width / 2f,
                centerY = size.height / 2f,
                rounding = CornerRounding(
                    size.minDimension / 10f,
                    smoothing = 0.1f
                )
            )
            val square = RoundedPolygon(
                numVertices = 4,
                radius = size.minDimension / 2f,
                centerX = size.width / 2f,
                centerY = size.height / 2f
            )

            val morph = Morph(start = triangle, end = square)
            val morphPath = morph
                .toPath(progress = morphProgress.value)
                .asComposePath()

            onDrawBehind {
                drawPath(morphPath, color = Color.Black)
            }
        }
        .fillMaxSize()
)

स्क्वेयर और गोल आकार वाले ट्राएंगल के बीच लगातार बदलाव करना
नौवीं इमेज. स्क्वेयर और राउंड ट्राएंगल के बीच लगातार बदलाव होता रहे.

पॉलीगॉन को क्लिप के तौर पर इस्तेमाल करना

Compose में, clip मॉडिफ़ायर का इस्तेमाल आम तौर पर किया जाता है. इससे, किसी कॉम्पोज़ेबल को रेंडर करने के तरीके में बदलाव किया जा सकता है. साथ ही, क्लिपिंग एरिया के आस-पास बनने वाली परछाई का फ़ायदा भी लिया जा सकता है:

fun RoundedPolygon.getBounds() = calculateBounds().let { Rect(it[0], it[1], it[2], it[3]) }
class RoundedPolygonShape(
    private val polygon: RoundedPolygon,
    private var matrix: Matrix = Matrix()
) : Shape {
    private var path = Path()
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        path.rewind()
        path = polygon.toPath().asComposePath()
        matrix.reset()
        val bounds = polygon.getBounds()
        val maxDimension = max(bounds.width, bounds.height)
        matrix.scale(size.width / maxDimension, size.height / maxDimension)
        matrix.translate(-bounds.left, -bounds.top)

        path.transform(matrix)
        return Outline.Generic(path)
    }
}

इसके बाद, पॉलीगॉन को क्लिप के तौर पर इस्तेमाल किया जा सकता है, जैसा कि इस स्निपेट में दिखाया गया है:

val hexagon = remember {
    RoundedPolygon(
        6,
        rounding = CornerRounding(0.2f)
    )
}
val clip = remember(hexagon) {
    RoundedPolygonShape(polygon = hexagon)
}
Box(
    modifier = Modifier
        .clip(clip)
        .background(MaterialTheme.colorScheme.secondary)
        .size(200.dp)
) {
    Text(
        "Hello Compose",
        color = MaterialTheme.colorScheme.onSecondary,
        modifier = Modifier.align(Alignment.Center)
    )
}

इस वजह से, ये समस्याएं हो सकती हैं:

हेक्सागॉन, जिसमें बीच में `hello compose` टेक्स्ट है.
10वीं इमेज. हेक्सागॉन, जिसमें बीच में "Hello Compose" टेक्स्ट है.

ऐसा हो सकता है कि यह पहले रेंडर किए गए कॉन्टेंट से अलग न दिखे, लेकिन इससे Compose में मौजूद अन्य सुविधाओं का फ़ायदा लिया जा सकता है. उदाहरण के लिए, इस तकनीक का इस्तेमाल करके, किसी इमेज को क्लिप किया जा सकता है और क्लिप किए गए हिस्से के आस-पास शैडो लागू किया जा सकता है:

val hexagon = remember {
    RoundedPolygon(
        6,
        rounding = CornerRounding(0.2f)
    )
}
val clip = remember(hexagon) {
    RoundedPolygonShape(polygon = hexagon)
}
Box(
    modifier = Modifier.fillMaxSize(),
    contentAlignment = Alignment.Center
) {
    Image(
        painter = painterResource(id = R.drawable.dog),
        contentDescription = "Dog",
        contentScale = ContentScale.Crop,
        modifier = Modifier
            .graphicsLayer {
                this.shadowElevation = 6.dp.toPx()
                this.shape = clip
                this.clip = true
                this.ambientShadowColor = Color.Black
                this.spotShadowColor = Color.Black
            }
            .size(200.dp)

    )
}

हेक्सागॉन में कुत्ता, जिसके किनारों पर शैडो लगाई गई है
11वीं इमेज. पसंद के मुताबिक आकार को क्लिप के तौर पर लागू किया गया.

क्लिक करने पर मॉर्फ बटन

graphics-shape लाइब्रेरी का इस्तेमाल करके, ऐसा बटन बनाया जा सकता है जो दबाने पर दो आकारों में बदल जाए. सबसे पहले, MorphPolygonShape बनाएं, जो Shape को बड़ा करे और उसे सही तरीके से फ़िट करने के लिए, स्केल और ट्रांसलेट करे. प्रोग्रेस के पास होने पर ध्यान दें, ताकि आकार को ऐनिमेट किया जा सके:

class MorphPolygonShape(
    private val morph: Morph,
    private val percentage: Float
) : Shape {

    private val matrix = Matrix()
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        // Below assumes that you haven't changed the default radius of 1f, nor the centerX and centerY of 0f
        // By default this stretches the path to the size of the container, if you don't want stretching, use the same size.width for both x and y.
        matrix.scale(size.width / 2f, size.height / 2f)
        matrix.translate(1f, 1f)

        val path = morph.toPath(progress = percentage).asComposePath()
        path.transform(matrix)
        return Outline.Generic(path)
    }
}

इस मॉर्फ़ आकार का इस्तेमाल करने के लिए, दो पॉलीगॉन बनाएं, shapeA और shapeB. Morph बनाएं और याद रखें. इसके बाद, बटन पर क्लिप आउटलाइन के तौर पर मॉर्फ़ लागू करें. इसके लिए, ऐनिमेशन के पीछे ड्राइविंग फ़ोर्स के तौर पर, interactionSource को दबाने पर इस्तेमाल करें:

val shapeA = remember {
    RoundedPolygon(
        6,
        rounding = CornerRounding(0.2f)
    )
}
val shapeB = remember {
    RoundedPolygon.star(
        6,
        rounding = CornerRounding(0.1f)
    )
}
val morph = remember {
    Morph(shapeA, shapeB)
}
val interactionSource = remember {
    MutableInteractionSource()
}
val isPressed by interactionSource.collectIsPressedAsState()
val animatedProgress = animateFloatAsState(
    targetValue = if (isPressed) 1f else 0f,
    label = "progress",
    animationSpec = spring(dampingRatio = 0.4f, stiffness = Spring.StiffnessMedium)
)
Box(
    modifier = Modifier
        .size(200.dp)
        .padding(8.dp)
        .clip(MorphPolygonShape(morph, animatedProgress.value))
        .background(Color(0xFF80DEEA))
        .size(200.dp)
        .clickable(interactionSource = interactionSource, indication = null) {
        }
) {
    Text("Hello", modifier = Modifier.align(Alignment.Center))
}

बॉक्स पर टैप करने पर, यह ऐनिमेशन दिखता है:

दो आकारों के बीच क्लिक करने पर, मॉर्फ़ लागू होना
12वीं इमेज. दो आकारों के बीच क्लिक के तौर पर लागू किया गया मॉर्फ़.

आकार को अनलिमिटेड तौर पर मॉर्फ़ करने वाला ऐनिमेशन

मॉर्फ़ किए गए आकार को लगातार ऐनिमेट करने के लिए, rememberInfiniteTransition का इस्तेमाल करें. यहां एक ऐसी प्रोफ़ाइल फ़ोटो का उदाहरण दिया गया है जो समय के साथ आकार बदलती है और घूमती रहती है. इस तरीके में, ऊपर दिखाए गए MorphPolygonShape में थोड़ा बदलाव किया जाता है:

class CustomRotatingMorphShape(
    private val morph: Morph,
    private val percentage: Float,
    private val rotation: Float
) : Shape {

    private val matrix = Matrix()
    override fun createOutline(
        size: Size,
        layoutDirection: LayoutDirection,
        density: Density
    ): Outline {
        // Below assumes that you haven't changed the default radius of 1f, nor the centerX and centerY of 0f
        // By default this stretches the path to the size of the container, if you don't want stretching, use the same size.width for both x and y.
        matrix.scale(size.width / 2f, size.height / 2f)
        matrix.translate(1f, 1f)
        matrix.rotateZ(rotation)

        val path = morph.toPath(progress = percentage).asComposePath()
        path.transform(matrix)

        return Outline.Generic(path)
    }
}

@Preview
@Composable
private fun RotatingScallopedProfilePic() {
    val shapeA = remember {
        RoundedPolygon(
            12,
            rounding = CornerRounding(0.2f)
        )
    }
    val shapeB = remember {
        RoundedPolygon.star(
            12,
            rounding = CornerRounding(0.2f)
        )
    }
    val morph = remember {
        Morph(shapeA, shapeB)
    }
    val infiniteTransition = rememberInfiniteTransition("infinite outline movement")
    val animatedProgress = infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 1f,
        animationSpec = infiniteRepeatable(
            tween(2000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        ),
        label = "animatedMorphProgress"
    )
    val animatedRotation = infiniteTransition.animateFloat(
        initialValue = 0f,
        targetValue = 360f,
        animationSpec = infiniteRepeatable(
            tween(6000, easing = LinearEasing),
            repeatMode = RepeatMode.Reverse
        ),
        label = "animatedMorphProgress"
    )
    Box(
        modifier = Modifier.fillMaxSize(),
        contentAlignment = Alignment.Center
    ) {
        Image(
            painter = painterResource(id = R.drawable.dog),
            contentDescription = "Dog",
            contentScale = ContentScale.Crop,
            modifier = Modifier
                .clip(
                    CustomRotatingMorphShape(
                        morph,
                        animatedProgress.value,
                        animatedRotation.value
                    )
                )
                .size(200.dp)
        )
    }
}

इस कोड से यह मज़ेदार नतीजा मिलता है:

दिल के आकर का
13वीं इमेज. प्रोफ़ाइल फ़ोटो, जिसे घूमने वाले स्कैलप आकार से काटा गया हो.

कस्टम पॉलीगॉन

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

दिल के आकर का
चौदहवीं इमेज. दिल का आकार.

RoundedPolygon के उस ओवरलोड का इस्तेमाल करके, इस आकार के अलग-अलग वर्टिसेस तय किए जा सकते हैं जो x, y निर्देशांक का फ़्लोट कलेक्शन लेता है.

दिल के आकार वाले पॉलीगॉन को अलग-अलग हिस्सों में बांटने के लिए, ध्यान दें कि बिंदुओं की जानकारी देने के लिए, कार्टिज़न (x,y) निर्देशांक प्रणाली का इस्तेमाल करने के मुकाबले, पोलर निर्देशांक प्रणाली का इस्तेमाल करना आसान होता है. कार्टिज़न निर्देशांक प्रणाली में, दाईं ओर से शुरू होता है और घड़ी की सुई की दिशा में आगे बढ़ता है. इसमें 270°, 12 बजे की पोज़िशन पर होता है:

दिल के आकर का
15वीं इमेज. निर्देशांकों के साथ दिल का आकार.

अब आकार को आसानी से तय किया जा सकता है. इसके लिए, हर बिंदु पर केंद्र से कोण (𝜭) और त्रिज्या की जानकारी दें:

दिल के आकर का
16वीं इमेज. निर्देशांक के साथ दिल का आकार, बिना राउंड किए.

अब वर्टिसेस बनाए जा सकते हैं और उन्हें RoundedPolygon फ़ंक्शन में पास किया जा सकता है:

val vertices = remember {
    val radius = 1f
    val radiusSides = 0.8f
    val innerRadius = .1f
    floatArrayOf(
        radialToCartesian(radiusSides, 0f.toRadians()).x,
        radialToCartesian(radiusSides, 0f.toRadians()).y,
        radialToCartesian(radius, 90f.toRadians()).x,
        radialToCartesian(radius, 90f.toRadians()).y,
        radialToCartesian(radiusSides, 180f.toRadians()).x,
        radialToCartesian(radiusSides, 180f.toRadians()).y,
        radialToCartesian(radius, 250f.toRadians()).x,
        radialToCartesian(radius, 250f.toRadians()).y,
        radialToCartesian(innerRadius, 270f.toRadians()).x,
        radialToCartesian(innerRadius, 270f.toRadians()).y,
        radialToCartesian(radius, 290f.toRadians()).x,
        radialToCartesian(radius, 290f.toRadians()).y,
    )
}

इस radialToCartesian फ़ंक्शन का इस्तेमाल करके, वर्टिसेस को कार्टेशियन कोऑर्डिनेट में बदलना होगा:

internal fun Float.toRadians() = this * PI.toFloat() / 180f

internal val PointZero = PointF(0f, 0f)
internal fun radialToCartesian(
    radius: Float,
    angleRadians: Float,
    center: PointF = PointZero
) = directionVectorPointF(angleRadians) * radius + center

internal fun directionVectorPointF(angleRadians: Float) =
    PointF(cos(angleRadians), sin(angleRadians))

ऊपर दिए गए कोड से, आपको दिल के लिए रॉ वर्टिसेस मिलते हैं. हालांकि, दिल का चुना गया आकार पाने के लिए, आपको कुछ खास कोनों को गोल करना होगा. 90° और 270° के कोनों को राउंड नहीं किया गया है, लेकिन अन्य कोनों को किया गया है. अलग-अलग कोनों के लिए कस्टम राउंडिंग पाने के लिए, perVertexRounding पैरामीटर का इस्तेमाल करें:

val rounding = remember {
    val roundingNormal = 0.6f
    val roundingNone = 0f
    listOf(
        CornerRounding(roundingNormal),
        CornerRounding(roundingNone),
        CornerRounding(roundingNormal),
        CornerRounding(roundingNormal),
        CornerRounding(roundingNone),
        CornerRounding(roundingNormal),
    )
}

val polygon = remember(vertices, rounding) {
    RoundedPolygon(
        vertices = vertices,
        perVertexRounding = rounding
    )
}
Box(
    modifier = Modifier
        .drawWithCache {
            val roundedPolygonPath = polygon.toPath().asComposePath()
            onDrawBehind {
                scale(size.width * 0.5f, size.width * 0.5f) {
                    translate(size.width * 0.5f, size.height * 0.5f) {
                        drawPath(roundedPolygonPath, color = Color(0xFFF15087))
                    }
                }
            }
        }
        .size(400.dp)
)

इससे गुलाबी दिल दिखता है:

दिल के आकर का
17वीं इमेज. दिल के आकार का नतीजा.

अगर ऊपर दी गई आकृतियां आपके काम की नहीं हैं, तो Path क्लास का इस्तेमाल करके कस्टम आकार बनाएं या डिस्क से ImageVector फ़ाइल लोड करें. graphics-shapes लाइब्रेरी का इस्तेमाल, मनमुताबिक आकार बनाने के लिए नहीं किया जाता. इसका मकसद, गोल पॉलीगॉन बनाने और उनके बीच मॉर्फ़ ऐनिमेशन बनाने की प्रोसेस को आसान बनाना है.

अन्य संसाधन

ज़्यादा जानकारी और उदाहरणों के लिए, ये संसाधन देखें: