গ্রাফিক্স মডিফায়ার

Canvas কম্পোজেবল ছাড়াও, কম্পোজে বেশ কিছু দরকারী গ্রাফিক্স Modifiers রয়েছে যা কাস্টম বিষয়বস্তু আঁকতে সাহায্য করে। এই মডিফায়ারগুলি দরকারী কারণ এগুলি যে কোনও কম্পোজেবলে প্রয়োগ করা যেতে পারে।

অঙ্কন সংশোধক

সমস্ত অঙ্কন কমান্ড রচনায় একটি অঙ্কন সংশোধক দিয়ে সম্পন্ন করা হয়। রচনায় তিনটি প্রধান অঙ্কন সংশোধক রয়েছে:

অঙ্কনের জন্য বেস মডিফায়ার হল drawWithContent , যেখানে আপনি আপনার কম্পোজেবলের অঙ্কন ক্রম এবং মডিফায়ারের ভিতরে জারি করা অঙ্কন কমান্ডগুলি নির্ধারণ করতে পারেন। drawBehind হল drawWithContent চারপাশে একটি সুবিধাজনক র‍্যাপার যেখানে কম্পোজেবলের বিষয়বস্তুর পিছনে অঙ্কন ক্রম সেট করা আছে। drawWithCache এর ভিতরের onDrawBehind বা onDrawWithContent কল করে - এবং সেগুলির মধ্যে তৈরি বস্তুগুলিকে ক্যাশ করার জন্য একটি প্রক্রিয়া প্রদান করে।

Modifier.drawWithContent : অঙ্কন ক্রম নির্বাচন করুন

Modifier.drawWithContent আপনাকে কম্পোজেবলের বিষয়বস্তুর আগে বা পরে DrawScope অপারেশন চালাতে দেয়। কম্পোজেবলের প্রকৃত বিষয়বস্তু রেন্ডার করতে drawContent কল করতে ভুলবেন না। এই সংশোধকটির সাহায্যে, আপনি অপারেশনের ক্রম নির্ধারণ করতে পারেন, যদি আপনি চান যে আপনার সামগ্রীটি আপনার কাস্টম অঙ্কন অপারেশনের আগে বা পরে আঁকা হোক৷

উদাহরণস্বরূপ, আপনি যদি UI-তে একটি ফ্ল্যাশলাইট কীহোল প্রভাব তৈরি করতে আপনার সামগ্রীর উপরে একটি রেডিয়াল গ্রেডিয়েন্ট রেন্ডার করতে চান তবে আপনি নিম্নলিখিতগুলি করতে পারেন:

var pointerOffset by remember {
    mutableStateOf(Offset(0f, 0f))
}
Column(
    modifier = Modifier
        .fillMaxSize()
        .pointerInput("dragging") {
            detectDragGestures { change, dragAmount ->
                pointerOffset += dragAmount
            }
        }
        .onSizeChanged {
            pointerOffset = Offset(it.width / 2f, it.height / 2f)
        }
        .drawWithContent {
            drawContent()
            // draws a fully black area with a small keyhole at pointerOffset that’ll show part of the UI.
            drawRect(
                Brush.radialGradient(
                    listOf(Color.Transparent, Color.Black),
                    center = pointerOffset,
                    radius = 100.dp.toPx(),
                )
            )
        }
) {
    // Your composables here
}

চিত্র 1 : একটি ফ্ল্যাশলাইট ধরনের UI অভিজ্ঞতা তৈরি করতে কম্পোজেবলের উপরে Modifier.drawWithContent ব্যবহার করা হয়েছে।

Modifier.drawBehind : একটি কম্পোজেবলের পিছনে আঁকা

Modifier.drawBehind আপনাকে স্ক্রীনে আঁকা কম্পোজযোগ্য বিষয়বস্তুর পিছনে DrawScope অপারেশন করতে দেয়। আপনি যদি Canvas বাস্তবায়নের দিকে নজর দেন, তাহলে আপনি লক্ষ্য করবেন যে এটি Modifier.drawBehind চারপাশে একটি সুবিধাজনক মোড়ক মাত্র।

Text পিছনে একটি বৃত্তাকার আয়তক্ষেত্র আঁকতে:

