با Android XR، از فضای صفحهنمایش فراتر بروید و برنامههایتان را در دنیای واقعی لنگر کنید. این جلسه به شما آموزش میدهد که چگونه بااستفاده از Jetpack Compose Glimmer و Geospatial API مربوط به ARCore، تجربههای Android XR آگاه از موقعیت جغرافیایی بسازید. با پوشش دادن نحوه دریافت وضعیت زمینمکانی دستگاه با ARCore شروع میکنیم. سپس خواهید دید که چگونه مؤلفههای واسط کاربر حداقلی Glimmer را میتوان ازطریق «سیستم موقعیتیابی بصری» (VPS) به مکانهای دنیای واقعی متصل کرد. اینها را باهم ترکیب میکنیم تا تجربه فضایی ساده و آگاه از مکان بسازیم.
آوانویسی
سلام به همگی، به اولین جلسه شما در دسته هدف Android XR در «نشست توسعهدهندگان Android» خوش آمدید.
آره!
بسیار خوشحالیم که میبینیم بسیاری از شما درحال آشنایی با Android XR هستید.
نام من یاسمین کوینتانا اوجن است و پل هوور و درک بریدی به من ملحق شدهاند و در ادامه گفتگو به ما خواهند پیوست.
موضوع این جلسه کاملاً درباره Android XR است و اینکه چگونه میتوانید با Jetpack Compose Glimmer و ARCore برای Jetpack XR تجربههای دنیای واقعی با لنگر فضایی بسازید.
اما ابتدا، بیایید Android XR را بهطور خلاصه معرفی کنیم.
Android XR پلاتفرم جدیدی است که نحوه تعامل کاربران با برنامه شما را بازتعریف میکند و فراتر از صفحه نمایش و به فضای اطراف آنها میرود.
ما این پلاتفرم را طراحی میکنیم تا تجربههای دیجیتال را مستقیماً به محیط فیزیکی بیاوریم.
خواه این بهمعنای همپوشانیهای قابلمشاهده در یک نگاه باشد که حضور در دنیای واقعی را بهبود میبخشد یا یک محیط فراگیر بینهایت.
این همان بومسازگان باز Android است که سالها است باهم ساختهایم، و اکنون بوم آن به اندازه اتاق بزرگ است و تا جایی که تخیل شما اجازه دهد گسترش مییابد.
ما واقعیت گسترده را بهعنوان طیفی از دستگاهها میبینیم که از افزاردید هوشمند (که تجربههای سبک و افزوده را در عینکهای صوتی و نمایشگردار ممکن میسازد) تا هدستهای فراگیر و عینکهای واقعیت گسترده سیمی (که تمرکز، بهرهوری، و قابلیتهای سرگرمی فراگیر را بههمراه دارند) را شامل میشود.
جدیدترین دستگاه در خانواده Android XR، XREAL AURA است که از امروز برای خرید دردسترس است.
این دستگاه سبک و قدرتمند است و تجربههای واقعیت گسترده را با آشنایی Android ممکن میسازد.
چشمانداز ما برای این پلاتفرم این است که اگر درحالحاضر برای Android توسعه میدهید، برای توسعه برای XR نیز آماده هستید.
بااستفاده از همان مدل برنامه، کتابخانه، و ابزارهایی که با آنها آشنا هستید، میخواهیم ساختن در Android XR را برای شما ساده کنیم.
با تغییرات کم یا بدون تغییر، برنامه سازگار با Android دوبعدی موجود شما روی هدستهای Android XR و عینکهای واقعیت گسترده سیمی کار خواهد کرد.
و برای ایجاد تجربیات واقعیت گسترده فوقالعادهای که کاملاً طبیعی بهنظر برسند، مجموعهای از کتابخانهها را ارائه میدهیم که بهطور ویژه برای پلاتفرم واقعیت گسترده ساخته شدهاند.
توسعهدهندگانی که به ساختن تجربهها در پلاتفرمهای فراگیر دیگر عادت دارند میتوانند با OpenXR و پشتیبانی موتور سهبعدی ما، مانند Unity، Godot، و Unreal، بسازند.
بیایید درباره ساختن با کتابخانههای Android صحبت کنیم.
ما Jetpack XR SDK را ارائه میدهیم که مجموعهای از کتابخانههای Kotlin است و به شما کمک میکند برنامههایتان را به واقعیت گسترده در تجربیات فراگیر و افزوده گسترش دهید.
بیایید نگاهی به کتابخانههای فراگیرمان بیندازیم.
کتابخانههای Jetpack XR ما امسال به نسخه بتا و پایدار رسیدند و اطمینان لازم را برای شروع ساخت تجربههای فراگیر «واقعیت گسترده» به شما میدهند.
لایه ادراک ARCore برای Jetpack XR است.
این کتابخانه اطلاعاتی درباره دنیای واقعی ارائه میدهد، مثلاً سطوح صاف مانند میز کجا قرار دارند و دستهای کاربران در چه موقعیتی قرار دارند.
این سرویس میتواند نقاط را در فضای سهبعدی ردیابی کند و البته درصورت اعطای اجازههای مناسب، این اطلاعات را به برنامهها ارائه دهد.
سپس Jetpack XR SceneCore وجود دارد که یک نمودار صحنه برای قرار دادن محتوای فضایی شما ارائه میدهد.
این کتابخانه قادر به ارائه نهادها در فضای سهبعدی است و رفتارهای فضایی را برای قرار دادن دقیق نمودار صحنه ارائه میدهد.
و Jetpack Compose برای XR ترکیبپذیرهای زیرفضای جدیدی را ارائه میدهد که بهطور خاص برای سهبعدی ساخته شدهاند.
توسعهدهندگان Android که ازقبل با چیدمانهای Compose آشنا هستند، مثلاً ساختن با ردیفها و ستونها، متوجه خواهند شد که چیدمان واسط کاربر فضایی حسی است.
با ایجاد ردیف فضایی، میتوانید چندین پانل فضایی را بهصورت اعلانی در کنار هم بچینید، بدون اینکه لازم باشد موقعیت یا اندازه آنها را بهصورت دستی محاسبه کنید.
بااستفاده از ترکیبپذیرهای زیرفضا مانند پانل فضایی یا مدارگرد، میتوانید بهراحتی مؤلفههای دوبعدی خود را به این فضای سهبعدی جدید گسترش دهید.
و البته، ترکیبپذیرهای زیرفضا میتوانند کارهایی فراتر از نمایش محتوای دوبعدی انجام دهند.
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»، میتوانید از شبیهساز برای تجسم کردن نحوه نمایش میانای کاربری عینک در پسزمینههای مختلف، مثل محیطهای روشن، تاریک، یا شلوغ استفاده کنید.
این بهروزرسانیها تازه ابتدای راه است.
بسیارخوب، نه.
تیمم به من گفت که با این یکی نمیتوانی کسی را بخندانی، اما من همچنان آن را نگه داشتم.
اما اکنون، میخواهم آن را به Paul بسپارم تا درباره Jetpack Compose Glimmer بیشتر به شما بگوید.
آزمایش، بسیار خوب!
باید دکمه بعدی را بزنم.
بسیار خوب، ممنون یاسمین.
بسیار خوب.
بنابراین، همانطور که یاسمین گفت، Jetpack Compose Glimmer واحدهای سازنده پایه را برای توسعه برنامههای سفارشیشده برای عینکهای نمایشگردار ارائه میدهد.
مؤلفههای ما بهترین روالهای مطلوب ساختهشده برای نمایشگرهای شفاف نوری را ادغام میکنند و ما آنها را مستقیماً در میاناهای برنامهسازی کاربردی برای شما ساختهایم تا همه توسعهدهندگان بتوانند تجربههای شفاف نوری زیبا و کاربردی بسازند.
وقتی درحال طراحی و ساخت برنامه برای دستگاههای نوری شفاف مثل این دستگاه هستید، باید چند نکته را بهخاطر داشته باشید.
اول اینکه این نمایشگر شفاف است، یعنی رنگ سیاه ندارد.
وقتی جهان قابلمشاهده است، رنگ سیاه شفاف است.
بنابراین نمیتوانید برای حفظ کنتراست واسط کاربر، نوشتار، و محتوا روی پسزمینههای تیره حساب کنید.
هرچند رنگ سیاه نامرئی است، میتوانید از آن برای پنهان کردن سایر محتوای دیجیتال استفاده کنید.
در چارچوب میانای کاربر Glimmer، یک API عمق داریم که به شما امکان میدهد عناصر میانای کاربر را بهراحتی از یکدیگر جدا کنید و حس سلسلهمراتب را ارائه دهید.
در اینجا میتوانید ببینید که چگونه عمق کارتها در این پشته به آنها کمک میکند تا از یکدیگر جدا بمانند.
دانشمندان بینایی ما نسبتهای کنتراست هدف را برای نوشتار و نمادهایی ارائه کردهاند که در اکثر شرایط نوری قابلمشاهده هستند.
همانطور که یاسمین نشان داد، ما میتوانیم این را بسازیم یا این را در چارچوب ساختهایم تا وقتی رنگهای سطح را سفارشی میکنید، مطمئن باشید که واسط شما برای کاربران خوانا خواهد بود.
این روالهای مطلوب و روالهای مطلوب دیگر را در کتابخانه مؤلفه درحال گسترش خود گنجاندهایم.
اخیراً مؤلفههای جدید زیادی را عرضه کردهایم.
یکی از جدیدترین نسخههای ما مؤلفه ورقزن است که با انتقالهای حرکتی زیبا و اشارههای داخلی ارائه میشود.
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")
}میتوانید همه انواع دکمههای ما را که در اینجا برای ایجاد این کنترل رسانه استفاده شدهاند ببینید.
و اکنون آزمایش کردن میانای کاربر در پسزمینههای مختلف آسان است.
شبیهساز عینک درواقع به شما امکان میدهد عکسهای ۳۶۰ درجه را وارد کنید و در اطراف بچرخید تا بتوانید آن را در پسزمینههای مختلف، پسزمینههای شلوغ، و، میدانید، روشن، تاریک آزمایش کنید.
گروههای دکمه برای استفاده در نمای جزئیات مانند این برای نمایش کنشهای بافتاری عالی هستند.
با تکضرب زدن، میتوانید از انتقالهای عنصر مشترک برای پیمایش به حالت نمایشگر دقیق استفاده کنید، سپس از اشاره برگشت سیستم برای برگشتن به نمای قبلی استفاده کنید.
خیلی خوب است.
علاوهبراین، نشانگر ورودی گفتار و کادرهای گفتگوی هشدار را اضافه کردهایم.
بنابراین، بله، چیزهای جدید زیادی وجود دارد.
اما حالا که برخیاز چیزهای جدید را دیدهایم، بیایید چیزی بسازیم.
علاوهبر استفاده از Glimmer برای ساختن افزاردید هوشمند، میتوانیم از Glimmer برای ساختن تجربههایی برای عینک واقعیت گسترده سیمی استفاده کنیم.
و میخواهیم تجربههایی بسازید که دنیای اطرافتان را با شروع از لنگرهای مبتنی بر مکان در دنیای واقعی تقویت کند.
تصور کنید در شهر جدیدی هستید، شاید برای شرکت در کنفرانس توسعهدهندگان سفر کردهاید، و میخواهید در شهر اطرافتان غذا پیدا کنید.
میتوانید از برنامه پیمایش دلخواهتان بخواهید رستورانهای اطراف و ردهبندی آنها را پیدا کند.
اطلاعات را میتوان مستقیماً روی مکان قرار داد تا زمینه، اطلاعات، و راهنمایی ارائه شود.
در اینجا میتوانید جدیدترین مؤلفه Glimmer ما را با نام «نشانگر نماد» ببینید.
این الگو به شما امکان میدهد عناصر کلیدی را در دنیای فیزیکی برجسته کنید و آنها را با مؤلفههای دیگر Glimmer مثل این کارت جفت کنید.
در این مثال، نقاط جالب را بااستفاده از Google Maps، Places، و Geospatial API حاشیهنویسی میکند.
سلام، درک، بیا به آنها نشان دهیم چطور این را راهاندازی کنند.
بیایید انجامش دهیم.
بسیار خوب.
بسیار خوب.
بنابراین، همانطور که پل قبلاً اشاره کرد، بیایید شروع به ساختن کنیم.
بنابراین، ما درواقع از مستندات توسعهدهنده در developer.android.com/xr استفاده خواهیم کرد و نگاهی به کتابخانه مؤلفه Jetpack Compose Glimmer خواهیم انداخت.
بنابراین میتوانید نمای کلی تصویری از همه مؤلفههای موجود در Glimmer را پیدا کنید.
و بیایید با این بخش از واسط کاربری که Paul قبلاً نشان داد شروع کنیم.
بنابراین از Glimmer UI برای ایجاد نشانگر فضایی و جعبه اطلاعات استفاده میکنیم.
بنابراین، بیایید با شناسایی مؤلفههایی که استفاده خواهیم کرد شروع کنیم.
در سمت راست، نشانگر نمادی را خواهید دید و در سمت چپ، از کارتی استفاده میکنیم که مکان را توصیف میکند.
بنابراین، اگر به Android Studio بروید، درواقع میتوانید این پانل را درست مانند هر مؤلفه Compose دیگری پیشنمایش کنید و تغییرات خود را بهطور همزمان ببینید.
بنابراین همانطور که قبلاً ذکر شد، میتوانید واسط کاربر را در انواع مختلف محیطهای پسزمینه پیشنمایش کنید و مطمئن شوید که کنتراست واسط کاربر شما در انواع مختلف سناریوها، مانند محیطهای تاریک و روشن، کافی است.
اکنون که بوم تنظیم شده است، ردیفی ایجاد میکنیم، نشانگر نمادی را با کمی فاصله در آن قرار میدهیم، و کارتی با چند نمونه نوشتار اضافه میکنیم.
و درواقع، این شما و این هم این ویژگی.
اگر از پیشنمایش دوبعدی راضی هستید، میتوانیم چیزی را در دنیای واقعی علامتگذاری کنیم و این کار را با فضایی کردن واسط کاربر انجام خواهیم داد.
این یعنی آن را بهجای دوبعدی، بهصورت سهبعدی نمایش میدهیم.
بنابراین، رابطهای کاربری فضایی در زیرفضاها قرار دارند که نوعی فضای سهبعدی در مقابل کاربر است.
Subspace {
SpatialPanel {
VideoPlayer()
}
}و بهطور پیشفرض، یک زیرفضا درواقع محتویات خود را در فاصلهای راحت از کاربر قرار میدهد.
بنابراین، قبلاز اینکه به شما نشان دهیم چگونه از Geospatial API استفاده کنید، بیایید ابتدا چیزی را در این نزدیکی قرار دهیم.
بنابراین، فضای فرعی قابلترکیب که قبلاً درباره آن صحبت کردم، یک پارامتر اختیاری دارد که به شما امکان میدهد هدف دنبال کردن را مشخص کنید.
val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}بنابراین برای پیوست کردن چیزی به دنیای واقعی، ابتدا یک لنگر ایجاد میکنید که از ARCore برای Jetpack XR بهدست میآید.
و در این مثال، من درواقع از ویژگی تشخیص رمزینه پاسخسریع استفاده میکنم.
و این به شما امکان میدهد رمزینههای پاسخسریع را بخوانید و ردیابی کنید، بنابراین محتوای شما میتواند آن رمزینه پاسخسریع را در فضا دنبال کند و ما واسط کاربریای را که قبلاً دیدیم پیوست خواهیم کرد.
بسیارخوب.
بنابراین، به شما نشان دادم که چگونه محتوای دیجیتال را در دنیای واقعی اطرافتان قرار دهید.
و بیایید به مثال پل برگردیم.
من خودم اهل هلند هستم.
من واقعاً با مانتین ویو آشنا نیستم.
بنابراین، بعداز این رویداد، میخواهم به شما کمک کنم برنامهای بسازید که به شما کمک کند چند کافه جالب پیدا کنید.
پس بیایید ببینیم چگونه میتوانیم به کاربرانمان کمک کنیم تا با Geospatial API که اکنون در ARCore برای 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 Maps» بخواهیم چند کافه عالی در نزدیکی کاربر پیدا کند.
بنابراین، اول از همه، کاربر کجا است؟
از 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 یا زمانی که سیستم مکانیابی بصری تطابقهایی در مکان کاربر پیدا میکند، سطح دقت میتواند بهبود یابد.
و منتظر ماندن برای سطح دقت بالا مهم است تا مطمئن شویم که تجربههای مکانی در مکان درست لنگر انداختهاند و نتایج از منطقه نزدیک کاربر هستند.
سپس، درنهایت آمادهایم تا بااستفاده از مقادیر مکان از Geospatial API، جستجو را با Places 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 برای پُرسمان مکانهای اطراف موقعیت کاربر که قبلاً بهدست آوردهایم استفاده میکنیم و نتایج را در ۱۰۰ متری پیدا میکنیم.
شناسه مکان، نام نمایشی، ردهبندی، و البته موقعیت مکانی آن را دریافت خواهیم کرد.
و درنهایت، جستجو را با پارامترهای مشخصشده ازجمله فیلتر نوع مکان انجام خواهیم داد.
خب، این از دادهها، حالا بیایید به واسط کاربر برگردیم.
بنابراین، باید بفهمیم که چگونه نشانگر و جعبه اطلاعات خود را از قبل قرار دهیم، و برای این کار، از لنگرهای زمینمکانی استفاده خواهیم کرد.
بنابراین، به کد برمیگردیم، یکبار دیگر، بااستفاده از جلسه XR به 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()
)
}بنابراین، در این مثال، ارتفاع را ۳ متر بالاتر از عوارض زمینی در آن مختصات مشخص کردهایم، اما میتوانید به پشتبامهای پشتیبانیشده نیز متصل شوید، به این معنی که مقدار ارتفاع نسبت به پشتبام ساختمان در آن مکان تعیین میشود.
بنابراین، میتوانید لنگر را بااستفاده از کواترنیون نیز بچرخانید که مقادیر چرخشی لنگر را مشخص میکند.
اما در این مثال درواقع از پیشفرضها استفاده خواهیم کرد زیرا میخواهیم واسط کاربر را بچرخانیم تا روبهروی کاربر قرار گیرد.
سپس، واسط کاربری 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 برای Jetpack XR و Jetpack Compose Glimmer.
ما مشتاقیم ببینیم Android XR چه ویژگیهای جدیدی برای عینکهای واقعیت گسترده سیمی بههمراه خواهد داشت.
توسعهدهندگان درحالحاضر برای Android XR میسازند و امیدواریم کار خلاقانه شما را در «فروشگاه Google Play» ببینیم.
برای کمک به شما در شروع کار، لطفاً مستندات توسعهدهنده ما را بررسی کنید، از آزمایشهای XR ما الهام بگیرید، و با codelabs وارد آن شوید.
ما جلسات، نسخههای نمایشی، و کارگاههای آموزشی عالی زیادی در زمینه واقعیت گسترده برای همه شما برنامهریزی کردهایم.
پس لطفاً با ما همراه باشید و درباره ساختن برای Android XR در تجربههای فراگیر و افزوده بیشتر بدانید.
ازطرف تیم Android XR، از همه شما بهخاطر حضور در اینجا بسیار سپاسگزاریم و امیدواریم از ادامه وقتتان در «نشست توسعهدهندگان Android» لذت ببرید.
پس، متشکرم.
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")
}