রচনায় গ্রাফিক্স

অনেক অ্যাপের ক্ষেত্রেই স্ক্রিনে ঠিক কী আঁকা হবে তা নিখুঁতভাবে নিয়ন্ত্রণ করার প্রয়োজন হয়। এটি স্ক্রিনের সঠিক জায়গায় একটি বাক্স বা বৃত্ত বসানোর মতো ছোট একটি বিষয় হতে পারে, অথবা বিভিন্ন শৈলীর গ্রাফিক উপাদানগুলোর একটি জটিল বিন্যাসও হতে পারে।

মডিফায়ার এবং DrawScope ব্যবহার করে মৌলিক অঙ্কন

Compose-এ নিজের মতো করে কিছু আঁকার মূল উপায় হলো মডিফায়ার ব্যবহার করা, যেমন Modifier.drawWithContent , Modifier.drawBehind , এবং Modifier.drawWithCache

উদাহরণস্বরূপ, আপনার কম্পোজেবলের পিছনে কিছু আঁকতে, আপনি ড্রয়িং কমান্ডগুলি কার্যকর করা শুরু করতে drawBehind মডিফায়ারটি ব্যবহার করতে পারেন:

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

আপনার যদি শুধু আঁকার মতো একটি কম্পোজেবল এলিমেন্টের প্রয়োজন হয়, তবে আপনি Canvas কম্পোজেবলটি ব্যবহার করতে পারেন। Canvas কম্পোজেবলটি হলো Modifier.drawBehind এর একটি সুবিধাজনক র‍্যাপার। আপনি অন্য যেকোনো কম্পোজ UI এলিমেন্টের মতোই আপনার লেআউটে Canvas স্থাপন করতে পারেন। Canvas ভেতরে, আপনি এলিমেন্টগুলোর স্টাইল এবং অবস্থানের উপর সুনির্দিষ্ট নিয়ন্ত্রণ রেখে সেগুলো আঁকতে পারেন।

সমস্ত ড্রয়িং মডিফায়ার একটি DrawScope প্রকাশ করে, যা একটি স্কোপড ড্রয়িং এনভায়রনমেন্ট এবং এটি তার নিজস্ব স্টেট বজায় রাখে। এর মাধ্যমে আপনি একদল গ্রাফিক্যাল এলিমেন্টের প্যারামিটার সেট করতে পারেন। DrawScope বেশ কিছু দরকারি ফিল্ড থাকে, যেমন size , যা একটি Size অবজেক্ট এবং এটি DrawScope এর বর্তমান ডাইমেনশন বা মাত্রা নির্দিষ্ট করে।

কোনো কিছু আঁকতে, আপনি DrawScope এর অনেকগুলো ড্র ফাংশনের মধ্যে যেকোনো একটি ব্যবহার করতে পারেন। উদাহরণস্বরূপ, নিচের কোডটি স্ক্রিনের উপরের বাম কোণে একটি আয়তক্ষেত্র আঁকে:

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

সাদা পটভূমিতে আঁকা একটি গোলাপী আয়তক্ষেত্র যা স্ক্রিনের এক-চতুর্থাংশ জায়গা জুড়ে রয়েছে।
চিত্র ১। কম্পোজ-এর ক্যানভাস ব্যবহার করে আঁকা আয়তক্ষেত্র।

বিভিন্ন ড্রয়িং মডিফায়ার সম্পর্কে আরও জানতে, গ্রাফিক্স মডিফায়ার ডকুমেন্টেশন দেখুন।

স্থানাঙ্ক ব্যবস্থা