Text(
    "Hello Compose!",
    modifier = Modifier
        .drawBehind {
            drawRoundRect(
                Color(0xFFBBAAEE),
                cornerRadius = CornerRadius(10.dp.toPx())
            )
        }
        .padding(4.dp)
)

যা নিম্নলিখিত ফলাফল তৈরি করে:

টেক্সট এবং একটি পটভূমি Modifier.drawBhind ব্যবহার করে আঁকা
চিত্র 2 : Modifier.drawBhind ব্যবহার করে আঁকা পাঠ্য এবং একটি পটভূমি

Modifier.drawWithCache : ড্র অবজেক্ট অঙ্কন এবং ক্যাশে করা

Modifier.drawWithCache এর ভিতরে তৈরি করা বস্তুগুলোকে ক্যাশে রাখে। যতক্ষণ পর্যন্ত অঙ্কন এলাকার আকার একই থাকে ততক্ষণ অবজেক্টগুলি ক্যাশ করা হয়, বা পঠিত কোনও স্টেট অবজেক্ট পরিবর্তিত না হয়। এই সংশোধকটি অঙ্কন কলগুলির কার্যকারিতা উন্নত করার জন্য দরকারী কারণ এটি ড্রতে তৈরি করা বস্তুগুলি (যেমন: Brush, Shader, Path ইত্যাদি) পুনরায় বরাদ্দ করার প্রয়োজন এড়ায়।

বিকল্পভাবে, আপনি মোডিফায়ারের বাইরে, remember ব্যবহার করে অবজেক্ট ক্যাশেও করতে পারেন। যাইহোক, এটি সর্বদা সম্ভব নয় কারণ আপনার সর্বদা রচনাটিতে অ্যাক্সেস থাকে না। বস্তুগুলি শুধুমাত্র অঙ্কনের জন্য ব্যবহার করা হলে drawWithCache ব্যবহার করা আরও কার্যকরী হতে পারে।

উদাহরণস্বরূপ, যদি আপনি একটি Text পিছনে একটি গ্রেডিয়েন্ট আঁকার জন্য একটি Brush তৈরি করেন, drawWithCache ব্যবহার করে অঙ্কন এলাকার আকার পরিবর্তন না হওয়া পর্যন্ত Brush অবজেক্টটিকে ক্যাশ করে:

Text(
    "Hello Compose!",
    modifier = Modifier
        .drawWithCache {
            val brush = Brush.linearGradient(
                listOf(
                    Color(0xFF9E82F0),
                    Color(0xFF42A5F5)
                )
            )
            onDrawBehind {
                drawRoundRect(
                    brush,
                    cornerRadius = CornerRadius(10.dp.toPx())
                )
            }
        }
)

drawWithCache দিয়ে ব্রাশ অবজেক্ট ক্যাশ করা হচ্ছে
চিত্র 3 : drawWithCache দিয়ে ব্রাশ অবজেক্ট ক্যাশ করা

গ্রাফিক্স মডিফায়ার

Modifier.graphicsLayer : কম্পোজেবলে রূপান্তর প্রয়োগ করুন

Modifier.graphicsLayer হল একটি মডিফায়ার যা কম্পোজেবল ড্রয়ের বিষয়বস্তুকে ড্র লেয়ারে পরিণত করে। একটি স্তর কয়েকটি ভিন্ন ফাংশন প্রদান করে, যেমন:

  • এর অঙ্কন নির্দেশাবলীর জন্য বিচ্ছিন্নতা ( RenderNode অনুরূপ)। একটি স্তরের অংশ হিসাবে ক্যাপচার করা অঙ্কন নির্দেশাবলী অ্যাপ্লিকেশন কোড পুনরায় নির্বাহ না করে রেন্ডারিং পাইপলাইন দ্বারা দক্ষতার সাথে পুনরায় জারি করা যেতে পারে।
  • একটি স্তরের মধ্যে থাকা সমস্ত অঙ্কন নির্দেশাবলীতে প্রযোজ্য রূপান্তর।
  • রচনা ক্ষমতার জন্য রাস্টারাইজেশন। যখন একটি স্তর রাস্টারাইজ করা হয়, তখন এর অঙ্কন নির্দেশাবলী কার্যকর করা হয় এবং আউটপুট একটি অফস্ক্রিন বাফারে ক্যাপচার করা হয়। পরবর্তী ফ্রেমের জন্য এই ধরনের একটি বাফার সংমিশ্রণ করা স্বতন্ত্র নির্দেশাবলী কার্যকর করার চেয়ে দ্রুততর, কিন্তু স্কেলিং বা ঘূর্ণনের মতো রূপান্তর প্রয়োগ করা হলে এটি একটি বিটম্যাপ হিসাবে আচরণ করবে।

