Com o Jetpack Compose para XR, é possível criar de forma declarativa a interface espacial e o layout usando conceitos conhecidos do Compose, como linhas e colunas. Isso permite estender a interface do Android para o espaço 3D ou criar aplicativos 3D imersivos completamente novos.
Se você estiver espacializando um app baseado em Android Views, terá várias opções de desenvolvimento. Você pode usar APIs de interoperabilidade, usar o Compose e as visualizações juntos ou trabalhar diretamente com a biblioteca SceneCore. Consulte nosso guia de trabalho com visualizações para mais detalhes.
Sobre subespaços e componentes espaciais
Ao criar seu app para o Android XR, é importante entender os conceitos de subespaço e componentes espacializados.
Sobre o Subspace
Ao desenvolver para o Android XR, você precisa adicionar um subspace ao app ou layout. Um subespaço é uma partição do espaço 3D no app em que é possível colocar conteúdo 3D, criar layouts 3D e adicionar profundidade a conteúdo 2D. Um subespaço é renderizado somente quando a espacialização está ativada. No espaço doméstico ou em dispositivos que não são XR, qualquer código nesse subspace é ignorado.
Há duas maneiras de criar um subespaço:
setSubspaceContent
: essa função cria um subespaço no nível do app. Ele pode ser chamado na MainActivity da mesma forma que você usasetContent
. Um subspace no nível do app não tem limite de altura, largura e profundidade, fornecendo uma tela infinita para conteúdo espacial.Subspace
: esse elemento combinável pode ser colocado em qualquer lugar na hierarquia da interface do app, permitindo que você mantenha layouts para interfaces 2D e espaciais sem perder o contexto entre os arquivos. Isso facilita o compartilhamento de elementos, como a arquitetura do app atual entre XR e outros formatos, sem precisar elevar o estado por toda a árvore da interface ou reprojetar o app.
Para mais informações, leia sobre como adicionar um subspace ao app.
Sobre os componentes espaciais
Combináveis de subespaço: esses componentes só podem ser renderizados em um subespaço.
Elas precisam ser incluídas em Subspace
ou setSubspaceContent
antes de serem
colocadas em um layout 2D. Um SubspaceModifier
permite adicionar
atributos como profundidade, deslocamento e posicionamento aos elementos combináveis do subespaço.
- Observação sobre os modificadores de subespaço: preste atenção na ordem das
APIs
SubspaceModifier
.- O deslocamento precisa ocorrer primeiro em uma cadeia de modificadores
- Movível e redimensionável precisam ocorrer por último
- A rotação precisa ser aplicada antes da escala.
Outros componentes espaciais não precisam ser chamados em um subspace. Eles consistem em elementos 2D convencionais unidos em um contêiner espacial. Esses elementos podem ser usados em layouts 2D ou 3D, se definidos para ambos. Quando a espacialização não está ativada, os recursos espaciais são ignorados e voltam para as versões 2D.
Criar um painel espacial
Um SpatialPanel
é um elemento combinável de subespaço que permite exibir o conteúdo do app. Por
exemplo, é possível exibir a reprodução de vídeo, imagens estáticas ou qualquer outro conteúdo em
um painel espacial.
Use SubspaceModifier
para mudar o tamanho, o comportamento e o posicionamento do
painel espacial, conforme mostrado no exemplo abaixo.
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
)
}
}
Pontos principais sobre o código
- Observação sobre os modificadores de subespaço: preste atenção à ordem das
APIs
SubspaceModifier
.- O deslocamento precisa ocorrer primeiro em uma cadeia de modificadores.
- Os modificadores móveis e redimensionáveis precisam ocorrer por último.
- A rotação precisa ser aplicada antes da escala.
- Como as APIs
SpatialPanel
são combináveis de subespaço, é necessário chamá-las dentro deSubspace
ousetSubspaceContent
. Chamar esse método fora de um subespaço gera uma exceção. - Permita que o usuário redimensione ou mova o painel adicionando
SubspaceModifier
s.movable
ou.resizable
. - Consulte nossas orientações de design de painel espacial para saber mais sobre dimensionamento e posicionamento. Consulte nossa documentação de referência para mais detalhes sobre a implementação do código.
Criar um orbitador
Um orbitador é um componente de interface espacial. Ele foi projetado para ser anexado a um painel espacial correspondente e contém itens de navegação e ação contextual relacionados a esse painel. Por exemplo, se você criou um painel espacial para exibir conteúdo de vídeo, pode adicionar controles de reprodução de vídeo dentro de um orbitador.
Conforme mostrado no exemplo abaixo, chame um orbitador dentro de um SpatialPanel
para
envolver controles do usuário, como navegação. Isso extrai os elementos do layout 2D
e os anexa ao painel espacial de acordo com a configuração.
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
)
}
}
}
}
Pontos principais sobre o código
- Observação sobre os modificadores de subespaço: preste atenção à ordem das
APIs
SubspaceModifier
.- O deslocamento precisa ocorrer primeiro em uma cadeia de modificadores
- Movível e redimensionável precisam ocorrer por último
- A rotação precisa ser aplicada antes da escala.
- Como os orbiters são componentes de interface espacial, o código pode ser reutilizado em layouts 2D ou 3D. Em um layout 2D, o app renderiza apenas o conteúdo dentro do orbitador e ignora o próprio orbitador.
- Confira nossas orientações de design para mais informações sobre como usar e projetar orbitadores.
Adicionar vários painéis espaciais a um layout espacial
É possível criar vários painéis espaciais e colocá-los em um
layout espacial usando SpatialRow
,
SpatialColumn
, SpatialBox
e
SpatialLayoutSpacer
.
O exemplo de código abaixo mostra como fazer isso.
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
)
}
}
Pontos principais sobre o código
SpatialRow
,SpatialColumn
,SpatialBox
eSpatialLayoutSpacer
são combináveis de subespaço e precisam ser colocados em um subespaço.- Use
SubspaceModifier
para personalizar o layout. - Para layouts com vários painéis em uma linha, recomendamos definir um raio de curva
de 825 dp usando um
SubspaceModifier
para que os painéis rodeiem o usuário. Consulte nossas orientações de design para mais detalhes.
Usar um volume para colocar um objeto 3D no layout
Para colocar um objeto 3D no layout, você precisa usar um elemento combinável de subespaço chamado volume. Confira um exemplo de como fazer isso.
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
}
}
}
}
}
Pontos principais sobre o código
- Observação sobre os modificadores de subespaço: preste atenção à ordem das
APIs
SubspaceModifier
.- O deslocamento precisa ocorrer primeiro em uma cadeia de modificadores
- Movível e redimensionável precisam ocorrer por último
- A rotação precisa ser aplicada antes da escala.
- Consulte Como adicionar conteúdo 3D para entender melhor como carregar conteúdo 3D em um volume.
Adicionar outros componentes de interface espacial
Os componentes de IU espacial podem ser colocados em qualquer lugar na hierarquia de IU do aplicativo. Esses elementos podem ser reutilizados na interface 2D, e os atributos espaciais só serão visíveis quando os recursos espaciais estiverem ativados. Isso permite adicionar elevação a menus, caixas de diálogo e outros componentes sem precisar escrever o código duas vezes. Confira os exemplos de interface espacial a seguir para entender melhor como usar esses elementos.
Componente da interface |
Quando a espacialização está ativada |
Em um ambiente 2D |
---|---|---|
|
O painel vai se afastar um pouco na profundidade Z para mostrar uma caixa de diálogo elevada. |
Volta para 2D |
|
O painel é empurrado ligeiramente para trás na z-depth para mostrar um pop-up elevado. |
Volta para um |
|
|
Mostra sem elevação espacial. |
SpatialDialog
Este é um exemplo de caixa de diálogo que é aberta após um breve atraso. Quando
SpatialDialog
é usado, a caixa de diálogo aparece na mesma profundidade z do painel
espacial, e o painel é empurrado para trás em 125dp quando a espacialização está ativada.
O SpatialDialog
ainda pode ser usado quando a espacialização não está ativada e
volta para a versão 2D: 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")
}
}
}
}
}
Pontos principais sobre o código
- Este é um exemplo de
SpatialDialog
. O uso deSpatialPopUp
eSpatialElevation
será muito semelhante. Consulte nossa referência da API para mais detalhes.
Criar painéis e layouts personalizados
Para criar painéis personalizados que não têm suporte do Compose para XR, você pode trabalhar
diretamente com PanelEntities
e a cena usando as APIs
SceneCore
.