কম্পোজে আকার

কম্পোজের সাহায্যে আপনি বহুভুজ থেকে তৈরি আকার তৈরি করতে পারেন। উদাহরণস্বরূপ, আপনি নিম্নলিখিত ধরণের আকার তৈরি করতে পারেন:

অঙ্কন এলাকার কেন্দ্রে নীল ষড়ভুজ
চিত্র ১. গ্রাফিক্স-শেপস লাইব্রেরি দিয়ে আপনি যে বিভিন্ন আকার তৈরি করতে পারেন তার উদাহরণ

Compose-এ একটি কাস্টম গোলাকার বহুভুজ তৈরি করতে, আপনার app/build.gradlegraphics-shapes নির্ভরতা যোগ করুন:

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 । প্রতিটি বৃত্তাকার কোণ 1-3 ঘন বক্ররেখা দিয়ে তৈরি, যার কেন্দ্রে একটি বৃত্তাকার চাপ আকৃতি থাকে যখন দুটি পাশ ("পার্শ্ব") বক্ররেখা আকৃতির প্রান্ত থেকে কেন্দ্র বক্ররেখায় স্থানান্তরিত হয়।

ব্যাসার্ধ

radius হলো বৃত্তের ব্যাসার্ধ যা একটি শীর্ষবিন্দুকে বৃত্তাকারে ব্যবহার করা হয়।

উদাহরণস্বরূপ, নিম্নলিখিত বৃত্তাকার কোণার ত্রিভুজটি নিম্নরূপ তৈরি করা হয়েছে:

গোলাকার কোণ সহ ত্রিভুজ
চিত্র ৩। গোলাকার কোণ বিশিষ্ট ত্রিভুজ।
বৃত্তাকার ব্যাসার্ধ r বৃত্তাকার কোণগুলির বৃত্তাকার বৃত্তাকার আকার নির্ধারণ করে
চিত্র ৪. বৃত্তাকার ব্যাসার্ধ 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)
)

দুটি কালো ত্রিভুজ যা মসৃণকরণের প্যারামিটারের পার্থক্য দেখাচ্ছে।
চিত্র ৭। দুটি কালো ত্রিভুজ যা মসৃণকরণ প্যারামিটারের পার্থক্য দেখাচ্ছে।

আকার এবং অবস্থান

ডিফল্টরূপে, কেন্দ্রের চারপাশে 1 ব্যাসার্ধের একটি আকৃতি তৈরি করা হয় ( 0, 0 )। এই ব্যাসার্ধটি বহুভুজের কেন্দ্র এবং বহির্মুখী শীর্ষবিন্দুর মধ্যবর্তী দূরত্বকে প্রতিনিধিত্ব করে যার উপর আকৃতিটি ভিত্তি করে তৈরি করা হয়েছে। মনে রাখবেন যে কোণগুলিকে বৃত্তাকার করার ফলে একটি ছোট আকার তৈরি হয় কারণ বৃত্তাকার কোণগুলি বৃত্তাকার শীর্ষবিন্দুগুলির তুলনায় কেন্দ্রের কাছাকাছি থাকবে। একটি বহুভুজকে আকার দিতে, radius মান সামঞ্জস্য করুন। অবস্থান সামঞ্জস্য করতে, বহুভুজের centerX বা centerY পরিবর্তন করুন। বিকল্পভাবে, DrawScope#translate() এর মতো স্ট্যান্ডার্ড DrawScope রূপান্তর ফাংশন ব্যবহার করে বস্তুর আকার, অবস্থান এবং ঘূর্ণন পরিবর্তন করতে রূপান্তর করুন।

রূপ আকৃতি

একটি Morph অবজেক্ট হল একটি নতুন আকৃতি যা দুটি বহুভুজ আকৃতির মধ্যে একটি অ্যানিমেশন উপস্থাপন করে। দুটি আকৃতির মধ্যে morph করার জন্য, দুটি RoundedPolygons এবং একটি Morph অবজেক্ট তৈরি করুন যা এই দুটি আকৃতি গ্রহণ করে। শুরু এবং শেষ আকৃতির মধ্যে একটি আকৃতি গণনা করতে, শুরু (0) এবং শেষ (1) আকৃতির মধ্যে এর রূপ নির্ধারণ করার জন্য শূন্য এবং একের মধ্যে একটি progress মান প্রদান করুন:

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()
)

উপরের উদাহরণে, অগ্রগতি দুটি আকারের (বৃত্তাকার ত্রিভুজ এবং একটি বর্গক্ষেত্র) ঠিক মাঝামাঝি, যা নিম্নলিখিত ফলাফল তৈরি করে:

