এক নজরে UI তৈরি করুন

এই পৃষ্ঠাটি বর্ণনা করে যে কীভাবে আকারগুলি পরিচালনা করতে হয় এবং গ্ল্যান্সের সাথে নমনীয় এবং প্রতিক্রিয়াশীল লেআউটগুলি প্রদান করে, বিদ্যমান গ্ল্যান্স উপাদানগুলি ব্যবহার করে৷

Box , Column এবং Row ব্যবহার করুন

গ্ল্যান্সের তিনটি প্রধান কম্পোজেবল লেআউট রয়েছে:

  • Box : উপাদানগুলিকে অন্যটির উপরে রাখে। এটি একটি RelativeLayout এ অনুবাদ করে।

  • Column : উল্লম্ব অক্ষে উপাদানগুলিকে একে অপরের পরে রাখে। এটি উল্লম্ব অভিযোজন সহ একটি LinearLayout অনুবাদ করে।

  • Row : অনুভূমিক অক্ষে পরস্পরের পর উপাদানগুলিকে স্থাপন করে। এটি অনুভূমিক অভিযোজন সহ একটি LinearLayout অনুবাদ করে।

গ্ল্যান্স Scaffold অবজেক্টকে সমর্থন করে। একটি প্রদত্ত Scaffold অবজেক্টের মধ্যে আপনার Column , Row এবং Box কম্পোজেবল রাখুন।

একটি কলাম, সারি এবং বক্স লেআউটের ছবি।
চিত্র 1. কলাম, সারি এবং বাক্স সহ লেআউটের উদাহরণ।

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

নিম্নলিখিত উদাহরণটি আপনাকে দেখায় কিভাবে একটি Row তৈরি করতে হয় যা তার বাচ্চাদের অনুভূমিকভাবে সমানভাবে বিতরণ করে, যেমন চিত্র 1-এ দেখা গেছে:

Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) {
    val modifier = GlanceModifier.defaultWeight()
    Text("first", modifier)
    Text("second", modifier)
    Text("third", modifier)
}

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

স্ক্রোলযোগ্য লেআউট ব্যবহার করুন

প্রতিক্রিয়াশীল সামগ্রী প্রদান করার আরেকটি উপায় হল এটি স্ক্রোলযোগ্য করে তোলা। এটি LazyColumn composable দিয়ে সম্ভব। এই কম্পোজেবল আপনাকে অ্যাপ উইজেটে একটি স্ক্রোলযোগ্য পাত্রের ভিতরে প্রদর্শিত আইটেমগুলির একটি সেট সংজ্ঞায়িত করতে দেয়।

নিম্নলিখিত স্নিপেটগুলি LazyColumn ভিতরে আইটেমগুলিকে সংজ্ঞায়িত করার বিভিন্ন উপায় দেখায়।

আপনি আইটেম সংখ্যা প্রদান করতে পারেন:

// Remember to import Glance Composables
// import androidx.glance.appwidget.layout.LazyColumn

LazyColumn {
    items(10) { index: Int ->
        Text(
            text = "Item $index",
            modifier = GlanceModifier.fillMaxWidth()
        )
    }
}

পৃথক আইটেম প্রদান করুন:

LazyColumn {
    item {
        Text("First Item")
    }
    item {
        Text("Second Item")
    }
}

আইটেমগুলির একটি তালিকা বা অ্যারে প্রদান করুন:

LazyColumn {
    items(peopleNameList) { name ->
        Text(name)
    }
}

আপনি পূর্ববর্তী উদাহরণগুলির সংমিশ্রণও ব্যবহার করতে পারেন:

LazyColumn {
    item {
        Text("Names:")
    }
    items(peopleNameList) { name ->
        Text(name)
    }

    // or in case you need the index:
    itemsIndexed(peopleNameList) { index, person ->
        Text("$person at index $index")
    }
}

মনে রাখবেন যে আগের স্নিপেটটি itemId নির্দিষ্ট করে না। itemId নির্দিষ্ট করা কর্মক্ষমতা উন্নত করতে এবং অ্যান্ড্রয়েড 12 এর পর থেকে তালিকা এবং appWidget আপডেটের মাধ্যমে স্ক্রোল অবস্থান বজায় রাখতে সহায়তা করে (উদাহরণস্বরূপ, তালিকা থেকে আইটেমগুলি যোগ করা বা সরানোর সময়)। নিম্নলিখিত উদাহরণ দেখায় কিভাবে একটি itemId নির্দিষ্ট করতে হয়:

items(items = peopleList, key = { person -> person.id }) { person ->
    Text(person.name)
}

SizeMode সংজ্ঞায়িত করুন

