تصف هذه الصفحة كيفية التعامل مع الأحجام وتوفير تجربة مرنة وسريعة الاستجابة باستخدام ميزة "نظرة سريعة" باستخدام مكونات ميزة "نظرة سريعة" الحالية
استخدام Box
وColumn
وRow
تتضمّن ميزة "نظرة سريعة" ثلاثة تنسيقات رئيسية قابلة للإنشاء:
Box
: يضع العناصر فوق عنصر آخر. ويُترجم هذا النص إلىRelativeLayout
.Column
: يضع العناصر بعد بعضها في المحور الرأسي. يترجم إلىLinearLayout
باتجاه عمودي.Row
: يضع العناصر بعد بعضها في المحور الأفقي. يترجم إلىLinearLayout
باتجاه أفقي.
تتوافق ميزة "نظرة سريعة" مع عناصر Scaffold
. يمكنك وضع Column
وRow
Box
عنصر قابل للإنشاء داخل كائن Scaffold
معيّن.
يتيح لك كل عنصر من العناصر القابلة للإنشاء تحديد المحاذاة العمودية والأفقية من محتواه وقيود العرض أو الارتفاع أو الوزن أو المساحة المتروكة باستخدام المعدِّلات. بالإضافة إلى ذلك، يمكن لكل طفل ضبط مفتاح التعديل الخاص به لتغيير المساحة والموضع داخل الأصل.
يوضّح لك المثال التالي كيفية إنشاء 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
بدءًا من الإصدار 12 من نظام التشغيل Android فصاعدًا
على سبيل المثال، عند إضافة عناصر إلى القائمة أو إزالتها منها). المثال التالي
طريقة تحديد itemId
:
items(items = peopleList, key = { person -> person.id }) { person -> Text(person.name) }
تحديد SizeMode
قد تختلف أحجام AppWidget
حسب الجهاز أو اختيار المستخدم أو مشغِّل التطبيقات.
لذلك من المهم توفير تخطيطات مرنة كما هو موضح في قسم توفير
تصميم مرن للتطبيقات المصغّرة. يبسّط تطبيق "نظرة سريعة" هذه العملية باستخدام "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 × 110 | 203 × 112 | 72 × 72 | 203 × 150 |
---|---|---|---|---|
SizeMode.Single |
110 × 110 | 110 × 110 | 110 × 110 | 110 × 110 |
SizeMode.Exact |
105 × 110 | 203 × 112 | 72 × 72 | 203 × 150 |
SizeMode.Responsive |
80 × 100 | 80 × 100 | 80 × 100 | 150 × 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
بالكامل في كل مرة يتغير فيها الحجم. هذا النمط إلى حدوث مشاكل في الأداء وتقفز واجهة المستخدم عندما يكون المحتوى معقدًا. - قد يختلف الحجم المتاح بناءً على تنفيذ مشغّل التطبيقات. على سبيل المثال، إذا لم يقدم المشغل قائمة بالأحجام، فإن الحد الأدنى استخدام الحجم المحتمل.
- في الأجهزة التي تسبق Android 12، قد لا ينجح احتساب المقاس في جميع المواقف المختلفة.
بشكل عام، عليك استخدام هذا الوضع في حال تعذّر استخدام SizeMode.Responsive
.
(أي أنه لا يمكن استخدام مجموعة صغيرة من التخطيطات سريعة الاستجابة).
الوصول إلى الموارد
يمكنك استخدام LocalContext.current
للوصول إلى أي مورد Android، كما هو موضح في
المثال التالي:
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", )
نص الاسم المعرِّف
يتضمّن الإصدار 1.1.0 من Glance واجهة برمجة تطبيقات لضبط أنماط النص. تعيين أنماط النص باستخدام
السمات fontSize
أو fontWeight
أو fontFamily
لفئة TextStyle
يدعم fontFamily
كل خطوط النظام، كما هو موضح في المثال التالي، ولكن
لا تتوفّر الخطوط المخصّصة في التطبيقات:
Text(
style = TextStyle(
fontWeight = FontWeight.Bold,
fontSize = 18.sp,
fontFamily = FontFamily.Monospace
),
text = "Example Text"
)
إضافة أزرار مركبة
تم تقديم الأزرار المركّبة في الإصدار 12 من نظام التشغيل Android. تتوافق ميزة "نظرة سريعة" مع الجهة الخلفية. التوافق مع أنواع الأزرار المركّبة التالية:
يعرض كل من هذه الأزرار المركب عرضًا قابلاً للنقر يمثل "محدد" الولاية.
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" )
عندما تتغير الحالة، يتم تشغيل دالة lambda المقدّمة. يمكنك تخزين الحالة، كما هو موضح في المثال التالي:
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) ), )
المكونات الإضافية
يتضمن الإصدار 1.1.0 من Glance إصدار مكونات إضافية، كما هو موضح في الجدول التالي:
الاسم | صورة | رابط المرجع | ملاحظات إضافية |
---|---|---|---|
زر معبأ | المكوّن | ||
أزرار المخطط | المكوّن | ||
أزرار الرموز | المكوّن | الابتدائي / الثانوي / الرموز فقط | |
شريط العناوين | المكوّن | ||
سقالة | يظهر سقالة وشريط العناوين في نفس العرض التوضيحي. |
لمزيد من المعلومات حول تفاصيل التصميم، راجع تصميمات المكونات في مجموعة أدوات التصميم على Figma.