একটি বৃত্তাকার ত্রিভুজ এবং একটি বর্গক্ষেত্রের মধ্যে ৫০% পথ
চিত্র ৮. একটি বৃত্তাকার ত্রিভুজ এবং একটি বর্গক্ষেত্রের মধ্যে ৫০% পথ।

বেশিরভাগ পরিস্থিতিতে, মর্ফিং একটি অ্যানিমেশনের অংশ হিসেবে করা হয়, শুধুমাত্র একটি স্ট্যাটিক রেন্ডারিং নয়। এই দুটির মধ্যে অ্যানিমেট করার জন্য, আপনি সময়ের সাথে সাথে অগ্রগতির মান পরিবর্তন করতে কম্পোজে স্ট্যান্ডার্ড অ্যানিমেশন API ব্যবহার করতে পারেন। উদাহরণস্বরূপ, আপনি এই দুটি আকারের মধ্যে মর্ফকে অসীমভাবে অ্যানিমেট করতে পারেন নিম্নরূপ:

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()
)

একটি বর্গক্ষেত্র এবং একটি বৃত্তাকার ত্রিভুজের মধ্যে অসীমভাবে রূপান্তরিত হচ্ছে
চিত্র ৯। একটি বর্গক্ষেত্র এবং একটি বৃত্তাকার ত্রিভুজের মধ্যে অসীমভাবে রূপান্তরিত হচ্ছে।

ক্লিপ হিসেবে বহুভুজ ব্যবহার করুন

কম্পোজেবল কীভাবে রেন্ডার করা হয় তা পরিবর্তন করতে এবং ক্লিপিং এরিয়ার চারপাশে আঁকা ছায়ার সুবিধা নিতে কম্পোজে 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` লেখা সহ ষড়ভুজ।
চিত্র ১০। কেন্দ্রে "হ্যালো কম্পোজ" লেখা সহ ষড়ভুজ।

এটি আগের রেন্ডারিং থেকে খুব একটা আলাদা নাও দেখাতে পারে, তবে এটি কম্পোজের অন্যান্য বৈশিষ্ট্যগুলিকে কাজে লাগানোর সুযোগ করে দেয়। উদাহরণস্বরূপ, এই কৌশলটি একটি ছবি ক্লিপ করতে এবং ক্লিপ করা অঞ্চলের চারপাশে একটি ছায়া প্রয়োগ করতে ব্যবহার করা যেতে পারে:

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)
    }
}

এই morph আকৃতি ব্যবহার করতে, দুটি বহুভুজ তৈরি করুন, shapeA এবং shapeBMorph তৈরি করুন এবং মনে রাখুন। তারপর, বোতামে morphটি একটি ক্লিপ আউটলাইন হিসেবে প্রয়োগ করুন, অ্যানিমেশনের পিছনে চালিকা শক্তি হিসেবে press-এ 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))
}

বাক্সটি ট্যাপ করলে নিম্নলিখিত অ্যানিমেশনটি দেখাবে:

দুটি আকৃতির মধ্যে ক্লিক হিসেবে মর্ফ প্রয়োগ করা হয়েছে
চিত্র ১২। দুটি আকৃতির মধ্যে ক্লিক হিসেবে মর্ফ প্রয়োগ করা হয়েছে।

আকৃতি অসীমভাবে রূপান্তরিত হচ্ছে অ্যানিমেট

একটি morph আকৃতিকে অবিরামভাবে অ্যানিমেট করতে, 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) স্থানাঙ্ক ব্যবস্থা ব্যবহারের তুলনায় এটিকে সহজ করে তোলে, যেখানে ডান দিকে শুরু হয় এবং ঘড়ির কাঁটার দিকে এগিয়ে যায়, 12 টার অবস্থানে 270° থাকে:

হৃদয় আকৃতি
চিত্র ১৫। স্থানাঙ্ক সহ হৃদয়ের আকৃতি।

প্রতিটি বিন্দুতে কেন্দ্র থেকে কোণ (𝜭) এবং ব্যাসার্ধ নির্দিষ্ট করে আকৃতিটি এখন আরও সহজে সংজ্ঞায়িত করা যেতে পারে:

হৃদয় আকৃতি
চিত্র ১৬। স্থানাঙ্ক সহ হৃদয় আকৃতি, বৃত্তাকার ছাড়াই।

শীর্ষবিন্দুগুলি এখন তৈরি করা যেতে পারে এবং 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 লাইব্রেরিটি ইচ্ছামত আকারের জন্য ব্যবহারের উদ্দেশ্যে নয়, তবে বিশেষভাবে গোলাকার বহুভুজ তৈরি এবং তাদের মধ্যে মর্ফ অ্যানিমেশন তৈরি সহজ করার জন্য তৈরি করা হয়েছে।

অতিরিক্ত সম্পদ

আরও তথ্য এবং উদাহরণের জন্য, নিম্নলিখিত সম্পদগুলি দেখুন: