باستخدام Jetpack Compose لتطبيقات الواقع المعزّز، يمكنك إنشاء واجهة المستخدم المكانية و التنسيق بشكل تعريفي باستخدام مفاهيم Compose المألوفة، مثل الصفوف والأعمدة. يتيح لك ذلك توسيع واجهة مستخدم Android الحالية إلى مساحة ثلاثية الأبعاد أو إنشاء تطبيقات ثلاثية الأبعاد غامرة جديدة تمامًا.
إذا كنت بصدد إضافة ميزة "الواقع المكاني" إلى تطبيق حالي يستند إلى Android Views، تتوفّر لك عدة خيارات تطوير. يمكنك استخدام واجهات برمجة التطبيقات للتشغيل التفاعلي أو استخدام Compose وViews معًا أو العمل مباشرةً مع مكتبة SceneCore. يمكنك الاطّلاع على دليل العمل مع المشاهدات للحصول على مزيد من التفاصيل.
لمحة عن المساحات الفرعية والمكونات المخصّصة للعرض في مساحات ثلاثية الأبعاد
عند كتابة تطبيقك لأجهزة Android XR، من المهم فهم مفاهيم المساحة الفرعية والمكوّنات المكانية.
لمحة عن المساحة الفرعية
عند تطوير تطبيقات لنظام Android XR، ستحتاج إلى إضافة مساحة فرعية إلى تطبيقك أو تنسيقه. المساحة الفرعية هي قسم من المساحة الثلاثية الأبعاد داخل تطبيقك حيث يمكنك وضع محتوى ثلاثي الأبعاد وإنشاء تصاميم ثلاثية الأبعاد وإضافة عمق إلى المحتوى ثنائي الأبعاد. لا يتم عرض المساحات الفرعية إلا عند تفعيل ميزة "الصوت المكاني". في "المساحة الرئيسية" أو على الأجهزة غير المزوّدة بتقنية الواقع المعزّز، يتم تجاهل أي رمز ضمن هذا الفضاء الفرعي.
تتوفّر طريقتان لإنشاء مساحة فرعية:
setSubspaceContent()
: تنشئ هذه الدالة مساحة فرعية على مستوى التطبيق. يمكن استدعاء هذا الإجراء في نشاطك الرئيسي بالطريقة نفسها التي تستخدم بهاsetContent()
. إنّ المساحة الفرعية على مستوى التطبيق غير محدودة من حيث الارتفاع والعرض والعمق، ما يوفر في الأساس مساحة رسم لا نهائية لعرض المحتوى المكاني.Subspace
: يمكن وضع هذا المكوّن القابل للتجميع في أي مكان ضمن التسلسل الهرمي لواجهة مستخدم تطبيقك، ما يتيح لك الحفاظ على تنسيقات واجهة المستخدم ثنائية الأبعاد والمكانية بدون فقدان السياق بين الملفات. يسهّل ذلك مشاركة عناصر، مثل بنية التطبيق الحالية، بين الواقع المعزّز وأشكال الأجهزة الأخرى بدون الحاجة إلى رفع الحالة من خلال شجرة واجهة المستخدم بالكامل أو إعادة تصميم تطبيقك.
لمزيد من المعلومات، يُرجى الاطّلاع على إضافة مساحة فرعية إلى تطبيقك.
لمحة عن المكونات المكانية
العناصر القابلة للتجميع في مساحة فرعية: لا يمكن عرض هذه العناصر إلا في مساحة فرعية.
يجب وضعها بين Subspace
أو setSubspaceContent
قبل
وضعها في تنسيق ثنائي الأبعاد. يتيح لك SubspaceModifier
إضافة
سمات مثل العمق والإزاحة والموضع إلى العناصر القابلة للتجميع في مساحة فرعية.
لا تتطلّب المكوّنات الأخرى التي تمّ وضعها في المكان استدعاؤها داخل مساحة فرعية. وهي تتكون من عناصر ثنائية الأبعاد تقليدية ملفوفة داخل حاوية مكانية. يمكن استخدام هذه العناصر ضمن التنسيقات ثنائية أو ثلاثية الأبعاد إذا تم تحديدها لكلا التنسيقَين. عندما لا يكون وضع "العرض المكاني" مفعّلاً، سيتم تجاهل ميزاته المكانية وسيتم الرجوع إلى نظيراتها ثنائية الأبعاد.
إنشاء لوحة مكانية
SpatialPanel
هو مساحة فرعية قابلة للتجميع تتيح لك عرض
محتوى التطبيق. على سبيل المثال، يمكنك عرض تشغيل الفيديو أو الصور الثابتة أو أي
محتوى آخر في لوحة مكانية.
يمكنك استخدام SubspaceModifier
لتغيير حجم الشاشة المكانية وسلوكها وموضعها، كما هو موضّح في المثال التالي.
Subspace {
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
.movable()
.resizable()
) {
SpatialPanelContent()
}
}
// 2D content placed within the spatial panel
@Composable
fun SpatialPanelContent(){
Box(
Modifier
.background(color = Color.Black)
.height(500.dp)
.width(500.dp),
contentAlignment = Alignment.Center
) {
Text(
text = "Spatial Panel",
color = Color.White,
fontSize = 25.sp
)
}
}
النقاط الرئيسية حول الرمز
- بما أنّ واجهات برمجة تطبيقات
SpatialPanel
هي عناصر قابلة للتجميع في مساحة فرعية، يجب طلبها داخلSubspace
أوsetSubspaceContent
. يؤدي استدعاءها خارج مساحة فرعية إلى طرح استثناء. - اسمح للمستخدم بتغيير حجم اللوحة أو نقلها عن طريق إضافة المُعدِّلات
movable
أوresizable
. - اطّلِع على إرشادات تصميم اللوحة المكانية للحصول على تفاصيل عن الحجم والموضع. يمكنك الاطّلاع على المستندات المرجعية للحصول على مزيد من التفاصيل حول تنفيذ الرمز.
إنشاء مدار
المسار هو مكوّن لواجهة مستخدِم مكانية. تم تصميمه ليتم إرفاقه بمَعلمة لوحة مكانية أو تنسيق أو كيان آخر ملائم. يحتوي العنصر المداري عادةً على عناصر تنقّل وإجراءات سياقية مرتبطة بالكيان الذي يتم تثبيته عليه. على سبيل المثال، إذا أنشأت لوحة مكانية لعرض محتوى فيديو، يمكنك إضافة عناصر التحكّم في تشغيل الفيديو داخل مسار مداري.
كما هو موضّح في المثال التالي، يمكنك استدعاء عنصر دوار داخل التنسيق ثنائي الأبعاد في علامة
SpatialPanel
لتغليف عناصر التحكّم الخاصة بالمستخدم، مثل عناصر التنقّل. يؤدي ذلك إلى استخراجها
من التنسيق ثنائي الأبعاد وإرفاقها باللوحة المكانية وفقًا لإعداداتك.
setContent {
Subspace {
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
.movable()
.resizable()
) {
SpatialPanelContent()
OrbiterExample()
}
}
}
//2D content inside Orbiter
@Composable
fun OrbiterExample() {
Orbiter(
position = OrbiterEdge.Bottom,
offset = 96.dp,
alignment = Alignment.CenterHorizontally
) {
Surface(Modifier.clip(CircleShape)) {
Row(
Modifier
.background(color = Color.Black)
.height(100.dp)
.width(600.dp),
horizontalArrangement = Arrangement.Center,
verticalAlignment = Alignment.CenterVertically
) {
Text(
text = "Orbiter",
color = Color.White,
fontSize = 50.sp
)
}
}
}
}
النقاط الرئيسية حول الرمز
- بما أنّ العناصر الدوّارة هي مكوّنات لواجهة المستخدم المكانية، يمكن إعادة استخدام الرمز البرمجي في تنسيقات ثنائية أو ثلاثية الأبعاد. في التنسيق ثنائي الأبعاد، يعرض تطبيقك المحتوى داخل المدار فقط ويتجاهل المدار نفسه.
- اطّلِع على إرشادات التصميم للحصول على مزيد من المعلومات عن كيفية استخدام الأقمار المدارية وتصميمها.
إضافة عدة لوحات مكانية إلى تنسيق مكاني
يمكنك إنشاء عدة لوحات مكانية ووضعها ضمن تنسيق مكاني
باستخدام SpatialRow
وSpatialColumn
SpatialBox
وSpatialLayoutSpacer
.
يوضّح مثال الرمز البرمجي التالي كيفية إجراء ذلك.
Subspace {
SpatialRow {
SpatialColumn {
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Top Left")
}
SpatialPanel(SubspaceModifier.height(200.dp).width(400.dp)) {
SpatialPanelContent("Middle Left")
}
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Bottom Left")
}
}
SpatialColumn {
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Top Right")
}
SpatialPanel(SubspaceModifier.height(200.dp).width(400.dp)) {
SpatialPanelContent("Middle Right")
}
SpatialPanel(SubspaceModifier.height(250.dp).width(400.dp)) {
SpatialPanelContent("Bottom Right")
}
}
}
}
@Composable
fun SpatialPanelContent(text: String) {
Column(
Modifier
.background(color = Color.Black)
.fillMaxSize(),
horizontalAlignment = Alignment.CenterHorizontally,
verticalArrangement = Arrangement.Center
) {
Text(
text = "Panel",
color = Color.White,
fontSize = 15.sp
)
Text(
text = text,
color = Color.White,
fontSize = 25.sp,
fontWeight = FontWeight.Bold
)
}
}
النقاط الرئيسية حول الرمز
- إنّ
SpatialRow
وSpatialColumn
وSpatialBox
وSpatialLayoutSpacer
كلها عناصر قابلة للتجميع في مساحة فرعية ويجب وضعها داخل مساحة فرعية. - استخدِم
SubspaceModifier
لتخصيص التنسيق. - بالنسبة إلى التنسيقات التي تتضمّن عدة لوحات في صف واحد، ننصحك بضبط شعاع منحنى
بقيمة 825dp باستخدام
SubspaceModifier
لكي تحيط اللوحات بالمستخدم. يمكنك الاطّلاع على إرشادات التصميم لمعرفة التفاصيل.
استخدام حجم لتحديد موضع عنصر ثلاثي الأبعاد في التنسيق
لوضع جسم ثلاثي الأبعاد في التنسيق، ستحتاج إلى استخدام مساحة فرعية قابلة للتجميع تُسمى حجمًا. في ما يلي مثال على كيفية إجراء ذلك.
Subspace {
SpatialPanel(
SubspaceModifier.height(1500.dp).width(1500.dp)
.resizable().movable()
) {
ObjectInAVolume(true)
Box(
Modifier.fillMaxSize(),
contentAlignment = Alignment.Center
) {
Text(
text = "Welcome",
fontSize = 50.sp,
)
}
}
}
}
@Composable
fun ObjectInAVolume(show3DObject: Boolean) {
val xrCoreSession = checkNotNull(LocalSession.current)
val scope = rememberCoroutineScope()
if (show3DObject) {
Subspace {
Volume(
modifier = SubspaceModifier
.offset(volumeXOffset, volumeYOffset, volumeZOffset) //
Relative position
.scale(1.2f) // Scale to 120% of the size
) { parent ->
scope.launch {
// Load your 3D Object here
}
}
}
}
}
النقاط الرئيسية حول الرمز
- اطّلِع على مقالة إضافة نماذج ثلاثية الأبعاد إلى تطبيقك للتعرّف بشكل أفضل على كيفية تحميل المحتوى الثلاثي الأبعاد داخل وحدة تخزين.
إضافة مكونات أخرى لواجهة المستخدم المكانية
يمكن وضع مكوّنات واجهة المستخدم المكانية في أيّ مكان في التسلسل الهرمي لواجهة المستخدم في تطبيقك. يمكن إعادة استخدام هذه العناصر في واجهة المستخدم ثنائية الأبعاد، ولن تكون سماتها المكانية مرئية إلا عند تفعيل الإمكانات المكانية. يتيح لك ذلك إضافة تأثير التمويه إلى القوائم وملفات الحوار والمكونات الأخرى بدون الحاجة إلى كتابة الرمز البرمجي مرتين. اطّلِع على الأمثلة التالية على واجهة المستخدم المكانية لفهم كيفية استخدام هذه العناصر بشكل أفضل.
مكوّن واجهة المستخدم |
عند تفعيل ميزة "الصوت المكاني" |
في بيئة ثنائية الأبعاد |
---|---|---|
|
سيتم دفع اللوحة للخلف قليلاً في العمق z لعرض مربّع حوار مرتفع |
الرجوع إلى العرض الثنائي الأبعاد |
|
سيتم دفع اللوحة للخلف قليلاً في العمق (z) لعرض نافذة منبثقة مرتفعة. |
يعود إلى |
|
يمكن ضبط |
عروض بدون ارتفاع مكاني |
SpatialDialog
هذا مثال على مربّع حوار يفتح بعد تأخير قصير. عند استخدام SpatialDialog
، يظهر مربّع الحوار في عمق z مماثل لعمق اللوحة المكانية، ويتم دفع اللوحة للخلف بمقدار 125dp عند تفعيل ميزة "العرض المكاني". يمكن أيضًا استخدام SpatialDialog
عندما تكون ميزة "العرض المكاني" غير مفعّلة،
وفي هذه الحالة، يعود SpatialDialog
إلى نظيره ثنائي الأبعاد، Dialog
.
@Composable
fun DelayedDialog() {
var showDialog by remember { mutableStateOf(false) }
LaunchedEffect(Unit) {
Handler(Looper.getMainLooper()).postDelayed({
showDialog = true
}, 3000)
}
if (showDialog) {
SpatialDialog (
onDismissRequest = { showDialog = false },
SpatialDialogProperties(
dismissOnBackPress = true)
){
Box(Modifier
.height(150.dp)
.width(150.dp)
) {
Button(onClick = { showDialog = false }) {
Text("OK")
}
}
}
}
}
النقاط الرئيسية حول الرمز
- في ما يلي مثال على
SpatialDialog
. إنّ استخدام الترميزَينSpatialPopUp
وSpatialElevation
متشابه جدًا. اطّلِع على مرجع واجهة برمجة التطبيقات للحصول على مزيد من التفاصيل.
إنشاء لوحات وتنسيقات مخصّصة
لإنشاء لوحات مخصّصة غير متوافقة مع Compose for XR، يمكنك العمل
مباشرةً مع PanelEntities
ورسم المشهد باستخدام واجهات برمجة التطبيقات
SceneCore
.
ربط المدارات بالتصاميم المكانية والكيانات الأخرى
يمكنك تثبيت مسار مداري بأي عنصر تم الإعلان عنه في Compose. ويشمل ذلك
تحديد مدار في تنسيق مكاني لعناصر واجهة المستخدم، مثل SpatialRow
أو
SpatialColumn
أو SpatialBox
. يتم تثبيت العنصر المداري بالعنصر الرئيسي
الأقرب إلى المكان الذي حدّدته له.
يتم تحديد سلوك المدار حسب المكان الذي تحدّده له:
- في تنسيق ثنائي الأبعاد مُغلف في
SpatialPanel
(كما هو موضّح في مقتطف رمز برمجي سابق)، يتم تثبيت العنصر المداري علىSpatialPanel
. - في
Subspace
، يتم تثبيت العنصر المداري بأقرب عنصر رئيسي، وهو التنسيق المكاني الذي تم الإعلان عن العنصر المداري فيه.
يوضّح المثال التالي كيفية تثبيت مدار حول صف مكاني:
Subspace {
SpatialRow {
Orbiter(
position = OrbiterEdge.Top,
offset = EdgeOffset.inner(8.dp),
shape = SpatialRoundedCornerShape(size = CornerSize(50))
) {
Text(
"Hello World!",
style = MaterialTheme.typography.titleLarge,
modifier = Modifier
.background(Color.White)
.padding(16.dp)
)
}
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
) {
Box(
modifier = Modifier
.background(Color.Red)
)
}
SpatialPanel(
SubspaceModifier
.height(824.dp)
.width(1400.dp)
) {
Box(
modifier = Modifier
.background(Color.Blue)
)
}
}
}
النقاط الرئيسية حول الرمز
- عند تحديد مسار مداري خارج تنسيق ثنائي الأبعاد، يتم تثبيت المسار المداري
بأقرب عنصر رئيسي له. في هذه الحالة، يتم تثبيت العنصر المداري في أعلى
SpatialRow
الذي تمّت الإشارة إليه فيه. - تحتوي جميع التنسيقات المكانية، مثل
SpatialRow
وSpatialColumn
وSpatialBox
، على عناصر لا تحتوي على محتوى مرتبطة بها. لذلك، يتم تثبيت مدار في تنسيق مكاني على هذا التنسيق.
انظر أيضًا
- إضافة نماذج ثلاثية الأبعاد إلى تطبيقك
- تطوير واجهة المستخدم للتطبيقات المستندة إلى Android Views
- تطبيق أسلوب Material Design للواقع المعزّز