تجاوز حدود الشاشة وثبِّت تطبيقاتك في العالم الحقيقي باستخدام Android XR. توضّح هذه الجلسة كيفية إنشاء تجارب Android XR تراعي الموقع الجغرافي المكاني باستخدام Jetpack Compose Glimmer وGeospatial API من ARCore. سنبدأ بشرح كيفية الحصول على الوضعية الجغرافية المكانية للجهاز باستخدام ARCore. بعد ذلك، ستتعرّف على كيفية تثبيت مكوّنات واجهة المستخدم البسيطة في Glimmer في مواقع جغرافية حقيقية من خلال "نظام تحديد الموقع المرئي" (VPS). سنجمع بين هذه الميزات لإنشاء تجربة مكانية بسيطة تراعي الموقع الجغرافي.
النص
مرحبًا بكم في الجلسة الأولى من مسار Android XR في مؤتمر Android Developer Summit.
أجل!
يسرّنا اهتمام الكثير منكم بالتعرّف على Android XR.
اسمي "ياسمين كوينتانا إيفجن"، وينضم إليّ "بول هوفر" و"ديريك برايدي"، وسينضمان إلينا مع استمرار المحادثة.
موضوع هذه الجلسة هو Android XR، وكيفية إنشاء تجارب واقعية مرتبطة بالمكان باستخدام Jetpack Compose Glimmer وARCore for Jetpack XR.
لكن أولاً، لنتعرّف سريعًا على Android XR.
Android XR هو نظام أساسي جديد يعيد تعريف كيفية تفاعل المستخدمين مع تطبيقك، متجاوزًا الشاشة إلى المساحة المحيطة بهم.
نصمّم المنصة لدمج التجارب الرقمية مباشرةً في البيئة المادية.
سواء كان ذلك يعني تراكبات سريعة تعزّز التواجد في العالم الحقيقي أو بيئة غامرة لا حصر لها.
إنّها منظومة Android المتكاملة المفتوحة نفسها التي عملنا على تطويرها معًا لسنوات، والآن أصبحت لوحة الرسم بحجم الغرفة وباتت تتسع لكل إبداعاتك الفنية.
نرى أنّ الواقع الممتد يشمل مجموعة من الأجهزة التي تتراوح بين النظارات الذكية، التي تتيح تجارب خفيفة الوزن ومعزّزة على النظارات الصوتية والنظارات بشاشة عرض، وسمّاعات الرأس الغامرة والنظارات السلكية التي تعمل بنظام الواقع الممتد، والتي توفّر إمكانات التركيز والإنتاجية والترفيه الغامر.
XREAL AURA هو أحدث جهاز في مجموعة Android XR، وهو متاح للشراء اليوم.
يتميّز هذا الجهاز بخفة وزنه وقوته، ما يتيح تجارب الواقع الممتد مع سهولة استخدام Android.
رؤيتنا للمنصة هي أنّه إذا كنت تطوّر تطبيقات لنظام Android، فأنت جاهز لتطوير تطبيقات لنظام XR.
نريد أن نسهّل عليك عملية إنشاء التطبيقات على Android XR باستخدام نموذج التطبيق والمكتبة والأدوات نفسها التي تعرفها.
سيعمل تطبيقك الحالي المتوافق مع Android ثنائي الأبعاد على سمّاعات رأس بنظام الواقع الممتد ونظّارات بنظام الواقع الممتد السلكية التي تعمل بنظام Android XR، بدون إجراء أي تعديلات أو بإجراء تعديلات بسيطة.
ولإنشاء تجارب رائعة في الواقع الممتد تبدو مألوفة، نقدّم مجموعة من المكتبات المصمّمة خصيصًا لمنصة الواقع الممتد.
بالنسبة إلى المطوّرين الذين اعتادوا على إنشاء تجارب على منصات غامرة أخرى، يمكنكم استخدام OpenXR ومحركاتنا الثلاثية الأبعاد، مثل Unity وGodot وUnreal.
لنتحدّث عن إنشاء التطبيقات باستخدام مكتبات Android.
نوفّر حزمة تطوير البرامج (SDK) لـ Jetpack XR، وهي مجموعة من مكتبات Kotlin التي تساعدك في توسيع نطاق تطبيقاتك لتشمل XR من خلال تجارب غامرة ومعزَّزة.
لنلقِ نظرة على مكتباتنا الغامرة.
أطلقنا هذا العام الإصدار التجريبي والإصدار الثابت من مكتبات Jetpack XR، ما يمنحك الثقة التي تحتاجها لبدء إنشاء تجارب الواقع الممتد الغامرة.
طبقة الإدراك هي ARCore for Jetpack XR.
توفّر هذه المكتبة معلومات عن العالم الحقيقي، مثل مكان الأسطح المستوية مثل الطاولة، وكيفية وضع أيدي المستخدمين.
ويمكنه تتبُّع النقاط في المساحة الثلاثية الأبعاد، ويوفّر هذه المعلومات للتطبيقات عند منحه الأذونات المناسبة بالطبع.
بعد ذلك، هناك Jetpack XR SceneCore، الذي يوفّر رسمًا بيانيًا للمشهد من أجل وضع المحتوى المكاني.
تستطيع هذه المكتبة عرض الكيانات في مساحة ثلاثية الأبعاد، وتوفّر سلوكيات مكانية لوضع الرسم البياني للمشهد بدقة.
وتوفّر حزمة Jetpack Compose للواقع الممتد دوال مركّبة جديدة للمساحات الفرعية تم إنشاؤها خصيصًا للمحتوى الثلاثي الأبعاد.
بالنسبة إلى مطوّري برامج Android الذين لديهم دراية بتنسيقات Compose، مثل الإنشاء باستخدام الصفوف والأعمدة، سيكون تصميم واجهة المستخدم المكانية أمرًا بديهيًا.
من خلال إنشاء صف مكاني، يمكنك تخطيط لوحات مكانية متعددة جنبًا إلى جنب بشكل تعريفي بدون الحاجة إلى حساب موضعها أو حجمها يدويًا.
باستخدام الدوال المركّبة للمساحة الفرعية، مثل اللوحة المكانية أو المدار، يمكنك بسهولة توسيع نطاق المكوّنات الثنائية الأبعاد إلى هذه المساحة الثلاثية الأبعاد الجديدة.
بالطبع، يمكن للدوال المركّبة في Subspace تنفيذ مهام أكثر من مجرد عرض المحتوى الثنائي الأبعاد.
يتيح Compose for XR استخدام الفيديوهات المكانية والنماذج الثلاثية الأبعاد من خلال السطح الخارجي المكاني ونموذج glTF المكاني.
لنتحدّث الآن عن التطبيقات المعزّزة.
باستخدام مكتبة Jetpack Projected، يمكنك تحسين تطبيقك الحالي على الأجهزة الجوّالة للاستفادة من أجهزة النظارات الذكية، مثل أدوات الاستشعار والشاشة.
أخيرًا، نقدّم Jetpack Compose Glimmer، وهي مجموعة أدوات واجهة مستخدم لإنشاء تجارب Android XR محسّنة للنظارات.
تتكوّن Jetpack Compose Glimmer من أنماط ومكوّنات جاهزة للاستخدام لإنشاء تجارب الواقع الممتد.
أطلقنا Glimmer العام الماضي وواصلنا توسيع نطاق إمكاناته، بما في ذلك مهارة مستندة إلى الذكاء الاصطناعي الوكيل لمساعدتك في إنشاء تطبيقات لنظارات بشاشة عرض باستخدام Glimmer.
android skills add display-glasses-with-jetpack-compose-glimmerمنذ إطلاق هذه الميزة، كنا نستمع إلى ملاحظاتكم.
وصلتنا ملاحظات من المستخدمين تطلب منّا توسيع نطاق Jetpack Compose Glimmer ليشمل أجهزة أخرى غير النظارات الذكية.
يسرّنا الإعلان عن أنّنا أجرينا تغييرات لتقديم دعم أفضل لتجاربكم المرتبطة بالمكان من خلال Glimmer، وسنتناول ذلك بالتفصيل لاحقًا في هذه الجلسة.
بدأ عملنا على تحسين Glimmer من خلال إنشاء مساحة عرض جديدة لعرض المحتوى على مجموعة متنوعة من أشكال أجهزة الواقع الممتد، بدءًا من الشاشات وصولاً إلى نظارات بنظام الواقع الممتد السلكية.
توفّر إضافة هذه المساحة الجديدة مرونة أكبر في كيفية تخصيص واجهة المستخدم.
ولزيادة تميّز العلامة التجارية لتطبيقاتك، أضفنا ألوانًا مخصّصة إلى مكوّنات Glimmer.
ويمكنك استخدامها للتعبير عن أسلوب علامتك التجارية في تطبيقات XR.
توفّر مكتبة Jetpack Compose Glimmer دوال مساعِدة تحوّل الألوان المستهدَفة وألوان العلامة التجارية إلى ألوان آمنة للنظارات.
يهدف ذلك إلى ضمان تحسين مستوى الرؤية على شاشات العرض الشفافة.
لنرَ الآن كيف يتم ذلك.
نريد تغيير لون الزر الذي يتم التركيز عليه في تطبيق النظارات هذا، وسأختار أحد ألواني المفضّلة الرائعة.
val brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)
Column(…) {
LeadingImageCard(
focusable = false,
…
) {
…
}
ButtonGroup(...) {
Button(
onClick = {},
leadingIcon = { … },
focusedColor = focusedColor,
) { Text("Add to cart") }
/* Rest of the buttons */
}
}لاحظ أنه عند إضافة اللون إلى الرمز، تقوم الدوال المساعدة في Glimmer بضبطه على لون آمن للنظارات لتحسين الرؤية.
تم إنشاء كل ذلك ضمن مكتبة Jetpack Compose Glimmer، ما يضمن لك إنشاء تجارب تبدو رائعة في بيئات مختلفة.
في استوديو Android، يمكنك استخدام المحاكي لتصوّر شكل واجهة المستخدم في النظّارة الذكية على خلفيات مختلفة، مثل البيئات الساطعة أو المظلمة أو المزدحمة.
هذه التعديلات ليست سوى البداية.
حسنًا، لا.
أخبرني فريقي أنّ هذه النكتة لن تضحكك، ولكنني أصررت على قولها.
والآن، سأترككم مع "بول" ليخبركم بالمزيد عن Jetpack Compose Glimmer.
أجرّب الميكروفون، حسنًا
عليّ النقر على زر "التالي".
حسنًا، شكرًا لك يا ياسمين.
حسنًا.
كما ذكرت ياسمين، يوفّر Jetpack Compose Glimmer اللبنات الأساسية لتطوير تطبيقات مخصّصة للنظارات بشاشة عرض.
تدمج مكوّناتنا أفضل الممارسات المصمّمة لشاشات العرض الشفافة، وقد دمجناها مباشرةً في واجهات برمجة التطبيقات من أجلكم، ما يتيح لكم جميعًا إنشاء تجارب عرض شفافة جميلة وعملية.
عند تصميم وإنشاء تطبيقات للأجهزة الشفافة البصرية مثل هذا الجهاز، عليك مراعاة بعض الأمور.
أولاً، إنّها شاشة شفافة، ما يعني أنّه لا يوجد لون أسود.
عندما يكون العالم مرئيًا، يكون اللون الأسود شفافًا.
لذلك لا يمكنك الاعتماد على الخلفيات الداكنة للحفاظ على التباين في واجهة المستخدم والنص والمحتوى.
على الرغم من أنّ اللون الأسود غير مرئي، يمكنك استخدامه لحجب محتوى رقمي آخر.
في إطار عمل واجهة المستخدم Glimmer، لدينا واجهة برمجة تطبيقات للعمق تتيح لك فصل عناصر في واجهة المستخدم عن بعضها بسهولة وتوفير شعور بالتسلسل الهرمي.
هنا، يمكنك أن ترى كيف يساعد العمق الموجود على البطاقات في هذه المجموعة على بقائها منفصلة عن بعضها البعض.
وقد قدّم علماء الرؤية لدينا نِسب تباين مستهدَفة للنصوص والرموز التي تظهر في معظم ظروف الإضاءة.
كما أوضحت ياسمين، يمكننا إنشاء هذا أو قمنا ببناء هذا في إطار العمل بحيث عندما تقوم بتخصيص ألوان السطح، يمكنك أن تكون واثقًا من أن واجهتك ستكون مقروءة للمستخدمين.
لقد أضفنا أفضل الممارسات هذه وغيرها إلى مكتبة المكوّنات المتزايدة لدينا.
لقد أطلقنا الكثير من المكوّنات الجديدة مؤخرًا.
من أحدث الإضافات التي قدّمناها هو مكوّن التنقّل بين الصفحات الذي يتضمّن حركات انتقالية وإيماءات سلسة.
val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}إذا كنت على دراية بميزة التنقّل الأفقي بين الصفحات في Compose، ستكون هذه الميزة مألوفة لك.
وقدّمنا أيضًا أربعة أنواع جديدة من البطاقات المصمّمة للتكامل بسلاسة مع أجهزة التنقّل بين الصفحات والمجموعات وغيرها من واجهات مستخدم Glimmer.
تعرض بطاقات الصور الرئيسية وبطاقات الصور اللاحقة النصوص والصور بجانب بعضها البعض.
لذلك استخدم متغيرات البطاقة هذه عندما يكون لديك قدر متساوٍ من المعلومات النصية والمرئية.
لقد فصلنا بطاقة الصورة إلى صيغة بطاقة خاصة بها.
من الأفضل استخدام هذا التنسيق عندما تكون لديك صورة كبيرة مع سطر واحد من النص أو الشرح، مثل أداة اختيار الفيديو هذه.
يضمّ خيار بطاقة الإجراء زرًا واحدًا في البطاقة.
استخدِم هذا الخيار عندما تريد أن يعرف المستخدمون بالضبط ما سيحدث عند تفعيل البطاقة، كما هو الحال في أداة اختيار الوجهة هذه.
تسمح لك مجموعات الأزرار بتجميع الكثير من الأزرار في مساحة صغيرة.
ButtonGroup {
Button(onClick = {}) { Text("Button 1") }
Button(onClick = {}) { Text("Button 2") }
Button(onClick = {}) { Text("Button 3") }
Button(onClick = {}) { Text("Button 4") }
Button(onClick = {}) { Text("Button 5") }
}باستخدام هذا الرمز البسيط هنا، يمكنك الحصول على هذه الانتقالات الجميلة وسلوكيات الانتقال والستائر التي تخفي الحواف، وتظهر فقط عند الحاجة، والإدخال الذي يتم توجيهه تلقائيًا من النظارات إلى عنصر التحكم.
يمكن أن تحتوي مجموعات الأزرار أيضًا على أزرار الرموز وأزرار الإيقاف/التفعيل الجديدة.
var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}يمكنك الاطّلاع على جميع أنواع الأزرار التي نستخدمها هنا لإنشاء أدوات التحكّم في الوسائط هذه.
وأصبح من السهل الآن اختبار واجهة المستخدم على خلفيات مختلفة.
يتيح لك محاكي النظارات في الواقع وضع صور بزاوية 360 درجة ويتيح لك التحريك حتى تتمكن من اختبارها على خلفيات مختلفة، وخلفيات مزدحمة، وخلفيات فاتحة وداكنة.
تُعدّ مجموعات الأزرار رائعة للاستخدام في عرض التفاصيل مثل هذا لعرض الإجراءات المستندة إلى السياق.
عند النقر، يمكنك استخدام انتقالات العناصر المشترَكة للانتقال إلى حالة عارض تفصيلية، ثم استخدام إيماءة الرجوع في النظام للرجوع إلى العرض السابق.
هذا رائع.
بالإضافة إلى ذلك، أضفنا مؤشرًا للإدخال الصوتي ومربّعات حوار للتنبيهات.
لذا، نعم، هناك الكثير من الميزات الجديدة.
بعد أن اطّلعنا على بعض الميزات الجديدة، لننشئ شيئًا ما.
بالإضافة إلى استخدام Glimmer لتصميم النظارات الذكية، يمكننا استخدامه لإنشاء تجارب لنظارات بنظام الواقع الممتد السلكية.
ونريد منك إنشاء تجارب تعزّز العالم من حولك، بدءًا من نقاط الارتكاز المستندة إلى الموقع الجغرافي في العالم الواقعي.
لنفترض أنّك في مدينة جديدة، ربما تسافر لحضور مؤتمر للمطوّرين، وتريد العثور على بعض الطعام في المدينة من حولك.
يمكنك أن تطلب من تطبيق التنقّل المفضّل لديك العثور على المطاعم القريبة وتقييماتها.
ويمكن عرض المعلومات مباشرةً على الموقع الجغرافي، ما يوفّر السياق والمعلومات والإرشادات.
يمكنك هنا الاطّلاع على أحدث مكوّن Glimmer يُسمى "علامة الرمز".
تتيح لك هذه الميزة إبراز العناصر الرئيسية في العالم الواقعي وربطها بمكوّنات Glimmer الأخرى، مثل هذه البطاقة.
في هذا المثال، يضيف تعليقات توضيحية إلى نقاط الاهتمام باستخدام واجهات برمجة التطبيقات Google Maps وPlaces وGeospatial.
مرحبًا "ديريك"، لنوضّح لهم كيفية إعداد هذه الميزة.
لنبدأ.
حسنًا.
حسنًا.
لذا، كما ذكر "بول" سابقًا، لنبدأ في إنشاء التطبيق.
لذا، سنستخدم مستندات المطوّرين على developer.android.com/xr، وسنلقي نظرة على مكتبة مكوّنات Jetpack Compose Glimmer.
لذلك ستتمكن من العثور على نظرة عامة مرئية لجميع المكونات المتوفرة في Glimmer.
لنبدأ بجزء واجهة المستخدم الذي عرضه "بول" سابقًا.
لذا، سنستخدم واجهة مستخدم Glimmer لإنشاء مؤشر مكاني ومربّع معلومات.
لذلك، لنبدأ بتحديد المكوّنات التي سنستخدمها.
على اليمين، سيظهر رمز علامة، وعلى اليسار، سنستخدم بطاقة تصف المكان.
لذا، إذا انتقلت إلى استوديو Android، ستتمكّن من معاينة هذه اللوحة تمامًا كما تفعل مع أي مكوّن آخر في Compose، ويمكنك الاطّلاع على التغييرات في الوقت الفعلي.
كما ذكرنا سابقًا، يمكنك معاينة واجهة المستخدم في جميع أنواع بيئات الخلفية المختلفة والتأكّد من أنّ تباين واجهة المستخدم كافٍ في أنواع متعددة من السيناريوهات، مثل البيئات المظلمة والفاتحة.
والآن بعد أن تم إعداد اللوحة، سننشئ صفًا ونضع فيه علامة رمز مع بعض المسافات وبطاقة تحتوي على بعض النصوص النموذجية.
وهذا كل ما في الأمر.
إذا كنت راضيًا عن المعاينة الثنائية الأبعاد، يمكننا البدء في وضع علامة على شيء ما في العالم الحقيقي، وسنفعل ذلك من خلال تحويل واجهة المستخدم إلى واجهة مكانية.
هذا يعني أنّنا سنعرضه بشكل ثلاثي الأبعاد بدلاً من ثنائي الأبعاد.
لذلك، يتم تضمين واجهات المستخدم المكانية في مساحات فرعية، وهي مساحة ثلاثية الأبعاد أمام المستخدم.
Subspace {
SpatialPanel {
VideoPlayer()
}
}وبشكل تلقائي، يعرض الفضاء الفرعي محتواه على مسافة مريحة من المستخدم.
لذا، قبل أن نوضّح لك كيفية استخدام Geospatial API، لنضع شيئًا قريبًا أولاً.
لذلك، تحتوي الدالة المركّبة للمساحة الفرعية التي تحدثتُ عنها سابقًا على مَعلمة اختيارية تتيح لك تحديد هدف المتابعة.
val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}لإرفاق عنصر بالعالم الحقيقي، عليك أولاً إنشاء نقطة ارتساء من خلال ARCore for Jetpack XR.
في هذا المثال، أستخدم ميزة التعرّف على رمز الاستجابة السريعة.
سيسمح لك ذلك بقراءة رموز الاستجابة السريعة وتتبُّعها، لكي يتبع المحتوى رمز الاستجابة السريعة في المساحة، وسنرفق واجهة المستخدم التي رأيناها سابقًا.
حسنًا
لقد شرحتُ لكم كيفية وضع محتوى رقمي في العالم الحقيقي بالقرب منكم.
لنعد إلى مثال "بول".
أنا شخصيًا من هولندا.
لستُ على دراية كافية بمدينة ماونتن فيو.
لذا، بعد هذا الحدث، أريد مساعدتك في إنشاء تطبيق يساعدك في العثور على بعض أماكن القهوة الممتعة.
لنتعرّف على كيفية مساعدة المستخدمين في العثور على بعضها باستخدام Geospatial API المتوفّرة الآن في ARCore for Jetpack XR.
لذلك، أصبحت Geospatial API التي تم إطلاقها في الأصل على الهواتف الذكية متاحة الآن على Android XR أيضًا.
وتستخدم هذه الميزة بيانات من ميزة "التجوّل الافتراضي" من Google وتدمجها مع قياسات نظام تحديد المواقع العالمي (GPS) لتحديد موقع الجهاز في المناطق المتوافقة.
لذلك، يمكن استخدام Geospatial API على النظارات الذكية لتحديد الموقع الجغرافي للمستخدم واتجاهه بدقة، كما تتيح حالات استخدام الاتجاهات المفصّلة العالية الدقة.
وعلى الأجهزة الغامرة، مثل نظارات بنظام الواقع الممتد السلكية، تتيح لك Geospatial API إنشاء تجارب يتم تحديد موضعها بدقة في العالم الحقيقي.
على سبيل المثال، يمكنك تثبيت محتوى مكاني على المباني أو إنشاء جولات متخصّصة في المدينة.
لنبدأ باستخدام Geospatial API من خلال هذه الخطوات الثلاث.
الخطوة الأولى هي إنشاء مشروع على Google Cloud Platform وضبط المصادقة في تطبيقك.
بعد ذلك، عند ضبط Geospatial API وتفعيلها في تطبيقك، ستطلب من المستخدم الإذن باسترداد موقعه الجغرافي باستخدام الدقة العالية.
وبعد ضبط الجلسة لاستخدام Geospatial API، تكون جاهزًا للاستخدام.
لذا، ستتمكّن من العثور على جميع التفاصيل في مستندات المطوّرين حول Geospatial API على صفحة مطوّري Android XR التي تم تحديثها مؤخرًا.
لنبدأ باستخدام الموقع الجغرافي للمستخدم لطلب Places API من "منصة خرائط Google" للعثور على بعض المقاهي الرائعة بالقرب من المستخدم.
أولاً، أين يتواجد المستخدم؟
سنطلب من Geospatial API الحصول على تحديثات مستمرة حول الموقع الجغرافي للمستخدم.
produceState<AppStatus>(Initializing) {
val geospatial = Geospatial.getInstance(session)
val wait = geospatial.state.onEach {
value = WaitingForGeospatial(it.geospatialTrackingState)
}.first {
it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
}
val accuracyWait = geospatial.state.onEach {
value = WaitingForGeospatialAccuracy(it)
}.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
value = WaitingForPlacesResults
val result = client.findNearby(context, accWait.geospatialPose)
value = Done(result)
}لذلك، سنصل إلى العنصر الجغرافي المكاني من خلال جلسة الواقع الممتد.
بعد ذلك، سننتظر حتى يتم تشغيل Geospatial أثناء تهيئة أجهزة الاستشعار اللازمة والاتصال بواجهة Cloud API.
بعد ذلك، سننتظر حتى نصل إلى مستوى معيّن من الدقة.
وبالتالي، يمكن تحسين مستويات الدقة أثناء ورود قياسات نظام تحديد المواقع العالمي (GPS) أو عندما يعثر نظام تحديد المواقع المرئي على نتائج مطابقة في الموقع الجغرافي للمستخدم.
ومن المهم الانتظار حتى يتم تحقيق مستوى عالٍ من الدقة للتأكّد من أنّ التجارب المستندة إلى الموقع الجغرافي ترتكز على المكان الصحيح وأنّ النتائج مأخوذة من المنطقة المجاورة للمستخدم.
بعد ذلك، نصبح جاهزين أخيرًا لإجراء البحث باستخدام Places API من خلال قيم الموقع الجغرافي من Geospatial API.
val bounds = CircularBounds.newInstance(
LatLng(pose.latitude, pose.longitude),
100.0, // radius, in meters
)
val placeFields = listOf(
Place.Field.ID, Place.Field.DISPLAY_NAME,
Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
SearchNearbyRequest.builder(bounds, placeFields)
.setIncludedTypes(listOf(PlaceTypes.CAFE))
.setMaxResultCount(10)
.build()
).await()لذا، سنستخدم SearchNearbyRequest مع Places API للاستعلام عن الأماكن المحيطة بموقع المستخدم الذي حصلنا عليه من قبل، وسنعثر على النتائج في نطاق 100 متر.
سنحصل على معرّف المكان واسمه المعروض وتقييمه وموقعه الجغرافي بالطبع.
وأخيرًا، سنُجري البحث باستخدام المَعلمات المحدّدة، بما في ذلك فلتر نوع المكان.
هذا كل ما يتعلق بالبيانات، ولنعد إلى واجهة المستخدم.
لذا، سنحتاج إلى معرفة كيفية وضع العلامة ومربّع المعلومات من قبل، ولهذا الغرض، سنستخدم نقاط الارتكاز الجغرافية المكانية.
بالعودة إلى الرمز، سنصل مرة أخرى إلى Geospatial API باستخدام جلسة الواقع الممتد، ثم سننشئ علامة جغرافية مكانية باستخدام خطوط عرض وطول محددة تم الحصول عليها من نتائج البحث سابقًا.
val anchorResult by produceState<AnchorResult?>(null) {
val geospatial = Geospatial.getInstance(session)
value = geospatial.createAnchorOnSurface(
place.location.latitude, place.location.longitude,
surface = GeospatialSurface.TERRAIN,
altitudeAboveSurface = 3.0,
eastUpSouthQuaternion = Quaternion()
)
}في هذا المثال، حدّدنا الارتفاع ليكون 3 أمتار فوق التضاريس عند هذه الإحداثيات، ولكن يمكنك أيضًا ربطها بأسطح المباني المتوافقة، ما يعني أنّه سيتم تحديد قيمة الارتفاع بالنسبة إلى سطح المبنى في ذلك الموقع الجغرافي.
لذا، يمكنك أيضًا تدوير نقطة الارتكاز باستخدام كواتيرنيون، والذي يحدّد قيم دوران نقطة الارتكاز.
لكننا سنستخدم في الواقع الإعدادات التلقائية في هذا المثال لأننا سنجعل واجهة المستخدم تدور لمواجهة المستخدم.
بعد ذلك، سنربط واجهة مستخدم Glimmer السابقة بهذه النقطة المرجعية، ما يمنحك الوحدات الأساسية لتجربة مرتبطة بالمكان.
when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}لذلك، نعتقد أنّ Geospatial API يمكن أن تتيح تجارب رائعة لتحديد الاتجاهات، وسيساعد التصميم باستخدام Glimmer في إنشاء تجارب مستخدم سهلة الفهم ومصمّمة خصيصًا لشاشات العرض الشفافة.
لمزيد من المعلومات حول Geospatial API، يُرجى الانتقال إلى الموقع الإلكتروني developer.android.com/xr الذي تم تعديله مؤخرًا.
والآن، سأترك الكلمة لـ "ياسمين" لإنهاء العرض التقديمي.
في هذه الجلسة، استعرضنا بعض إمكانات Android XR: ARCore for Jetpack XR وJetpack Compose Glimmer.
نحن متحمسون للميزات الجديدة التي سيقدّمها Android XR لنظارات الواقع الممتد السلكية.
بدأ المطوّرون بالفعل في إنشاء تطبيقات لمنصة Android XR، ونأمل أن نرى أعمالك الإبداعية على "متجر Google Play".
لمساعدتك في البدء، يُرجى الاطّلاع على مستندات المطوّرين، واستلهام الأفكار من تجاربنا في مجال الواقع الممتد، والبدء في استخدام الدروس التطبيقية حول الترميز.
لقد خطّطنا لكم جميعًا لتقديم مجموعة كبيرة من الجلسات والعروض التوضيحية وورش العمل الرائعة حول الواقع الممتد.
لذا، يُرجى متابعتنا والتعرّف على كيفية إنشاء تطبيقات لمنصة Android XR تتيح تجارب غامرة ومعزَّزة.
بالنيابة عن فريق Android XR، نشكركم جميعًا على حضوركم، ونأمل أن تستمتعوا ببقية وقتكم هنا في مؤتمر Android Developer Summit.
لذا، شكرًا لك.
android skills add display-glasses-with-jetpack-compose-glimmerval brandColor = Color(0xFFFFAABB)
val focusedColor = ButtonDefaults.focusedColor(brandColor)
Column(…) {
LeadingImageCard(
focusable = false,
…
) {
…
}
ButtonGroup(...) {
Button(
onClick = {},
leadingIcon = { … },
focusedColor = focusedColor,
) { Text("Add to cart") }
/* Rest of the buttons */
}
}val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}ButtonGroup {
Button(onClick = {}) { Text("Button 1") }
Button(onClick = {}) { Text("Button 2") }
Button(onClick = {}) { Text("Button 3") }
Button(onClick = {}) { Text("Button 4") }
Button(onClick = {}) { Text("Button 5") }
}var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}Subspace {
SpatialPanel {
VideoPlayer()
}
}val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}produceState<AppStatus>(Initializing) {
val geospatial = Geospatial.getInstance(session)
val wait = geospatial.state.onEach {
value = WaitingForGeospatial(it.geospatialTrackingState)
}.first {
it.geospatialTrackingState == Geospatial.GeospatialTrackingState.RUNNING
}
val accuracyWait = geospatial.state.onEach {
value = WaitingForGeospatialAccuracy(it)
}.first { it.horizontalAccuracy < horizontalAccuracyRequirement }
value = WaitingForPlacesResults
val result = client.findNearby(context, accWait.geospatialPose)
value = Done(result)
}val bounds = CircularBounds.newInstance(
LatLng(pose.latitude, pose.longitude),
100.0, // radius, in meters
)
val placeFields = listOf(
Place.Field.ID, Place.Field.DISPLAY_NAME,
Place.Field.RATING, Place.Field.LOCATION,
)
return placesClient.searchNearby(
SearchNearbyRequest.builder(bounds, placeFields)
.setIncludedTypes(listOf(PlaceTypes.CAFE))
.setMaxResultCount(10)
.build()
).await()val anchorResult by produceState<AnchorResult?>(null) {
val geospatial = Geospatial.getInstance(session)
value = geospatial.createAnchorOnSurface(
place.location.latitude, place.location.longitude,
surface = GeospatialSurface.TERRAIN,
altitudeAboveSurface = 3.0,
eastUpSouthQuaternion = Quaternion()
)
}when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}