ডিভাইস, ব্যবহারকারীর পছন্দ বা লঞ্চারের উপর নির্ভর করে AppWidget মাপ ভিন্ন হতে পারে, তাই নমনীয় লেআউট প্রদান করা গুরুত্বপূর্ণ যেমন নমনীয় উইজেট লেআউট প্রদান পৃষ্ঠায় বর্ণিত আছে। Glance এটিকে SizeMode সংজ্ঞা এবং LocalSize মান দিয়ে সহজ করে। নিম্নলিখিত বিভাগ তিনটি মোড বর্ণনা.

SizeMode.Single

SizeMode.Single হল ডিফল্ট মোড। এটি নির্দেশ করে যে শুধুমাত্র এক ধরনের সামগ্রী প্রদান করা হয়; অর্থাৎ, AppWidget উপলব্ধ আকার পরিবর্তিত হলেও, সামগ্রীর আকার পরিবর্তন করা হয় না।

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Single

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the minimum size or resizable
        // size defined in the App Widget metadata
        val size = LocalSize.current
        // ...
    }
}

এই মোড ব্যবহার করার সময়, নিশ্চিত করুন যে:

  • ন্যূনতম এবং সর্বাধিক আকারের মেটাডেটা মানগুলি সামগ্রীর আকারের উপর ভিত্তি করে সঠিকভাবে সংজ্ঞায়িত করা হয়।
  • প্রত্যাশিত আকারের সীমার মধ্যে সামগ্রীটি যথেষ্ট নমনীয়।

সাধারণভাবে, আপনার এই মোডটি ব্যবহার করা উচিত যখন হয়:

ক) AppWidget একটি নির্দিষ্ট আকার রয়েছে, বা খ) এটি পুনরায় আকার দেওয়ার সময় এটির বিষয়বস্তু পরিবর্তন করে না।

SizeMode.Responsive

এই মোডটি প্রতিক্রিয়াশীল লেআউট প্রদানের সমতুল্য, যা GlanceAppWidget নির্দিষ্ট মাপের দ্বারা আবদ্ধ প্রতিক্রিয়াশীল লেআউটগুলির একটি সেট সংজ্ঞায়িত করতে দেয়৷ প্রতিটি সংজ্ঞায়িত আকারের জন্য, যখন AppWidget তৈরি বা আপডেট করা হয় তখন বিষয়বস্তু তৈরি করা হয় এবং নির্দিষ্ট আকারে ম্যাপ করা হয়। সিস্টেম তারপর উপলব্ধ আকারের উপর ভিত্তি করে সেরা ফিটিং একটি নির্বাচন করে।

উদাহরণস্বরূপ, আমাদের গন্তব্য AppWidget এ, আপনি তিনটি আকার এবং এর বিষয়বস্তু সংজ্ঞায়িত করতে পারেন:

class MyAppWidget : GlanceAppWidget() {

    companion object {
        private val SMALL_SQUARE = DpSize(100.dp, 100.dp)
        private val HORIZONTAL_RECTANGLE = DpSize(250.dp, 100.dp)
        private val BIG_SQUARE = DpSize(250.dp, 250.dp)
    }

    override val sizeMode = SizeMode.Responsive(
        setOf(
            SMALL_SQUARE,
            HORIZONTAL_RECTANGLE,
            BIG_SQUARE
        )
    )

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be one of the sizes defined above.
        val size = LocalSize.current
        Column {
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            }
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width >= HORIZONTAL_RECTANGLE.width) {
                    Button("School")
                }
            }
            if (size.height >= BIG_SQUARE.height) {
                Text(text = "provided by X")
            }
        }
    }
}

পূর্ববর্তী উদাহরণে, provideContent পদ্ধতিটি তিনবার বলা হয় এবং সংজ্ঞায়িত আকারে ম্যাপ করা হয়।

  • প্রথম কলে, আকার 100x100 এ মূল্যায়ন করা হয়। বিষয়বস্তুতে অতিরিক্ত বোতাম বা উপরের এবং নীচের পাঠ্য অন্তর্ভুক্ত নয়।
  • দ্বিতীয় কলে, আকার 250x100 মূল্যায়ন করা হয়। বিষয়বস্তুতে অতিরিক্ত বোতাম রয়েছে, তবে উপরের এবং নীচের পাঠ্য নয়।
  • তৃতীয় কলে, আকার 250x250 মূল্যায়ন করা হয়। বিষয়বস্তু অতিরিক্ত বোতাম এবং উভয় পাঠ্য অন্তর্ভুক্ত.

SizeMode.Responsive হল অন্য দুটি মোডের সংমিশ্রণ, এবং আপনাকে পূর্বনির্ধারিত সীমার মধ্যে প্রতিক্রিয়াশীল বিষয়বস্তু সংজ্ঞায়িত করতে দেয়। সাধারণভাবে, এই মোডটি আরও ভাল পারফর্ম করে এবং যখন AppWidget আকার পরিবর্তন করা হয় তখন মসৃণ রূপান্তরের অনুমতি দেয়৷