রূপান্তর

Modifier.graphicsLayer এর অঙ্কন নির্দেশাবলীর জন্য বিচ্ছিন্নতা প্রদান করে; উদাহরণস্বরূপ, Modifier.graphicsLayer ব্যবহার করে বিভিন্ন রূপান্তর প্রয়োগ করা যেতে পারে। অঙ্কন ল্যাম্বডা পুনরায় চালানোর প্রয়োজন ছাড়াই এগুলি অ্যানিমেটেড বা পরিবর্তন করা যেতে পারে।

Modifier.graphicsLayer আপনার কম্পোজেবলের পরিমাপকৃত আকার বা স্থান পরিবর্তন করে না, কারণ এটি শুধুমাত্র ড্র ফেজকে প্রভাবিত করে। এর মানে হল যে আপনার কম্পোজেবল অন্যদের ওভারল্যাপ করতে পারে যদি এটি তার লেআউট সীমার বাইরে অঙ্কন করে।

এই সংশোধকের সাথে নিম্নলিখিত রূপান্তরগুলি প্রয়োগ করা যেতে পারে:

স্কেল - আকার বৃদ্ধি

scaleX এবং scaleY যথাক্রমে অনুভূমিক বা উল্লম্ব দিক থেকে বিষয়বস্তুকে বড় করে বা সঙ্কুচিত করে। 1.0f এর মান স্কেলে কোন পরিবর্তন নির্দেশ করে না, 0.5f এর মান মানে মাত্রার অর্ধেক।

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.scaleX = 1.2f
            this.scaleY = 0.8f
        }
)

চিত্র 4 : কম্পোজযোগ্য চিত্রে স্কেলএক্স এবং স্কেলওয়াই প্রয়োগ করা হয়েছে
অনুবাদ

translationX এবং translationY graphicsLayer দিয়ে পরিবর্তন করা যেতে পারে, translationX কম্পোজযোগ্য বাম বা ডান দিকে নিয়ে যায়। translationY কম্পোজেবলকে উপরে বা নিচে নিয়ে যায়।

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.translationX = 100.dp.toPx()
            this.translationY = 10.dp.toPx()
        }
)

চিত্র 5 : TranslationX এবং translationY ইমেজে Modifier.graphicsLayer এর সাথে প্রয়োগ করা হয়েছে
ঘূর্ণন

অনুভূমিকভাবে ঘোরানোর জন্য rotationX , উল্লম্বভাবে ঘোরানোর জন্য rotationY এবং Z অক্ষে ঘোরানোর জন্য rotationZ সেট করুন (স্ট্যান্ডার্ড ঘূর্ণন)। এই মান ডিগ্রী (0-360) নির্দিষ্ট করা হয়.

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.rotationX = 90f
            this.rotationY = 275f
            this.rotationZ = 180f
        }
)

চিত্র 6 : rotationX, rotationY এবং rotationZ চিত্রের উপর সেট করা হয়েছে Modifier.graphicsLayer
উৎপত্তি

একটি transformOrigin নির্দিষ্ট করা যেতে পারে। এটি তখন বিন্দু হিসাবে ব্যবহৃত হয় যেখান থেকে রূপান্তর ঘটে। এখন পর্যন্ত সমস্ত উদাহরণ TransformOrigin.Center ব্যবহার করেছে, যা (0.5f, 0.5f) । যদি আপনি (0f, 0f) এ উৎপত্তি উল্লেখ করেন, তাহলে রূপান্তরগুলি কম্পোজেবলের উপরের-বাম কোণ থেকে শুরু হয়।

আপনি যদি একটি rotationZ রূপান্তর দিয়ে মূল পরিবর্তন করেন, আপনি দেখতে পাবেন যে আইটেমটি কম্পোজেবলের উপরের বাম দিকে ঘোরে:

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "Sunset",
    modifier = Modifier
        .graphicsLayer {
            this.transformOrigin = TransformOrigin(0f, 0f)
            this.rotationX = 90f
            this.rotationY = 275f
            this.rotationZ = 180f
        }
)