স্ক্রিনে কিছু আঁকতে হলে, আপনার আইটেমটির অফসেট ( 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 ১০ গুণ এবং scaleY ১৫ গুণ বৃদ্ধি করে:

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

অসমভাবে স্কেল করা একটি বৃত্ত
চিত্র ৩। ক্যানভাসে একটি বৃত্তের উপর স্কেল অপারেশন প্রয়োগ করা।

অনুবাদ করুন

আপনার ড্রয়িং অপারেশনকে উপরে, নিচে, বামে বা ডানে সরাতে DrawScope.translate() ব্যবহার করুন। উদাহরণস্বরূপ, নিচের কোডটি ড্রয়িংটিকে ১০০ পিক্সেল ডানে এবং ৩০০ পিক্সেল উপরে সরায়:

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

একটি বৃত্ত যা কেন্দ্র থেকে সরে গেছে
চিত্র ৪। ক্যানভাসে একটি বৃত্তের উপর স্থানান্তর অপারেশন প্রয়োগ করা।

ঘোরান

একটি পিভট পয়েন্টকে কেন্দ্র করে আপনার অঙ্কন কার্যক্রম ঘোরানোর জন্য DrawScope.rotate() ব্যবহার করুন। উদাহরণস্বরূপ, নিচের কোডটি একটি আয়তক্ষেত্রকে ৪৫ ডিগ্রি ঘোরায়:

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

একটি ফোন যার স্ক্রিনের কেন্দ্রে একটি আয়তক্ষেত্র ৪৫ ডিগ্রি কোণে ঘোরানো আছে।
চিত্র ৫। আমরা বর্তমান ড্রয়িং স্কোপে একটি ঘূর্ণন প্রয়োগ করতে rotate() ব্যবহার করি, যা আয়তক্ষেত্রটিকে ৪৫ ডিগ্রি কোণে ঘোরায়।

ইনসেট

বর্তমান 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 composable ব্যবহার করতে পারেন। তবে, যদি আপনি DrawScope এর মধ্যে থাকেন অথবা কাস্টমাইজেশন সহ ম্যানুয়ালি আপনার টেক্সট আঁকতে চান, তাহলে আপনি DrawScope.drawText() মেথডটি ব্যবহার করতে পারেন।

টেক্সট আঁকতে, rememberTextMeasurer ব্যবহার করে একটি TextMeasurer তৈরি করুন এবং মেজারার সহ drawText কল করুন:

val textMeasurer = rememberTextMeasurer()

Canvas(modifier = Modifier.fillMaxSize()) {
    drawText(textMeasurer, "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()
)

লেখাটি এখন নির্দিষ্ট সীমার মধ্যে আঁকা হয় এবং শেষে একটি এলিপসিস (তিনটি বিন্দু) থাকে:

গোলাপী পটভূমিতে আঁকা লেখা, যেখানে ডট ডট চিহ্ন দিয়ে লেখাটি কেটে দেওয়া হয়েছে।
চিত্র ১০। টেক্সট পরিমাপের উপর নির্দিষ্ট সীমাবদ্ধতাসহ TextOverflow.Ellipsis

ছবি আঁকুন

DrawScope ব্যবহার করে একটি ImageBitmap আঁকতে, ImageBitmap.imageResource() ব্যবহার করে ছবিটি লোড করুন এবং তারপর drawImage কল করুন:

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

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

ক্যানভাসে আঁকা একটি কুকুরের ছবি
চিত্র ১১। ক্যানভাসে একটি 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()
)

কম্পোজে আঁকা একটি উল্টো বেগুনি পথের ত্রিভুজ।
চিত্র ১২। কম্পোজে Path তৈরি ও অঙ্কন করা।

Canvas অবজেক্ট অ্যাক্সেস করা

DrawScope এর মাধ্যমে আপনি সরাসরি একটি Canvas অবজেক্ট অ্যাক্সেস করতে পারেন না। সরাসরি Canvas অবজেক্টটি অ্যাক্সেস করার জন্য আপনি DrawScope.drawIntoCanvas() ব্যবহার করতে পারেন, যার উপর আপনি বিভিন্ন ফাংশন কল করতে পারবেন।

উদাহরণস্বরূপ, আপনার যদি একটি কাস্টম Drawable থাকে যা আপনি ক্যানভাসে আঁকতে চান, তাহলে আপনি ক্যানভাসটি অ্যাক্সেস করে Canvas অবজেক্টটি পাস করে Drawable#draw() কল করতে পারেন:

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

একটি ডিম্বাকৃতির কালো শেপড্রয়েবল যা সম্পূর্ণ আকার জুড়ে থাকে।
চিত্র ১৩। একটি Drawable আঁকার জন্য ক্যানভাস অ্যাক্সেস করা।

আরও জানুন

Compose-এ অঙ্কন সম্পর্কে আরও তথ্যের জন্য, নিম্নলিখিত উৎসগুলো দেখুন:

{% হুবহু %} {% endverbatim %} {% হুবহু %} {% endverbatim %}