SizeMode এবং AppWidget উপলব্ধ আকারের উপর নির্ভর করে নিম্নলিখিত টেবিলটি আকারের মান দেখায়:

উপলব্ধ আকার 105 x 110 203 x 112 72 x 72 203 x 150
SizeMode.Single 110 x 110 110 x 110 110 x 110 110 x 110
SizeMode.Exact 105 x 110 203 x 112 72 x 72 203 x 150
SizeMode.Responsive 80 x 100 80 x 100 80 x 100 150 x 120
* সঠিক মানগুলি শুধুমাত্র ডেমো উদ্দেশ্যে।

SizeMode.Exact

SizeMode.Exact হল সঠিক লেআউট প্রদানের সমতুল্য, যা GlanceAppWidget বিষয়বস্তুর জন্য অনুরোধ করে প্রতিবার উপলব্ধ AppWidget আকার পরিবর্তন করার সময় (উদাহরণস্বরূপ, যখন ব্যবহারকারী হোমস্ক্রীনে AppWidget আকার পরিবর্তন করে)।

উদাহরণস্বরূপ, গন্তব্য উইজেটে, একটি অতিরিক্ত বোতাম যোগ করা যেতে পারে যদি উপলব্ধ প্রস্থ একটি নির্দিষ্ট মানের চেয়ে বড় হয়।

class MyAppWidget : GlanceAppWidget() {

    override val sizeMode = SizeMode.Exact

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        // ...

        provideContent {
            MyContent()
        }
    }

    @Composable
    private fun MyContent() {
        // Size will be the size of the AppWidget
        val size = LocalSize.current
        Column {
            Text(text = "Where to?", modifier = GlanceModifier.padding(12.dp))
            Row(horizontalAlignment = Alignment.CenterHorizontally) {
                Button()
                Button()
                if (size.width > 250.dp) {
                    Button("School")
                }
            }
        }
    }
}

এই মোডটি অন্যদের তুলনায় আরো নমনীয়তা প্রদান করে, তবে এটি কয়েকটি সতর্কতার সাথে আসে:

  • প্রতিবার আকার পরিবর্তনের সময় AppWidget সম্পূর্ণরূপে পুনরায় তৈরি করা আবশ্যক। বিষয়বস্তু জটিল হলে এটি পারফরম্যান্স সমস্যা এবং UI জাম্প হতে পারে।
  • লঞ্চারের বাস্তবায়নের উপর নির্ভর করে উপলব্ধ আকার ভিন্ন হতে পারে। উদাহরণস্বরূপ, যদি লঞ্চার মাপের তালিকা প্রদান না করে, ন্যূনতম সম্ভাব্য আকার ব্যবহার করা হয়।
  • প্রি-অ্যান্ড্রয়েড 12 ডিভাইসে, আকার গণনার যুক্তি সব পরিস্থিতিতে কাজ নাও করতে পারে।

সাধারণভাবে, আপনার এই মোডটি ব্যবহার করা উচিত যদি SizeMode.Responsive ব্যবহার করা না যায় (অর্থাৎ, প্রতিক্রিয়াশীল লেআউটের একটি ছোট সেট সম্ভব নয়)।

সম্পদ অ্যাক্সেস

নিম্নলিখিত উদাহরণে দেখানো যেকোন Android রিসোর্স অ্যাক্সেস করতে LocalContext.current ব্যবহার করুন:

LocalContext.current.getString(R.string.glance_title)

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

কম্পোজেবল এবং পদ্ধতিগুলি "প্রোভাইডার" ব্যবহার করে সম্পদ গ্রহণ করে, যেমন ImageProvider , অথবা GlanceModifier.background(R.color.blue) এর মতো ওভারলোড পদ্ধতি ব্যবহার করে। উদাহরণ স্বরূপ:

Column(
    modifier = GlanceModifier.background(R.color.default_widget_background)
) { /**...*/ }

Image(
    provider = ImageProvider(R.drawable.ic_logo),
    contentDescription = "My image",
)

পাঠ্য পরিচালনা করুন

Glance 1.1.0 আপনার পাঠ্য শৈলী সেট করার জন্য একটি API অন্তর্ভুক্ত করে। টেক্সটস্টাইল ক্লাসের fontSize , fontWeight বা fontFamily অ্যাট্রিবিউট ব্যবহার করে টেক্সট স্টাইল সেট করুন।