চিত্র 7 : 0f, 0f এ সেট করা TransformOrigin-এর সাথে ঘূর্ণন প্রয়োগ করা হয়েছে

ক্লিপ এবং আকৃতি

আকৃতি সেই রূপরেখাটি নির্দিষ্ট করে যে বিষয়বস্তুটি যখন clip = true । এই উদাহরণে, আমরা দুটি আলাদা ক্লিপ রাখার জন্য দুটি বাক্স সেট করেছি - একটি graphicsLayer ক্লিপ ভেরিয়েবল ব্যবহার করে এবং অন্যটি সুবিধাজনক র্যাপার Modifier.clip ব্যবহার করে।

Column(modifier = Modifier.padding(16.dp)) {
    Box(
        modifier = Modifier
            .size(200.dp)
            .graphicsLayer {
                clip = true
                shape = CircleShape
            }
            .background(Color(0xFFF06292))
    ) {
        Text(
            "Hello Compose",
            style = TextStyle(color = Color.Black, fontSize = 46.sp),
            modifier = Modifier.align(Alignment.Center)
        )
    }
    Box(
        modifier = Modifier
            .size(200.dp)
            .clip(CircleShape)
            .background(Color(0xFF4DB6AC))
    )
}

প্রথম বাক্সের বিষয়বস্তু ("হ্যালো কম্পোজ" লেখা লেখা) বৃত্তের আকারে ক্লিপ করা হয়েছে:

ক্লিপ বক্স কম্পোজেবল প্রয়োগ করা হয়েছে
চিত্র 8 : বক্স কম্পোজেবলে ক্লিপ প্রয়োগ করা হয়েছে

আপনি যদি উপরের গোলাপী বৃত্তে একটি translationY প্রয়োগ করেন, আপনি দেখতে পাবেন যে কম্পোজেবলের সীমানা এখনও একই, কিন্তু বৃত্তটি নীচের বৃত্তের নীচে (এবং এর সীমানার বাইরে) আঁকে।

ক্লিপ translationY সহ প্রয়োগ করা হয়েছে এবং রূপরেখার জন্য লাল সীমানা
চিত্র 9 : ক্লিপ অনুবাদ সহ প্রয়োগ করা হয়েছে, এবং রূপরেখার জন্য লাল বর্ডার

এটি যে অঞ্চলে আঁকা হয়েছে তাতে কম্পোজযোগ্য ক্লিপ করতে, আপনি মডিফায়ার চেইনের শুরুতে আরেকটি Modifier.clip(RectangleShape) যোগ করতে পারেন। বিষয়বস্তু তারপর মূল সীমার ভিতরে থেকে যায়.

Column(modifier = Modifier.padding(16.dp)) {
    Box(
        modifier = Modifier
            .clip(RectangleShape)
            .size(200.dp)
            .border(2.dp, Color.Black)
            .graphicsLayer {
                clip = true
                shape = CircleShape
                translationY = 50.dp.toPx()
            }
            .background(Color(0xFFF06292))
    ) {
        Text(
            "Hello Compose",
            style = TextStyle(color = Color.Black, fontSize = 46.sp),
            modifier = Modifier.align(Alignment.Center)
        )
    }

    Box(
        modifier = Modifier
            .size(200.dp)
            .clip(RoundedCornerShape(500.dp))
            .background(Color(0xFF4DB6AC))
    )
}

গ্রাফিক্স লেয়ার রূপান্তরের উপরে ক্লিপ প্রয়োগ করা হয়েছে
চিত্র 10 : গ্রাফিক্স লেয়ার রূপান্তরের উপরে ক্লিপ প্রয়োগ করা হয়েছে

আলফা

Modifier.graphicsLayer পুরো স্তরের জন্য একটি alpha (অস্বচ্ছতা) সেট করতে ব্যবহার করা যেতে পারে। 1.0f সম্পূর্ণ অস্বচ্ছ এবং 0.0f অদৃশ্য।

Image(
    painter = painterResource(id = R.drawable.sunset),
    contentDescription = "clock",
    modifier = Modifier
        .graphicsLayer {
            this.alpha = 0.5f
        }
)

