Vượt ra ngoài không gian màn hình và cố định ứng dụng của bạn trong thế giới thực bằng Android XR. Phiên này hướng dẫn bạn cách xây dựng trải nghiệm Android XR nhận biết không gian địa lý bằng Jetpack Compose Glimmer và Geospatial API của ARCore. Chúng ta sẽ bắt đầu bằng cách tìm hiểu cách lấy tư thế không gian địa lý của thiết bị bằng ARCore. Sau đó, bạn sẽ thấy cách các thành phần giao diện người dùng tối giản của Glimmer có thể được liên kết với các vị trí trong thế giới thực thông qua Hệ thống định vị trực quan (VPS). Chúng ta sẽ kết hợp các thành phần này để xây dựng một trải nghiệm không gian đơn giản, nhận biết vị trí.
Bản chép lời
Chào mọi người, chào mừng các bạn đến với phiên đầu tiên về Android XR tại Hội nghị Nhà phát triển Android.
Đúng vậy!
Chúng tôi rất vui khi thấy nhiều người trong số các bạn đang tìm hiểu về Android XR.
Tôi là Yasmine Quintana Evjen, và tôi có mời Paul Hoover và Dereck Bridie tham gia cùng chúng ta trong cuộc trò chuyện này.
Chủ đề của phiên này là về Android XR và cách bạn có thể xây dựng trải nghiệm thực tế, cố định trong không gian bằng Jetpack Compose Glimmer và ARCore cho Jetpack XR.
Nhưng trước tiên, hãy cùng tìm hiểu sơ lược về Android XR.
Android XR là một nền tảng mới giúp định hình lại cách người dùng tương tác với ứng dụng của bạn, vượt ra ngoài màn hình và bước vào không gian xung quanh họ.
Chúng tôi thiết kế nền tảng này để đưa trải nghiệm kỹ thuật số vào thẳng môi trường thực tế.
Đó có thể là lớp phủ nhanh giúp nâng cao sự hiện diện trong thế giới thực hoặc môi trường sống động vô tận.
Đây vẫn là hệ sinh thái Android mở mà chúng ta đã cùng nhau xây dựng trong nhiều năm qua, nhưng giờ đây, không gian sáng tạo đã rộng lớn như căn phòng và bao la như trí tưởng tượng của bạn.
Chúng tôi xem XR là một dải thiết bị, từ kính thông minh (mang đến trải nghiệm tăng cường, gọn nhẹ trên kính có màn hình và âm thanh) cho đến kính thực tế ảo và kính thông minh XR có dây (mang đến khả năng tập trung, năng suất và giải trí sống động).
Thiết bị mới nhất trong dòng Android XR là XREAL AURA, hiện đã có thể mua.
Thiết bị này nhẹ và mạnh mẽ, mang đến trải nghiệm XR quen thuộc của Android.
Tầm nhìn của chúng tôi đối với nền tảng này là nếu bạn đã phát triển ứng dụng cho Android, thì bạn cũng đã sẵn sàng phát triển ứng dụng cho XR.
Chúng tôi muốn giúp bạn dễ dàng xây dựng ứng dụng trên Android XR bằng cách sử dụng cùng một mô hình ứng dụng, thư viện và công cụ mà bạn đã quen thuộc.
Ứng dụng 2D hiện tại tương thích với Android sẽ hoạt động trên thiết bị đeo đầu Android XR và kính thông minh XR có dây mà không cần sửa đổi hoặc chỉ cần sửa đổi một chút.
Để tạo ra những trải nghiệm XR tuyệt vời và quen thuộc, chúng tôi cung cấp một bộ thư viện được xây dựng riêng cho nền tảng XR.
Đối với những nhà phát triển đã quen với việc xây dựng trải nghiệm trên các nền tảng sống động khác, bạn có thể xây dựng bằng OpenXR và dịch vụ hỗ trợ công cụ 3D của chúng tôi, chẳng hạn như Unity, Godot và Unreal.
Hãy cùng tìm hiểu về cách xây dựng bằng thư viện Android.
Chúng tôi cung cấp SDK Jetpack XR, một bộ thư viện Kotlin giúp bạn mở rộng ứng dụng sang XR thông qua trải nghiệm sống động và tăng cường.
Hãy cùng xem các thư viện sống động của chúng tôi.
Năm nay, các thư viện Jetpack XR của chúng tôi đã ra mắt phiên bản thử nghiệm và phiên bản chính thức, giúp bạn tự tin bắt đầu xây dựng trải nghiệm XR sống động.
Lớp nhận thức là ARCore cho Jetpack XR.
Thư viện này cung cấp thông tin về thế giới thực, chẳng hạn như vị trí của các bề mặt phẳng như bàn và vị trí đặt tay của người dùng.
Nó có thể theo dõi các điểm đánh dấu trong không gian 3D và cung cấp thông tin đó cho các ứng dụng khi được cấp quyền phù hợp.
Sau đó là Jetpack XR SceneCore, cung cấp biểu đồ cảnh để đặt nội dung không gian của bạn.
Thư viện này có thể trình bày các thực thể trong không gian 3D, cung cấp các hành vi không gian để đặt biểu đồ cảnh chính xác.
Jetpack Compose cho XR cung cấp các thành phần kết hợp không gian con mới được xây dựng riêng cho 3D.
Những nhà phát triển Android đã quen thuộc với bố cục Compose (chẳng hạn như xây dựng bằng hàng và cột) sẽ thấy việc bố trí giao diện người dùng không gian rất trực quan.
Bằng cách tạo một hàng không gian, bạn có thể bố trí nhiều bảng điều khiển không gian cạnh nhau một cách rõ ràng mà không cần tính toán vị trí hoặc kích thước của chúng theo cách thủ công.
Bằng cách sử dụng các thành phần kết hợp không gian phụ như bảng điều khiển không gian hoặc trình điều khiển, bạn có thể dễ dàng mở rộng các thành phần 2D vào không gian 3D mới này.
Và đương nhiên, các thành phần kết hợp không gian con có thể làm được nhiều việc hơn là chỉ hiển thị nội dung 2D.
Compose cho XR hỗ trợ video không gian cũng như mô hình 3D thông qua bề mặt không gian bên ngoài và mô hình glTF không gian.
Bây giờ, hãy cùng nói về ứng dụng tăng cường.
Với thư viện Jetpack Projected, bạn có thể cải thiện ứng dụng di động hiện có để sử dụng phần cứng của kính thông minh, chẳng hạn như cảm biến và màn hình.
Cuối cùng là Jetpack Compose Glimmer, một bộ công cụ giao diện người dùng để xây dựng trải nghiệm Android XR được tối ưu hoá cho kính.
Jetpack Compose Glimmer bao gồm các kiểu và thành phần có sẵn để xây dựng trải nghiệm XR.
Chúng tôi đã ra mắt Glimmer vào năm ngoái và tiếp tục mở rộng các tính năng, bao gồm cả một kỹ năng tác tử giúp bạn xây dựng ứng dụng cho kính có màn hình bằng Glimmer.
android skills add display-glasses-with-jetpack-compose-glimmerKể từ khi ra mắt, chúng tôi đã lắng nghe ý kiến phản hồi của bạn.
Chúng tôi nhận được ý kiến phản hồi rằng bạn muốn chúng tôi mở rộng Jetpack Compose Glimmer ra ngoài phạm vi kính thông minh.
Chúng tôi rất vui mừng thông báo rằng chúng tôi đã thực hiện các thay đổi để hỗ trợ tốt hơn cho trải nghiệm được neo trong không gian của bạn với Glimmer, chúng tôi sẽ đi sâu vào vấn đề này sau trong bài nói chuyện này.
Công việc tối ưu hoá Glimmer của chúng tôi bắt đầu bằng việc tạo một nền tảng mới để hiển thị trên nhiều kiểu dáng XR, từ màn hình cho đến kính thông minh XR có dây.
Việc bổ sung nền tảng mới này giúp bạn linh hoạt hơn trong việc tuỳ chỉnh giao diện người dùng.
Để tăng tính riêng biệt cho thương hiệu của ứng dụng, chúng tôi đã thêm màu sắc tuỳ chỉnh vào các thành phần Glimmer.
Hãy sử dụng các thành phần này để thể hiện phong cách thương hiệu của bạn trên các ứng dụng XR.
Thư viện Glimmer của Jetpack Compose cung cấp các hàm trợ giúp để chuyển đổi màu mục tiêu, màu thương hiệu thành màu an toàn cho kính.
Việc này nhằm đảm bảo khả năng hiển thị tối ưu trên màn hình quang học nhìn xuyên thấu.
Hãy xem ví dụ thực tế.
Chúng ta muốn thay đổi màu nút được lấy tiêu điểm cho ứng dụng kính này, tôi sẽ chọn một trong những màu yêu thích của mình.
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 */
}
}Lưu ý rằng khi màu được thêm vào mã, các hàm trợ giúp của Glimmer sẽ điều chỉnh màu đó thành màu an toàn cho kính để tối ưu hoá chế độ hiển thị.
Tất cả những tính năng này đều được tích hợp trong thư viện Glimmer của Jetpack Compose, đảm bảo bạn xây dựng được những trải nghiệm đẹp mắt trên nhiều môi trường.
Trong Android Studio, bạn có thể sử dụng trình mô phỏng để hình dung giao diện người dùng của kính sẽ trông như thế nào trên nhiều nền, chẳng hạn như môi trường sáng, tối hoặc bận rộn.
Đây chỉ là những thay đổi bước đầu.
Không.
Nhóm của tôi nói rằng bạn sẽ không cười khi nghe câu đó, nhưng tôi vẫn giữ lại.
Còn bây giờ, tôi sẽ nhường lời cho Paul để chia sẻ thêm về Jetpack Compose Glimmer.
Kiểm thử, được rồi!
Tôi phải nhấn nút tiếp theo.
Cảm ơn Yasmine.
Được rồi.
Như Yasmine đã nói, Jetpack Compose Glimmer cung cấp các thành phần nền tảng để phát triển ứng dụng phù hợp với kính có màn hình.
Các thành phần của chúng tôi tích hợp những phương pháp hay nhất được xây dựng cho màn hình quang học nhìn xuyên thấu và chúng tôi đã tích hợp trực tiếp các thành phần đó vào API cho các bạn, giúp tất cả nhà phát triển xây dựng trải nghiệm quang học nhìn xuyên thấu đẹp mắt và hữu ích.
Khi thiết kế và xây dựng ứng dụng cho các thiết bị quang học nhìn xuyên thấu như thiết bị này, bạn cần lưu ý một số điều.
Thứ nhất, đây là màn hình trong suốt, nghĩa là không có màu đen.
Khi thế giới hiển thị, màu đen sẽ trong suốt.
Vì vậy, bạn không thể dựa vào nền tối để duy trì độ tương phản cho giao diện người dùng, văn bản và nội dung.
Mặc dù màu đen không hiển thị, nhưng bạn có thể dùng màu này để che khuất nội dung kỹ thuật số khác.
Trong khung giao diện người dùng Glimmer, chúng tôi có một API chiều sâu cho phép bạn dễ dàng tách biệt các thành phần trên giao diện người dùng và tạo cảm giác phân cấp.
Tại đây, bạn có thể thấy độ sâu trên các thẻ trong ngăn xếp này giúp chúng tách biệt với nhau.
Các nhà khoa học về thị giác của chúng tôi đã cung cấp tỷ lệ tương phản mục tiêu cho văn bản và biểu tượng hiển thị trong hầu hết các điều kiện ánh sáng.
Như Yasmine đã trình bày, chúng tôi có thể xây dựng hoặc đã xây dựng tính năng này vào khung để khi tuỳ chỉnh màu nền, bạn có thể yên tâm rằng người dùng sẽ đọc được giao diện của bạn.
Chúng tôi đã tích hợp những phương pháp hay nhất này và các phương pháp khác vào thư viện thành phần ngày càng mở rộng của mình.
Gần đây, chúng tôi đã ra mắt nhiều thành phần mới.
Một trong những phiên bản mới nhất của chúng tôi là thành phần trình chuyển trang có các hiệu ứng chuyển đổi chuyển động và cử chỉ mượt mà được tích hợp sẵn.
val pagerState =
rememberGlimmerPagerState(pageCount = { 10 })
GlimmerHorizontalPager(pagerState) { page ->
/* Card Content */
}Nếu đã quen thuộc với trình chuyển trang ngang của Compose, bạn sẽ thấy thành phần này rất quen thuộc.
Chúng tôi cũng đã ra mắt 4 biến thể thẻ mới được thiết kế để tích hợp liền mạch với trình chuyển trang, ngăn xếp và các thành phần giao diện người dùng khác của Glimmer.
Thẻ hình ảnh ở đầu và thẻ hình ảnh ở cuối hiển thị văn bản và hình ảnh cạnh nhau.
Vì vậy, hãy sử dụng các biến thể thẻ này khi bạn có lượng thông tin bằng văn bản và hình ảnh bằng nhau.
Chúng tôi đã tách thẻ hình ảnh thành biến thể thẻ riêng.
Bạn nên sử dụng bố cục này khi có một hình ảnh lớn với một dòng văn bản hoặc chú thích, chẳng hạn như bộ chọn video này.
Biến thể thẻ hành động nhúng một nút duy nhất vào thẻ.
Hãy sử dụng thuộc tính này khi bạn muốn người dùng biết chính xác điều gì sẽ xảy ra khi họ kích hoạt thẻ, chẳng hạn như trong bộ chọn đích đến này.
Nhóm nút cho phép bạn đặt nhiều nút vào một không gian nhỏ.
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") }
}Chỉ với đoạn mã đơn giản này, bạn sẽ có được những hiệu ứng chuyển đổi đẹp mắt, hành vi cuộn, lớp phủ che đi các cạnh và chỉ xuất hiện khi cần, cũng như dữ liệu đầu vào được tự động định tuyến từ kính đến thành phần điều khiển.
Nhóm nút cũng có thể chứa các nút biểu tượng và nút bật tắt mới.
var buttonChecked by remember { mutableStateOf(false) }
ToggleButton(
checked = buttonChecked,
leadingIcon = { Icon(FavoriteIcon) },
onCheckedChange = { buttonChecked = it }
) {
Text(if (buttonChecked) "On" else "Off")
}Bạn có thể thấy tất cả các loại nút của chúng tôi được sử dụng tại đây để tạo nút điều khiển nội dung nghe nhìn này.
Giờ đây, bạn có thể dễ dàng thử nghiệm giao diện người dùng trên nhiều nền.
Trình mô phỏng kính thực tế cho phép bạn đưa ảnh 360 độ vào và xoay xung quanh để có thể kiểm thử trên nhiều nền, nền bận rộn và bạn biết đấy, sáng, tối.
Nhóm nút rất phù hợp để sử dụng trong chế độ xem chi tiết như thế này để hiển thị các thao tác theo ngữ cảnh.
Khi nhấn, bạn có thể sử dụng hiệu ứng chuyển đổi thành phần dùng chung để chuyển đến trạng thái trình xem chi tiết, sau đó sử dụng cử chỉ quay lại của hệ thống để quay lại chế độ xem trước.
Thật tuyệt.
Ngoài ra, chúng tôi cũng đã thêm chỉ báo nhập bằng giọng nói và hộp thoại cảnh báo.
Vậy nên, có rất nhiều điều mới mẻ.
Nhưng giờ chúng ta đã thấy một số điểm mới, hãy cùng xây dựng một thứ gì đó.
Ngoài việc sử dụng Glimmer để chế tạo kính thông minh, chúng ta còn có thể dùng Glimmer để xây dựng trải nghiệm cho kính thông minh XR có dây.
Chúng tôi muốn bạn xây dựng những trải nghiệm giúp tăng cường thế giới xung quanh bạn, bắt đầu bằng các điểm neo dựa trên vị trí trong thế giới thực.
Hãy tưởng tượng bạn đang ở một thành phố mới, có thể là đi dự một hội nghị dành cho nhà phát triển và bạn muốn tìm một số món ăn ở thành phố xung quanh bạn.
Bạn có thể yêu cầu ứng dụng chỉ đường mà bạn yêu thích tìm các nhà hàng lân cận và thông tin xếp hạng của những nhà hàng đó.
Thông tin có thể được phủ trực tiếp lên vị trí, cung cấp bối cảnh, thông tin và hướng dẫn.
Tại đây, bạn có thể xem thành phần Glimmer mới nhất của chúng tôi có tên là Điểm đánh dấu biểu tượng.
Thành phần này cho phép bạn làm nổi bật các yếu tố chính trong thế giới thực và kết hợp chúng với các thành phần Glimmer khác như thẻ này.
Trong ví dụ này, ứng dụng chú thích các địa điểm yêu thích bằng Google Maps, Địa điểm và API không gian địa lý.
Dereck này, hãy hướng dẫn mọi người cách thiết lập tính năng này nhé.
Bắt đầu nào.
Được rồi.
Được rồi.
Vì vậy, như Paul đã đề cập trước đó, hãy bắt đầu xây dựng.
Vì vậy, chúng ta sẽ sử dụng tài liệu dành cho nhà phát triển trên developer.android.com/xr và xem xét thư viện thành phần Glimmer của Jetpack Compose.
Vì vậy, bạn sẽ có thể xem thông tin tổng quan trực quan về tất cả các thành phần có trên Glimmer.
Hãy bắt đầu với một chút giao diện người dùng mà Paul đã trình bày trước đó.
Vì vậy, chúng ta sẽ sử dụng Glimmer UI để tạo một chỉ báo không gian và một hộp thông tin.
Vì vậy, hãy bắt đầu bằng cách xác định các thành phần mà chúng ta sẽ sử dụng.
Ở bên trái, bạn sẽ thấy một điểm đánh dấu biểu tượng và ở bên phải, chúng tôi sẽ sử dụng một thẻ mô tả địa điểm.
Vì vậy, nếu chuyển đến Android Studio, bạn thực sự có thể xem trước ngăn này giống như bất kỳ thành phần Compose nào khác và bạn có thể thấy các thay đổi của mình theo thời gian thực.
Như đã đề cập trước đó, bạn có thể xem trước giao diện người dùng trong mọi loại môi trường nền và đảm bảo rằng độ tương phản của giao diện người dùng là đủ trong nhiều loại tình huống, chẳng hạn như môi trường tối và sáng.
Và giờ đây, khi canvas đã được thiết lập, chúng ta sẽ tạo một hàng, đặt một điểm đánh dấu biểu tượng vào đó với một số khoảng cách và một thẻ có một số văn bản mẫu.
Và thế là xong.
Nếu bạn hài lòng với bản xem trước 2D, chúng ta có thể bắt đầu đánh dấu một nội dung nào đó trong thế giới thực bằng cách không gian hoá giao diện người dùng.
Điều này có nghĩa là chúng ta sẽ bố trí theo không gian 3D thay vì 2D.
Vì vậy, giao diện người dùng không gian được chứa trong các không gian phụ, tức là một không gian 3D trước mặt người dùng.
Subspace {
SpatialPanel {
VideoPlayer()
}
}Theo mặc định, một không gian con thực sự bố trí nội dung của nó ở một khoảng cách thoải mái với người dùng.
Vì vậy, trước khi hướng dẫn bạn cách sử dụng Geospatial API, hãy đặt một đối tượng ở gần trước.
Vì vậy, composable không gian con mà tôi đã đề cập trước đó có một tham số không bắt buộc cho phép bạn chỉ định mục tiêu theo dõi.
val state by
qrCode.state.collectAsState()
Subspace(FollowTarget.anchor(anchor)) {
SpatialPanel {
Row {
IndicatorDot()
Spacer()
QrCodeCard(state)
}
}
}Vì vậy, để gắn một đối tượng vào thế giới thực, trước tiên, bạn sẽ tạo một neo lấy từ ARCore cho Jetpack XR.
Và trong ví dụ này, tôi thực sự đang sử dụng tính năng nhận dạng mã QR.
Và điều này sẽ cho phép bạn đọc và theo dõi mã QR, nhờ đó, nội dung của bạn có thể theo dõi mã QR đó trong không gian và chúng ta sẽ đính kèm giao diện người dùng mà chúng ta đã thấy trước đó.
Được rồi.
Tôi đã hướng dẫn bạn cách đặt nội dung kỹ thuật số vào thế giới thực xung quanh.
Hãy quay lại ví dụ về Paul.
Cá nhân tôi đến từ Hà Lan.
Tôi không rành về Mountain View lắm.
Vì vậy, sau sự kiện này, tôi muốn giúp bạn tạo một ứng dụng giúp bạn tìm thấy một số quán cà phê thú vị.
Hãy cùng tìm hiểu cách chúng ta có thể giúp người dùng tìm thấy một số địa điểm bằng Geospatial API hiện có trong ARCore cho Jetpack XR.
Vì vậy, Geospatial API (vốn ra mắt trên điện thoại thông minh) nay cũng có trên Android XR.
Tính năng này sử dụng dữ liệu từ Chế độ xem đường phố của Google và kết hợp dữ liệu đó với thông tin đo lường GPS để xác định vị trí của thiết bị ở những khu vực được hỗ trợ.
Vì vậy, trên kính thông minh, bạn có thể dùng Geospatial API để xác định chính xác vị trí và hướng đi của người dùng, đồng thời hỗ trợ các trường hợp sử dụng tính năng đường đi từng chặng có độ chính xác cao.
Trên các thiết bị sống động như kính thông minh XR có dây, Geospatial API cho phép bạn xây dựng trải nghiệm được định vị chính xác trong thế giới thực.
Ví dụ: bạn có thể neo nội dung không gian trên các toà nhà hoặc tạo các chuyến tham quan thành phố chuyên biệt.
Vậy thì hãy bắt đầu sử dụng Geospatial API qua 3 bước sau đây.
Đầu tiên, bạn sẽ tạo một dự án Google Cloud Platform và định cấu hình quy trình xác thực trong ứng dụng.
Sau đó, khi Geospatial API được định cấu hình và bật trong ứng dụng, bạn sẽ yêu cầu người dùng cấp quyền truy xuất thông tin vị trí của họ bằng cách sử dụng độ chi tiết cao.
Sau khi định cấu hình phiên để sử dụng Geospatial API, bạn đã hoàn tất.
Vì vậy, bạn có thể tìm thấy tất cả thông tin chi tiết về Geospatial API trong tài liệu dành cho nhà phát triển trên trang mới được làm mới dành cho nhà phát triển Android XR.
Vì vậy, hãy bắt đầu bằng cách sử dụng vị trí của người dùng để yêu cầu Places API từ Google Maps Platform tìm một số quán cà phê tuyệt vời gần người dùng.
Vậy trước tiên, người dùng đang ở đâu?
Chúng tôi sẽ yêu cầu Geospatial API liên tục cập nhật thông tin về vị trí của người dùng.
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)
}Vì vậy, chúng ta sẽ truy cập vào đối tượng không gian địa lý thông qua phiên XR.
Sau đó, chúng ta sẽ đợi Geospatial khởi động và chạy trong khi khởi chạy các cảm biến trung tâm cần thiết và kết nối với Cloud API.
Sau đó, chúng ta sẽ đợi cho đến khi đạt được một mức độ chính xác nhất định.
Do đó, mức độ chính xác có thể cải thiện khi có kết quả đo lường của GPS hoặc khi hệ thống định vị trực quan tìm thấy kết quả trùng khớp tại vị trí của người dùng.
Ngoài ra, việc chờ đợi để có được Độ chính xác cao là điều quan trọng để đảm bảo rằng trải nghiệm dựa trên vị trí được cố định ở đúng nơi và kết quả là từ khu vực lân cận của người dùng.
Sau đó, chúng ta đã sẵn sàng thực hiện tìm kiếm bằng Places API bằng cách sử dụng các giá trị vị trí từ 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()Vì vậy, chúng ta sẽ sử dụng SearchNearbyRequest với Places API để truy vấn các địa điểm xung quanh vị trí của người dùng mà chúng ta đã thu thập trước đó và tìm kết quả trong phạm vi 100 m.
Chúng ta sẽ lấy mã nhận dạng, tên hiển thị, điểm xếp hạng và tất nhiên là cả vị trí của địa điểm.
Cuối cùng, chúng ta sẽ thực hiện tìm kiếm bằng các tham số đã chỉ định, bao gồm cả bộ lọc loại địa điểm.
Vậy là xong phần dữ liệu, giờ hãy quay lại giao diện người dùng.
Vì vậy, chúng ta cần tìm cách đặt điểm đánh dấu và hộp thông tin từ trước đó. Để làm việc này, chúng ta sẽ sử dụng neo không gian địa lý.
Quay lại đoạn mã, một lần nữa, chúng ta sẽ truy cập vào Geospatial API bằng phiên XR, sau đó tạo một điểm neo không gian địa lý bằng cách sử dụng vĩ độ và kinh độ cụ thể lấy từ kết quả tìm kiếm trước đó.
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()
)
}Vì vậy, trong ví dụ này, chúng tôi đã chỉ định độ cao là 3 m so với địa hình tại các toạ độ đó, nhưng bạn cũng có thể gắn vào các mái nhà được hỗ trợ, tức là giá trị độ cao sẽ được xác định tương ứng với mái nhà tại toà nhà ở vị trí đó.
Vì vậy, bạn cũng có thể xoay điểm neo bằng cách sử dụng một quaternion, chỉ định các giá trị xoay của điểm neo.
Nhưng chúng ta sẽ thực sự sử dụng các giá trị mặc định trong ví dụ này vì chúng ta sẽ làm cho giao diện người dùng xoay để đối diện với người dùng.
Sau đó, chúng ta sẽ đính kèm giao diện người dùng Glimmer trước đó vào điểm neo này, và điều đó thực sự mang đến cho bạn các thành phần cho một trải nghiệm được neo trong không gian.
when (anchorResult) {
is AnchorCreateSuccess ->
Subspace(FollowTarget.anchor(anchorResult.anchor)) {
SpatialPanel(SubspaceModifier.rotateToLookAtUser()) {
PlaceIndicator(place)
}
}
else ->
Log.e("Demo", "Failed to create anchor $anchorResult")
}Vì vậy, chúng tôi tin rằng Geospatial API có thể mang lại trải nghiệm tìm đường tuyệt vời và việc thiết kế bằng Glimmer sẽ giúp tạo ra trải nghiệm người dùng dễ nhìn, được thiết kế riêng cho màn hình trong suốt.
Để biết thêm thông tin về Geospatial API, hãy truy cập vào trang developer.android.com/xr mới được cập nhật gần đây.
Bây giờ, tôi xin nhường lại cho Yasmine để kết thúc buổi hội thảo.
Trong phiên này, chúng ta đã tìm hiểu một số tính năng của Android XR: ARCore cho Jetpack XR và Jetpack Compose Glimmer.
Chúng tôi rất hào hứng về những tính năng mới mà Android XR sẽ mang đến cho kính thông minh XR có dây.
Các nhà phát triển đã bắt đầu xây dựng cho Android XR và chúng tôi hy vọng sẽ thấy tác phẩm sáng tạo của bạn trên Cửa hàng Google Play.
Để bắt đầu, vui lòng xem tài liệu dành cho nhà phát triển, lấy cảm hứng từ các thử nghiệm XR của chúng tôi và bắt đầu với các lớp học lập trình.
Chúng tôi đã lên kế hoạch cho rất nhiều buổi chia sẻ, minh hoạ và hội thảo thú vị về XR cho tất cả các bạn.
Vì vậy, hãy theo dõi và tìm hiểu về cách xây dựng ứng dụng cho Android XR trên cả trải nghiệm sống động và trải nghiệm tăng cường.
Thay mặt cho nhóm Android XR, xin chân thành cảm ơn các bạn đã tham dự và chúc các bạn có một khoảng thời gian tuyệt vời tại Hội nghị Nhà phát triển Android.
Cảm ơn bạn.
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")
}