fontFamily সমস্ত সিস্টেম ফন্ট সমর্থন করে, যেমনটি নিম্নলিখিত উদাহরণে দেখানো হয়েছে, কিন্তু অ্যাপে কাস্টম ফন্ট সমর্থিত নয়:

Text(
    style = TextStyle(
        fontWeight = FontWeight.Bold,
        fontSize = 18.sp,
        fontFamily = FontFamily.Monospace
    ),
    text = "Example Text"
)

যৌগিক বোতাম যোগ করুন

কম্পাউন্ড বোতামগুলি Android 12 এ চালু করা হয়েছিল। গ্ল্যান্স নিম্নলিখিত ধরণের যৌগিক বোতামগুলির জন্য পিছনের সামঞ্জস্যকে সমর্থন করে:

এই যৌগিক বোতামগুলি প্রতিটি একটি ক্লিকযোগ্য দৃশ্য প্রদর্শন করে যা "চেক করা" অবস্থার প্রতিনিধিত্ব করে।

var isApplesChecked by remember { mutableStateOf(false) }
var isEnabledSwitched by remember { mutableStateOf(false) }
var isRadioChecked by remember { mutableStateOf(0) }

CheckBox(
    checked = isApplesChecked,
    onCheckedChange = { isApplesChecked = !isApplesChecked },
    text = "Apples"
)

Switch(
    checked = isEnabledSwitched,
    onCheckedChange = { isEnabledSwitched = !isEnabledSwitched },
    text = "Enabled"
)

RadioButton(
    checked = isRadioChecked == 1,
    onClick = { isRadioChecked = 1 },
    text = "Checked"
)

যখন রাষ্ট্র পরিবর্তন হয়, প্রদত্ত ল্যাম্বডা ট্রিগার হয়। আপনি চেক অবস্থা সংরক্ষণ করতে পারেন, নিম্নলিখিত উদাহরণে দেখানো হয়েছে:

class MyAppWidget : GlanceAppWidget() {

    override suspend fun provideGlance(context: Context, id: GlanceId) {
        val myRepository = MyRepository.getInstance()

        provideContent {
            val scope = rememberCoroutineScope()

            val saveApple: (Boolean) -> Unit =
                { scope.launch { myRepository.saveApple(it) } }
            MyContent(saveApple)
        }
    }

    @Composable
    private fun MyContent(saveApple: (Boolean) -> Unit) {

        var isAppleChecked by remember { mutableStateOf(false) }

        Button(
            text = "Save",
            onClick = { saveApple(isAppleChecked) }
        )
    }
}

এছাড়াও আপনি CheckBox , Switch এবং RadioButton রঙগুলি কাস্টমাইজ করতে colors বৈশিষ্ট্য প্রদান করতে পারেন:

CheckBox(
    // ...
    colors = CheckboxDefaults.colors(
        checkedColor = ColorProvider(day = colorAccentDay, night = colorAccentNight),
        uncheckedColor = ColorProvider(day = Color.DarkGray, night = Color.LightGray)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked }
)

Switch(
    // ...
    colors = SwitchDefaults.colors(
        checkedThumbColor = ColorProvider(day = Color.Red, night = Color.Cyan),
        uncheckedThumbColor = ColorProvider(day = Color.Green, night = Color.Magenta),
        checkedTrackColor = ColorProvider(day = Color.Blue, night = Color.Yellow),
        uncheckedTrackColor = ColorProvider(day = Color.Magenta, night = Color.Green)
    ),
    checked = isChecked,
    onCheckedChange = { isChecked = !isChecked },
    text = "Enabled"
)

RadioButton(
    // ...
    colors = RadioButtonDefaults.colors(
        checkedColor = ColorProvider(day = Color.Cyan, night = Color.Yellow),
        uncheckedColor = ColorProvider(day = Color.Red, night = Color.Blue)
    ),

)

অতিরিক্ত উপাদান

এক নজরে 1.1.0 অতিরিক্ত উপাদানের প্রকাশ অন্তর্ভুক্ত করে, যা নিম্নলিখিত টেবিলে বর্ণিত হয়েছে:

নাম ছবি রেফারেন্স লিঙ্ক অতিরিক্ত নোট
ভরা বোতাম alt_text উপাদান
আউটলাইন বোতাম alt_text উপাদান
আইকন বোতাম alt_text উপাদান প্রাথমিক/মাধ্যমিক/শুধুমাত্র আইকন
শিরোনাম বাক্স alt_text উপাদান
ভারা স্ক্যাফোল্ড এবং টাইটেল বার একই ডেমোতে রয়েছে।

ডিজাইনের সুনির্দিষ্ট বিষয়ে আরও তথ্যের জন্য, ফিগমা-তে এই ডিজাইন কিটের কম্পোনেন্ট ডিজাইনগুলি দেখুন।