আলফা প্রয়োগ করা ছবি
চিত্র 11 : আলফা প্রয়োগ করা ছবি

কম্পোজিটিং কৌশল

আলফা এবং স্বচ্ছতার সাথে কাজ করা একটি একক আলফা মান পরিবর্তন করার মতো সহজ নাও হতে পারে। একটি আলফা পরিবর্তন করার পাশাপাশি, একটি graphicsLayer একটি CompositingStrategy সেট করার বিকল্পও রয়েছে। একটি CompositingStrategy নির্ধারণ করে যে কীভাবে কম্পোজেবলের বিষয়বস্তুটি ইতিমধ্যেই স্ক্রিনে আঁকা অন্যান্য সামগ্রীর সাথে সংমিশ্রিত (একত্রে রাখা) হয়।

বিভিন্ন কৌশল হল:

স্বয়ংক্রিয় (ডিফল্ট)

কম্পোজিটিং কৌশলটি বাকি graphicsLayer প্যারামিটার দ্বারা নির্ধারিত হয়। আলফা 1.0f এর কম হলে বা RenderEffect সেট করা থাকলে এটি লেয়ারটিকে অফস্ক্রিন বাফারে রেন্ডার করে। যখনই আলফা 1f-এর কম হয়, তখন বিষয়বস্তু রেন্ডার করার জন্য একটি সংমিশ্রণ স্তর স্বয়ংক্রিয়ভাবে তৈরি হয় এবং তারপরে সংশ্লিষ্ট আলফার সাথে এই অফস্ক্রিন বাফারটিকে গন্তব্যে আঁকতে হয়। একটি RenderEffect সেট করা বা ওভারস্ক্রোল সর্বদা CompositingStrategy সেট নির্বিশেষে একটি অফস্ক্রিন বাফারে সামগ্রী রেন্ডার করে৷

অফস্ক্রিন

গন্তব্যে রেন্ডার করার আগে কম্পোজেবলের বিষয়বস্তু সবসময় একটি অফস্ক্রিন টেক্সচার বা বিটম্যাপে রাস্টারাইজ করা হয়। এটি মাস্ক বিষয়বস্তুতে BlendMode ক্রিয়াকলাপ প্রয়োগ করার জন্য এবং অঙ্কন নির্দেশাবলীর জটিল সেট রেন্ডার করার সময় কার্য সম্পাদনের জন্য দরকারী।

CompositingStrategy.Offscreen ব্যবহার করার একটি উদাহরণ হল BlendModes এর সাথে। নীচের উদাহরণটি একবার দেখে বলুন যে আপনি BlendMode.Clear ব্যবহার করে এমন একটি ড্র কমান্ড জারি করে কম্পোজযোগ্য একটি Image অংশগুলি সরাতে চান। আপনি যদি CompositingStrategy.OffscreencompositingStrategy সেট না করেন, তাহলে BlendMode এর নিচের সমস্ত বিষয়বস্তুর সাথে ইন্টারঅ্যাক্ট করে।

Image(
    painter = painterResource(id = R.drawable.dog),
    contentDescription = "Dog",
    contentScale = ContentScale.Crop,
    modifier = Modifier
        .size(120.dp)
        .aspectRatio(1f)
        .background(
            Brush.linearGradient(
                listOf(
                    Color(0xFFC5E1A5),
                    Color(0xFF80DEEA)
                )
            )
        )
        .padding(8.dp)
        .graphicsLayer {
            compositingStrategy = CompositingStrategy.Offscreen
        }
        .drawWithCache {
            val path = Path()
            path.addOval(
                Rect(
                    topLeft = Offset.Zero,
                    bottomRight = Offset(size.width, size.height)
                )
            )
            onDrawWithContent {
                clipPath(path) {
                    // this draws the actual image - if you don't call drawContent, it wont
                    // render anything
                    this@onDrawWithContent.drawContent()
                }
                val dotSize = size.width / 8f
                // Clip a white border for the content
                drawCircle(
                    Color.Black,
                    radius = dotSize,
                    center = Offset(
                        x = size.width - dotSize,
                        y = size.height - dotSize
                    ),
                    blendMode = BlendMode.Clear
                )
                // draw the red circle indication
                drawCircle(
                    Color(0xFFEF5350), radius = dotSize * 0.8f,
                    center = Offset(
                        x = size.width - dotSize,
                        y = size.height - dotSize
                    )
                )
            }
        }
)

