این صفحه نحوه مدیریت اندازهها و ارائه طرحبندیهای انعطافپذیر و واکنشگرا با Glance، با استفاده از اجزای موجود Glance را شرح میدهد.
استفاده از Box ، Column و Row
Glance سه طرحبندی اصلی قابل ترکیب دارد:
Box: عناصر را روی یکدیگر قرار میدهد. بهRelativeLayoutترجمه میشود.Column: عناصر را در محور عمودی، پشت سر هم قرار میدهد. این به یکLinearLayoutبا جهتگیری عمودی تبدیل میشود.Row: عناصر را در محور افقی پشت سر هم قرار میدهد. این به یکLinearLayoutبا جهت افقی تبدیل میشود.
Glance از اشیاء Scaffold پشتیبانی میکند. کامپوننتهای Column ، Row و Box خود را درون یک شیء Scaffold مشخص قرار دهید.

هر یک از این composableها به شما امکان میدهند ترازبندی عمودی و افقی محتوای آن و محدودیتهای عرض، ارتفاع، وزن یا padding را با استفاده از modifierها تعریف کنید. علاوه بر این، هر فرزند میتواند modifier خود را برای تغییر فضا و قرارگیری درون والد تعریف کند.
مثال زیر به شما نشان میدهد که چگونه یک Row ایجاد کنید که فرزندانش را به طور مساوی به صورت افقی توزیع کند، همانطور که در شکل 1 مشاهده میکنید:
Row(modifier = GlanceModifier.fillMaxWidth().padding(16.dp)) { val modifier = GlanceModifier.defaultWeight() Text("first", modifier) Text("second", modifier) Text("third", modifier) }
Row حداکثر عرض موجود را پر میکند و از آنجا که هر فرزند وزن یکسانی دارد، فضای موجود را به طور مساوی به اشتراک میگذارند. میتوانید وزنها، اندازهها، فاصلهگذاریها یا ترازبندیهای مختلفی را برای تطبیق طرحبندیها با نیازهای خود تعریف کنید.
از طرحبندیهای قابل اسکرول استفاده کنید
راه دیگر برای ارائه محتوای واکنشگرا، قابلیت اسکرول کردن آن است. این کار با استفاده از کامپوننت LazyColumn امکانپذیر است. این کامپوننت به شما امکان میدهد مجموعهای از آیتمها را تعریف کنید که درون یک کانتینر اسکرولپذیر در ویجت برنامه نمایش داده شوند.
قطعه کدهای زیر روشهای مختلفی برای تعریف آیتمها درون 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 به بهبود عملکرد و حفظ موقعیت اسکرول در بهروزرسانیهای لیست و appWidget از اندروید ۱۲ به بعد کمک میکند (برای مثال، هنگام اضافه کردن یا حذف موارد از لیست). مثال زیر نحوه مشخص کردن itemId را نشان میدهد:
items(items = peopleList, itemId = { person -> person.id.hashCode().toLong() }) { person -> Text(person.name) }
پیمایش سریع
پیمایش سریع (Snap scrolling) انیمیشنی است که به محتوای قابل پیمایش اجازه میدهد تا به بالای ظرف ویجت (widget container) بچسبد.
برای پیادهسازی پیمایش سریع، مطمئن شوید که شرایط زیر را دارید:
- وابستگی Glance خود را به نسخه ۱.۳.۰-alpha02 یا بالاتر بهروزرسانی کنید.
-
compileSdkخود را روی ۳۷ یا بالاتر تنظیم کنید، زیرا پیمایش اسنپ در دستگاههایی که اندروید ۱۷ و بالاتر دارند پشتیبانی میشود. -
LazyColumnخود را باVerticalScrollModeپیکربندی کنید. اگر دستگاه از پیمایش سریع پشتیبانی میکند، ازSnapScrollMatchHeightاستفاده کنید. در غیر این صورت،Normalاستفاده کنید.
اگر از پیمایش سریع برای تصاویر استفاده میکنید، به طرحبندی متعارف تصویر با حاشیهبندی کامل مراجعه کنید.
@Composable fun SnapScrollLayout() { val height = LocalSize.current.height val items = listOf( ColorItem(Color.Red, "Red"), ColorItem(Color.Yellow, "Yellow"), ColorItem(Color.Blue, "Blue") ) val scrollMode = if (Build.VERSION.SDK_INT >= 37) { VerticalScrollMode.SnapScrollMatchHeight(height) } else { VerticalScrollMode.Normal } LazyColumn( verticalScrollMode = scrollMode ) { items(items) { item -> ColorCard(item, height) } } } @Composable private fun ColorCard(item: ColorItem, height: Dp) { Box( modifier = GlanceModifier .background(item.color) .fillMaxWidth() .height(height), contentAlignment = Alignment.Center ) { Text( text = item.name, modifier = GlanceModifier.background(Color.White) ) } }
تعریف 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 نشان میدهد:
| اندازه موجود | ۱۰۵ در ۱۱۰ | ۲۰۳ در ۱۱۲ | ۷۲ در ۷۲ | ۲۰۳ در ۱۵۰ |
|---|---|---|---|---|
SizeMode.Single | ۱۱۰ × ۱۱۰ | ۱۱۰ × ۱۱۰ | ۱۱۰ × ۱۱۰ | ۱۱۰ × ۱۱۰ |
SizeMode.Exact | ۱۰۵ در ۱۱۰ | ۲۰۳ در ۱۱۲ | ۷۲ در ۷۲ | ۲۰۳ در ۱۵۰ |
SizeMode.Responsive | ۸۰ در ۱۰۰ | ۸۰ در ۱۰۰ | ۸۰ در ۱۰۰ | ۱۵۰ در ۱۲۰ |
| * مقادیر دقیق فقط برای اهداف نمایشی هستند. |
SizeMode.Exact
SizeMode.Exact معادل ارائه طرحبندیهای دقیق است که هر بار اندازه AppWidget موجود تغییر میکند (مثلاً وقتی کاربر AppWidget در صفحه اصلی تغییر میدهد)، محتوای GlanceAppWidget را درخواست میکند.
برای مثال، در ویجت مقصد، اگر عرض موجود بزرگتر از یک مقدار مشخص باشد، میتوان یک دکمه اضافی اضافه کرد.
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باید کاملاً از نو ساخته شود. این امر میتواند منجر به مشکلات عملکردی و پرشهای رابط کاربری در هنگام پیچیدگی محتوا شود. - اندازه موجود ممکن است بسته به پیادهسازی لانچر متفاوت باشد. برای مثال، اگر لانچر لیست اندازهها را ارائه ندهد، از حداقل اندازه ممکن استفاده میشود.
- در دستگاههای قبل از اندروید ۱۲، منطق محاسبه اندازه ممکن است در همه شرایط کار نکند.
به طور کلی، اگر SizeMode.Responsive قابل استفاده نباشد (یعنی، مجموعه کوچکی از طرحبندیهای واکنشگرا امکانپذیر نباشد)، باید از این حالت استفاده کنید.
دسترسی به منابع
برای دسترسی به هر منبع اندروید، LocalContext.current استفاده کنید، همانطور که در مثال زیر نشان داده شده است:
LocalContext.current.getString(R.string.glance_title)
توصیه میکنیم شناسههای منابع را مستقیماً ارائه دهید تا اندازه شیء نهایی RemoteViews کاهش یابد و منابع پویا، مانند رنگهای پویا ، فعال شوند.
Composableها و متدها منابع را با استفاده از یک "provider" مانند ImageProvider یا با استفاده از یک متد overload مانند 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 از کلاس TextStyle تنظیم کنید.
fontFamily از تمام فونتهای سیستم پشتیبانی میکند، همانطور که در مثال زیر نشان داده شده است، اما فونتهای سفارشی در برنامهها پشتیبانی نمیشوند:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
دکمههای ترکیبی اضافه کنید
دکمههای ترکیبی در اندروید ۱۲ معرفی شدند. Glance از سازگاری معکوس برای انواع دکمههای ترکیبی زیر پشتیبانی میکند:
این دکمههای ترکیبی هر کدام یک نمای قابل کلیک را نمایش میدهند که نشاندهندهی حالت «علامتگذاریشده» است.
var isApplesChecked by remember { mutableStateOf(false) } var isEnabledSwitched by remember { mutableStateOf(false) } var isRadioChecked by remember { mutableIntStateOf(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) } ) } }
همچنین میتوانید ویژگی colors را به CheckBox ، Switch و RadioButton ارائه دهید تا رنگهای آنها را سفارشی کنید:
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) ), )
اجزای اضافی
Glance 1.1.0 شامل انتشار اجزای اضافی است، همانطور که در جدول زیر شرح داده شده است:
| نام | تصویر | لینک مرجع | یادداشتهای تکمیلی |
|---|---|---|---|
| دکمه پر شده | ![]() | کامپوننت | |
| دکمههای طرح کلی | ![]() | کامپوننت | |
| دکمههای آیکون | کامپوننت | اصلی / فرعی / فقط آیکون | |
| نوار عنوان | ![]() | کامپوننت | |
| داربست | داربست و نوار عنوان در یک نسخه آزمایشی قرار دارند. |
برای اطلاعات بیشتر در مورد جزئیات طراحی، به طرحهای اجزای موجود در این کیت طراحی در Figma مراجعه کنید.
برای اطلاعات بیشتر در مورد طرحبندیهای متعارف، به طرحبندیهای ویجت متعارف مراجعه کنید.


