تتيح الشاشات الكبيرة غير المطوية وحالات الطي الفريدة تجارب مستخدم جديدة على الأجهزة القابلة للطي. لإتاحة إمكانية طي تطبيقك في Jetpack Compose، استخدِم مكتبة Compose Material 3 Adaptive التي توفّر واجهات برمجة تطبيقات لميزات نوافذ الأجهزة القابلة للطي، مثل الطيات والمفصلات وأوضاع الجهاز. عندما يكون تطبيقك متوافقًا مع الأجهزة القابلة للطي، يمكنه تعديل تصميمه لتجنُّب وضع المحتوى المهم في منطقة الطيات أو المفصلات واستخدام الطيات والمفصلات كفواصل طبيعية.
يمكن أن يساعدك معرفة ما إذا كان الجهاز يتيح إعدادات مثل وضعية الجهاز على الطاولة أو وضعية الكتاب في اتّخاذ قرارات بشأن إتاحة تنسيقات مختلفة أو توفير ميزات معيّنة.
معلومات النافذة
في Jetpack Compose، استخدِم الدالة القابلة للإنشاء collectFoldingFeaturesAsState() لمراقبة معلومات طي النافذة.
تجمع collectFoldingFeaturesAsState() ميزات طي النافذة الحالية
من WindowInfoTracker في State من Compose يحتوي على قائمة
بعناصر FoldingFeature.
بما أنّ collectFoldingFeaturesAsState() تعرض State في Compose، تتم إعادة تركيب العناصر القابلة للإنشاء تلقائيًا كلما تغيرت حالة الطي أو الوضعية على الجهاز، بدون الحاجة إلى إدارة دورة الحياة أو جمع البيانات يدويًا:
@Composable
fun FoldAwareScreen() {
val foldingFeatures by collectFoldingFeaturesAsState()
// Access folding features for the current window.
val foldFeature = foldingFeatures.firstOrNull()
if (foldFeature != null) {
// Adapt layout based on the fold feature.
}
}
ميزات الشاشات القابلة للطي
تعرض قائمة عناصر FoldingFeature التي تعرضها الدالة
collectFoldingFeaturesAsState() (وهي نوع فرعي من DisplayFeature)
معلومات عن الشاشات القابلة للطي، بما في ذلك الخصائص التالية:
state: حالة الجهاز عند طيّه،FLATأوHALF_OPENEDorientation: اتجاه الطي أو المفصل،HORIZONTALأوVERTICALocclusionType: ما إذا كان الطي أو المفصلة يخفيان جزءًا من الشاشة،NONEأوFULLisSeparating: ما إذا كان الطي أو المفصل ينشئان مساحتَي عرض منطقيتَين، صحيح أو خطأ
الجهاز القابل للطي الذي HALF_OPENED يعرض دائمًا القيمة isSeparating على أنّها صحيحة
لأنّ الشاشة مقسّمة إلى منطقتَي عرض. بالإضافة إلى ذلك، تكون قيمة isSeparating صحيحة دائمًا على جهاز بشاشتَين عندما يمتد التطبيق على كلتا الشاشتَين.
تمثّل السمة FoldingFeature bounds (الموروثة من DisplayFeature) المستطيل المحيط بميزة قابلة للطي، مثل الطي أو المفصلة.
يمكن استخدام الحدود لتحديد موضع العناصر على الشاشة بالنسبة إلى الميزة:
@Composable
fun FoldFeatureDemo() {
val foldingFeatures by collectFoldingFeaturesAsState()
val foldFeature = foldingFeatures.firstOrNull()
if (foldFeature != null) {
val isSeparating = foldFeature.isSeparating
val occlusionType = foldFeature.occlusionType
val bounds = foldFeature.bounds
// Use bounds and properties to position content.
}
}
وضع الجهاز على سطح مستوٍ
باستخدام المعلومات المضمّنة في العنصر FoldingFeature، يمكن لتطبيقك توفير أوضاع مثل وضع الطاولة، حيث يكون الهاتف موضوعًا على سطح، ويكون المفصلة في وضع أفقي، وتكون الشاشة القابلة للطي مفتوحة جزئيًا.
تتيح وضعية "على الطاولة" للمستخدمين إمكانية تشغيل هواتفهم بدون الحاجة إلى حملها بأيديهم. يُعد وضع الجهاز على سطح مستوٍ مثاليًا لمشاهدة الوسائط والتقاط الصور وإجراء مكالمات الفيديو.
استخدِم FoldingFeature.State وFoldingFeature.Orientation من collectFoldingFeaturesAsState() لتحديد ما إذا كان الجهاز في وضعية سطح الطاولة:
@Composable
fun TabletopContent() {
val foldingFeatures by collectFoldingFeaturesAsState()
val foldFeature = foldingFeatures.firstOrNull()
val isTableTopPosture = foldFeature != null &&
foldFeature.state == FoldingFeature.State.HALF_OPENED &&
foldFeature.orientation == FoldingFeature.Orientation.HORIZONTAL
if (isTableTopPosture) {
// Tabletop layout: separate content and controls across the fold.
} else {
// Standard layout.
}
}
بدلاً من ذلك، يمكنك تحديد ما إذا كانت النافذة في وضع الشاشة المسطحة من خلال التحقّق من السمة Posture التي تعرضها الدالة currentWindowAdaptiveInfoV2():
val adaptiveInfo = currentWindowAdaptiveInfoV2()
val isTabletop = adaptiveInfo.windowPosture.isTabletop
بعد التأكّد من أنّ الجهاز في وضعية سطح الطاولة، عدِّل تخطيط تطبيقك وفقًا لذلك. بالنسبة إلى تطبيقات الوسائط، يعني ذلك عادةً وضع التشغيل فوق الجزء الظاهر من الصفحة مباشرةً، وتحديد موضع عناصر التحكّم والمحتوى التكميلي بعد ذلك مباشرةً لتوفير تجربة مشاهدة أو استماع بدون استخدام اليدين.
أمثلة
تطبيق
MediaPlayerActivity: تعرَّف على كيفية استخدام Media3 Exoplayer وWindowManager لإنشاء مشغّل فيديو متوافق مع الأجهزة القابلة للطي.تحسين تطبيق الكاميرا على الأجهزة القابلة للطي باستخدام Jetpack WindowManager درس تطبيقي حول الترميز: تعرَّف على كيفية تنفيذ وضع "المنضدة" لتطبيقات التصوير. عرض عدسة الكاميرا في النصف العلوي من الشاشة (الجزء المرئي من الصفحة) وعناصر التحكّم في النصف السفلي
وضع الكتاب
من الميزات الفريدة الأخرى في الأجهزة القابلة للطي وضع الكتاب، حيث يتم فتح الجهاز حتى المنتصف ويكون المفصل عموديًا. يُعد وضع الكتاب مناسبًا لقراءة الكتب الإلكترونية. عند استخدام جهاز قابل للطي بشاشة كبيرة في وضع الكتاب، أي مع فتح الجهاز بشكل مسطح مثل كتاب مجلّد، يمكنك الاستفادة من ميزة "وضع الكتاب" التي تتيح لك الاستمتاع بتجربة قراءة شبيهة بالقراءة من كتاب حقيقي.
يمكن استخدامها أيضًا للتصوير إذا أردت التقاط صور بنسبة عرض إلى ارتفاع مختلفة بدون استخدام اليدين.
يمكنك تنفيذ وضعية الكتاب باستخدام التقنيات نفسها المستخدَمة لوضعية سطح الطاولة. تأكَّد من أنّ اتجاه ميزة الطي عمودي بدلاً من أفقي:
@Composable
fun BookContent() {
val foldingFeatures by collectFoldingFeaturesAsState()
val foldFeature = foldingFeatures.firstOrNull()
val isBookPosture = foldFeature != null &&
foldFeature.state == FoldingFeature.State.HALF_OPENED &&
foldFeature.orientation == FoldingFeature.Orientation.VERTICAL
if (isBookPosture) {
// Book posture layout: two-page layout across the vertical fold.
} else {
// Standard single-page layout.
}
}
تغييرات حجم النافذة
يمكن أن تتغيّر مساحة عرض التطبيق نتيجةً لتغيير في إعدادات الجهاز، على سبيل المثال، عند طي الجهاز أو فتحه أو تدويره أو تغيير حجمه في وضع النوافذ المتعددة.
لاسترداد فئة حجم النافذة الحالية والتكيّف مع تغييرات الحجم في Jetpack Compose، استخدِم الدالة المركّبة currentWindowAdaptiveInfoV2() من مكتبة Compose Material 3 Adaptive. تعرض الدالة currentWindowAdaptiveInfoV2()
مثيلاً من WindowAdaptiveInfo يوفّر
WindowSizeClass للنافذة الحالية (مع توفّر نقاط التوقف الكبيرة والكبيرة جدًا تلقائيًا)، بالإضافة إلى
windowPosture للجهاز:
@Composable
fun AdaptiveApp() {
val adaptiveInfo = currentWindowAdaptiveInfoV2()
val windowSizeClass = adaptiveInfo.windowSizeClass
when {
windowSizeClass.isWidthAtLeastBreakpoint(
WIDTH_DP_EXPANDED_LOWER_BOUND
) -> {
// Expanded layout
}
windowSizeClass.isWidthAtLeastBreakpoint(
WIDTH_DP_MEDIUM_LOWER_BOUND
) -> {
// Medium layout
}
else -> {
// Compact layout
}
}
}
راجِع مقالة استخدام فئات حجم النافذة.
مراجع إضافية
لمزيد من المعلومات حول التصميمات المتوافقة مع الأجهزة القابلة للطي، يُرجى الاطّلاع على المراجع التالية:
نماذج
- نموذج WindowManager من Jetpack: مثال على كيفية استخدام مكتبة WindowManager من Jetpack
- Jetcaster : تنفيذ وضعية الجهاز اللوحي باستخدام Compose
اختبارات الرموز
- دَعْم الأجهزة القابلة للطي والمزودة بشاشتين من خلال مكتبة Jetpack WindowManager
- تحسين تطبيق الكاميرا على الأجهزة القابلة للطي باستخدام Jetpack WindowManager