CompositingStrategy Offscreen সেট করার মাধ্যমে, এটি কমান্ডগুলি কার্যকর করার জন্য একটি অফস্ক্রিন টেক্সচার তৈরি করে (শুধুমাত্র এই কম্পোজেবলের বিষয়বস্তুতে BlendMode প্রয়োগ করে)। এটি তারপরে এটিকে স্ক্রীনে ইতিমধ্যে রেন্ডার করা হয়েছে তার উপরে রেন্ডার করে, ইতিমধ্যে আঁকা বিষয়বস্তুকে প্রভাবিত করে না।

একটি ছবিতে Modifier.drawWithContent একটি বৃত্তের ইঙ্গিত দেখাচ্ছে, BlendMode.Clear ভিতরে অ্যাপের সাথে
চিত্র 12 : একটি চিত্রে Modifier.drawWithContent একটি বৃত্তের ইঙ্গিত দেখাচ্ছে, সাথে BlendMode.Clear এবং CompositingStrategy.অফস্ক্রিন অ্যাপের ভিতরে

আপনি যদি CompositingStrategy.Offscreen ব্যবহার না করে থাকেন, তাহলে BlendMode.Clear প্রয়োগের ফলাফল গন্তব্যের সমস্ত পিক্সেল সাফ করে, আগে থেকে যা সেট করা ছিল তা নির্বিশেষে- উইন্ডোর রেন্ডারিং বাফার (কালো) দৃশ্যমান রেখে৷ আলফা জড়িত অনেক BlendModes অফস্ক্রিন বাফার ছাড়া আশানুরূপ কাজ করবে না। লাল বৃত্ত নির্দেশকের চারপাশে কালো রিং নোট করুন:

একটি চিত্রে Modifier.drawWithContent একটি বৃত্তের ইঙ্গিত দেখাচ্ছে, BlendMode.Clear সহ এবং কোন CompositingStrategy সেট নেই
চিত্র 13 : একটি চিত্রে Modifier.drawWithContent একটি বৃত্তের ইঙ্গিত দেখাচ্ছে, BlendMode.Clear সহ এবং কোন CompositingStrategy সেট নেই

এটি আরও কিছুটা বোঝার জন্য: যদি অ্যাপটির একটি স্বচ্ছ উইন্ডো ব্যাকগ্রাউন্ড থাকে এবং আপনি CompositingStrategy.Offscreen ব্যবহার না করেন, তাহলে BlendMode পুরো অ্যাপের সাথে ইন্টারঅ্যাক্ট করবে। এটি নীচের অ্যাপ বা ওয়ালপেপার দেখানোর জন্য সমস্ত পিক্সেল সাফ করবে, যেমন এই উদাহরণে:

একটি স্বচ্ছ উইন্ডো ব্যাকগ্রাউন্ড আছে এমন একটি অ্যাপের সাথে BlendMode.Clear ব্যবহার করে কোনো CompositingStrategy সেট করা হয়নি। গোলাপী ওয়ালপেপার লাল স্ট্যাটাস বৃত্তের চারপাশের এলাকা দিয়ে দেখানো হয়েছে।
চিত্র 14 : কোন কম্পোজিটিং স্ট্র্যাটেজি সেট করা নেই এবং ব্লেন্ডমোড ব্যবহার করা হয়েছে। একটি স্বচ্ছ উইন্ডো ব্যাকগ্রাউন্ড আছে এমন একটি অ্যাপের সাথে সাফ করুন। লাল অবস্থার বৃত্তের চারপাশের এলাকা দিয়ে গোলাপী ওয়ালপেপার কীভাবে দেখানো হয়েছে তা লক্ষ্য করুন।

এটা লক্ষণীয় যে CompositingStrategy.Offscreen ব্যবহার করার সময়, একটি অফস্ক্রিন টেক্সচার তৈরি করা হয় যা অঙ্কন এলাকার আকার হয় এবং পর্দায় আবার রেন্ডার করা হয়। এই কৌশলের সাহায্যে করা যেকোনো অঙ্কন কমান্ড ডিফল্টরূপে এই অঞ্চলে ক্লিপ করা হয়। নিচের কোড স্নিপেটটি অফস্ক্রিন টেক্সচার ব্যবহারে স্যুইচ করার সময় পার্থক্যগুলিকে চিত্রিত করে:

