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

Compose में, गोल आकार वाला अपनी पसंद के मुताबिक पॉलीगॉन बनाने के लिए,
graphics-shapes
आपकी इस बात पर निर्भर है
app/build.gradle
:
implementation "androidx.graphics:graphics-shapes:1.0.1"
इस लाइब्रेरी में, पॉलीगॉन से बनाए गए आकार बनाए जा सकते हैं. पॉलीगॉन आकार में सिर्फ़ सीधे किनारे और नुकीले कोने होते हैं. हालांकि, इन आकारों में गोल कोने भी हो सकते हैं. यह दो अलग-अलग चीज़ों के बीच मॉर्फ़ करना आसान बनाता है आकार. अलग-अलग आकार के बीच मॉर्फ़ करना मुश्किल होता है. यह डिज़ाइन के समय की समस्या होती है. हालांकि, इस लाइब्रेरी में दी गई चीज़ों को आपस में जोड़कर, इसे आसान बनाया जा सकता है एक जैसे पॉलीगॉन स्ट्रक्चर वाली आकृतियां.
पॉलीगॉन बनाना
नीचे दिया गया स्निपेट एक सामान्य पॉलीगॉन आकार बनाता है, जिसके बीच में 6 पॉइंट होते हैं का साइज़:
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 बनाम 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() )
ऊपर दिए गए उदाहरण में, प्रोग्रेस दो शेप के बीच की आधी दूरी पर है (गोलाकार त्रिभुज और एक वर्ग), जिससे ऐसा नतीजा मिलता है:

ज़्यादातर मामलों में, मॉर्फ़िंग को ऐनिमेशन के हिस्से के तौर पर किया जाता है, न कि सिर्फ़ स्टैटिक रेंडरिंग के तौर पर. इन दोनों वैल्यू के बीच ऐनिमेशन जोड़ने के लिए, 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) ) }
इसका नतीजा ये होता है:

ऐसा हो सकता है कि यह पहले रेंडर किए गए कॉन्टेंट से अलग न दिखे, लेकिन इससे 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) ) }

क्लिक करने पर मॉर्फ बटन
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)) }
बॉक्स पर टैप करने पर, यह ऐनिमेशन दिखेगा:

आकार को असीम रूप से मॉर्फ़ करने वाले ऐनिमेशन को ऐनिमेट करें
मॉर्फ़ आकार को लगातार ऐनिमेट करने के लिए, इसका इस्तेमाल करें
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) ) } }
इस कोड से यह मज़ेदार नतीजा मिलता है:

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

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

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

अब वर्टिसेस बनाए जा सकते हैं और उन्हें 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) )
इससे गुलाबी दिल दिखता है:

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