@Composable
fun CompositingStrategyExamples() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .wrapContentSize(Alignment.Center)
    ) {
        // Does not clip content even with a graphics layer usage here. By default, graphicsLayer
        // does not allocate + rasterize content into a separate layer but instead is used
        // for isolation. That is draw invalidations made outside of this graphicsLayer will not
        // re-record the drawing instructions in this composable as they have not changed
        Canvas(
            modifier = Modifier
                .graphicsLayer()
                .size(100.dp) // Note size of 100 dp here
                .border(2.dp, color = Color.Blue)
        ) {
            // ... and drawing a size of 200 dp here outside the bounds
            drawRect(color = Color.Magenta, size = Size(200.dp.toPx(), 200.dp.toPx()))
        }

        Spacer(modifier = Modifier.size(300.dp))

        /* Clips content as alpha usage here creates an offscreen buffer to rasterize content
        into first then draws to the original destination */
        Canvas(
            modifier = Modifier
                // force to an offscreen buffer
                .graphicsLayer(compositingStrategy = CompositingStrategy.Offscreen)
                .size(100.dp) // Note size of 100 dp here
                .border(2.dp, color = Color.Blue)
        ) {
            /* ... and drawing a size of 200 dp. However, because of the CompositingStrategy.Offscreen usage above, the
            content gets clipped */
            drawRect(color = Color.Red, size = Size(200.dp.toPx(), 200.dp.toPx()))
        }
    }
}

CompositingStrategy.Auto বনাম CompositingStrategy.Offscreen - অঞ্চলের অফস্ক্রিন ক্লিপ, যেখানে স্বয়ংক্রিয় নয়
চিত্র 15 : CompositingStrategy.Auto বনাম CompositingStrategy.Offscreen - অঞ্চলের অফস্ক্রিন ক্লিপ, যেখানে স্বয়ংক্রিয় নয়
ModulateAlpha

এই রচনা কৌশলটি graphicsLayer মধ্যে রেকর্ড করা প্রতিটি অঙ্কন নির্দেশাবলীর জন্য আলফা মডিউল করে। এটি 1.0f এর নিচে আলফার জন্য একটি অফস্ক্রিন বাফার তৈরি করবে না যদি না একটি RenderEffect সেট করা হয়, তাই এটি আলফা রেন্ডারিংয়ের জন্য আরও দক্ষ হতে পারে। যাইহোক, এটি ওভারল্যাপিং বিষয়বস্তুর জন্য বিভিন্ন ফলাফল প্রদান করতে পারে। ব্যবহারের ক্ষেত্রে যেখানে এটি আগে থেকেই জানা যায় যে বিষয়বস্তু ওভারল্যাপ হচ্ছে না, এটি 1-এর কম আলফা মান সহ CompositingStrategy.Auto থেকে ভাল পারফরম্যান্স প্রদান করতে পারে৷

বিভিন্ন কম্পোজিশন কৌশলের আরেকটি উদাহরণ নিচে দেওয়া হল - কম্পোজেবলের বিভিন্ন অংশে বিভিন্ন আলফা প্রয়োগ করা এবং একটি Modulate কৌশল প্রয়োগ করা:

@Preview
@Composable
fun CompositingStrategy_ModulateAlpha() {
    Column(
        modifier = Modifier
            .fillMaxSize()
            .padding(32.dp)
    ) {
        // Base drawing, no alpha applied
        Canvas(
            modifier = Modifier.size(200.dp)
        ) {
            drawSquares()
        }

        Spacer(modifier = Modifier.size(36.dp))

        // Alpha 0.5f applied to whole composable
        Canvas(
            modifier = Modifier
                .size(200.dp)
                .graphicsLayer {
                    alpha = 0.5f
                }
        ) {
            drawSquares()
        }
        Spacer(modifier = Modifier.size(36.dp))

        // 0.75f alpha applied to each draw call when using ModulateAlpha
        Canvas(
            modifier = Modifier
                .size(200.dp)
                .graphicsLayer {
                    compositingStrategy = CompositingStrategy.ModulateAlpha
                    alpha = 0.75f
                }
        ) {
            drawSquares()
        }
    }
}

private fun DrawScope.drawSquares() {

    val size = Size(100.dp.toPx(), 100.dp.toPx())
    drawRect(color = Red, size = size)
    drawRect(
        color = Purple, size = size,
        topLeft = Offset(size.width / 4f, size.height / 4f)
    )
    drawRect(
        color = Yellow, size = size,
        topLeft = Offset(size.width / 4f * 2f, size.height / 4f * 2f)
    )
}

val Purple = Color(0xFF7E57C2)
val Yellow = Color(0xFFFFCA28)
val Red = Color(0xFFEF5350)

ModulateAlpha প্রতিটি পৃথক ড্র কমান্ডে আলফা সেট প্রয়োগ করে
চিত্র 16 : ModulateAlpha প্রতিটি পৃথক ড্র কমান্ডে আলফা সেট প্রয়োগ করে

একটি বিটম্যাপে একটি রচনাযোগ্য বিষয়বস্তু লিখুন

একটি সাধারণ ব্যবহারের ক্ষেত্রে একটি কম্পোজেবল থেকে একটি Bitmap তৈরি করা হয়। একটি Bitmap আপনার কম্পোজেবল বিষয়বস্তু অনুলিপি করতে, rememberGraphicsLayer() ব্যবহার করে একটি GraphicsLayer তৈরি করুন।

drawWithContent() এবং graphicsLayer.record{} ব্যবহার করে অঙ্কন কমান্ডগুলিকে নতুন স্তরে পুনর্নির্দেশ করুন। তারপর drawLayer ব্যবহার করে দৃশ্যমান ক্যানভাসে স্তরটি আঁকুন:

val coroutineScope = rememberCoroutineScope()
val graphicsLayer = rememberGraphicsLayer()
Box(
    modifier = Modifier
        .drawWithContent {
            // call record to capture the content in the graphics layer
            graphicsLayer.record {
                // draw the contents of the composable into the graphics layer
                this@drawWithContent.drawContent()
            }
            // draw the graphics layer on the visible canvas
            drawLayer(graphicsLayer)
        }
        .clickable {
            coroutineScope.launch {
                val bitmap = graphicsLayer.toImageBitmap()
                // do something with the newly acquired bitmap
            }
        }
        .background(Color.White)
) {
    Text("Hello Android", fontSize = 26.sp)
}

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

কাস্টম অঙ্কন সংশোধক

আপনার নিজস্ব কাস্টম মডিফায়ার তৈরি করতে, DrawModifier ইন্টারফেস প্রয়োগ করুন। এটি আপনাকে একটি ContentDrawScope এ অ্যাক্সেস দেয়, যা Modifier.drawWithContent() ব্যবহার করার সময় উন্মুক্ত করা হয়। তারপর আপনি কোড পরিষ্কার করতে এবং সুবিধাজনক মোড়ক প্রদান করতে কাস্টম ড্রয়িং মডিফায়ারে সাধারণ অঙ্কন ক্রিয়াকলাপগুলি বের করতে পারেন; উদাহরণস্বরূপ, Modifier.background() একটি সুবিধাজনক DrawModifier

উদাহরণস্বরূপ, আপনি যদি একটি Modifier প্রয়োগ করতে চান যা উল্লম্বভাবে বিষয়বস্তু ফ্লিপ করে, আপনি নিম্নরূপ একটি তৈরি করতে পারেন:

class FlippedModifier : DrawModifier {
    override fun ContentDrawScope.draw() {
        scale(1f, -1f) {
            this@draw.drawContent()
        }
    }
}

fun Modifier.flipped() = this.then(FlippedModifier())

তারপর Text প্রয়োগ করা এই ফ্লিপড মডিফায়ারটি ব্যবহার করুন:

Text(
    "Hello Compose!",
    modifier = Modifier
        .flipped()
)

টেক্সটে কাস্টম ফ্লিপড মডিফায়ার
চিত্র 17 : টেক্সটে কাস্টম ফ্লিপড মডিফায়ার

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

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

{% শব্দার্থে %} {% endverbatim %} {% শব্দার্থে %} {% endverbatim %}