Para começar a fornecer blocos, inclua as dependências abaixo no
arquivo build.gradle
do app.
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.5.0-alpha04" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.3.0-alpha04" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.3.0-alpha04" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.5.0-alpha04" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.5.0-alpha04" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.5.0-alpha04") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.3.0-alpha04") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.3.0-alpha04") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.3.0-alpha04") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.5.0-alpha04") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.5.0-alpha04") }
Principais conceitos
Os Blocos não são criados da mesma forma que os apps Android e usam conceitos diferentes:
- Modelos de layout:definem a disposição geral dos elementos visuais na
tela. Um bloco usa um modelo de layout
EdgeContentLayout
, que inclui um indicador de progresso ao redor da borda da tela, ou umPrimaryLayout
, que não mostra esse indicador. - Elementos de layout:representam um elemento gráfico individual, como
Button
ouChip
, ou vários elementos agrupados usando umColumn
,MultiButtonLayout
,MultiSlotLayout
ou algo semelhante. Eles são incorporados em um modelo de layout. - Recursos:os objetos
ResourceBuilders.Resources
consistem em um mapa de pares de chave-valor dos recursos do Android (imagens) necessários para renderizar um layout e uma versão. - Linha do tempo:um objeto
TimelineBuilders.Timeline
é uma lista de uma ou mais instâncias de um objeto de layout. É possível fornecer vários mecanismos e expressões para indicar quando o renderizador precisa alternar de um objeto de layout para outro, como parar de mostrar um layout em um momento específico. - Estado:uma estrutura de dados do tipo
StateBuilders.State
que é transmitida entre o Bloco e o app para permitir que os dois componentes se comuniquem entre si. Por exemplo, se um botão for tocado no bloco, o estado terá o ID do botão. Também é possível trocar tipos de dados usando um mapa. - Tile:um objeto
TileBuilders.Tile
que representa um bloco, consistindo de uma linha do tempo, um ID da versão de recursos, um intervalo de atualização e um estado. - Protolayout:esse termo aparece no nome de várias classes relacionadas a blocos e se refere à biblioteca Protolayout do Wear OS, uma biblioteca gráfica usada em várias plataformas do Wear OS.
Criar um bloco
Para fornecer um Bloco do app, implemente um serviço do tipo TileService
e registre-o no manifesto. Com isso, o sistema solicita os
tiles necessários durante as chamadas para onTileRequest()
e
recursos durante as chamadas para onTileResourcesRequest()
.
class MyTileService : TileService() { override fun onTileRequest(requestParams: RequestBuilders.TileRequest) = Futures.immediateFuture( Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( Text.Builder(this, "Hello World!") .setTypography(Typography.TYPOGRAPHY_BODY1) .setColor(argb(0xFFFFFFFF.toInt())) .build() ) ) .build() ) override fun onTileResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture( Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ) }
Em seguida, adicione um serviço dentro da tag <application>
do
arquivo AndroidManifest.xml
.
<service android:name=".snippets.tile.MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:icon="@mipmap/ic_launcher" android:exported="true" android:permission="com.google.android.wearable.permission.BIND_TILE_PROVIDER"> <intent-filter> <action android:name="androidx.wear.tiles.action.BIND_TILE_PROVIDER" /> </intent-filter> <meta-data android:name="androidx.wear.tiles.PREVIEW" android:resource="@drawable/tile_preview" /> </service>
O filtro de permissão e intent registra esse serviço como um provedor de blocos.
O ícone, o rótulo, a descrição e o recurso de visualização são mostrados ao usuário quando ele configura Blocos no smartphone ou smartwatch.
Implante o app e adicione o Bloco ao carrossel de Blocos. Há uma maneira mais fácil para desenvolvedores visualizarem um Bloco, mas, por enquanto, faça manualmente.
Figura 1. Bloco "Hello World".
Para conferir um exemplo completo, consulte o exemplo de código no GitHub ou o codelab.
Criar uma IU para blocos
O layout de um bloco é criado usando um padrão de construtor. Ele é construído como árvore que consiste em contêineres e elementos básicos de layout. Cada elemento de layout tem propriedades, que podem ser definidas com vários métodos setter.
Elementos básicos de layout
Os elementos visuais da biblioteca protolayout
abaixo têm suporte
nos componentes do Material Design:
Text
: renderiza uma string de texto, opcionalmente a encapsulando.Image
: renderiza uma imagem.Spacer
: fornece padding entre elementos ou pode atuar como um divisor quando você define a cor do plano de fundo.
Componentes do Material Design
Além dos elementos básicos, a biblioteca protolayout-material
fornece
componentes que garantem um design de blocos alinhado às recomendações da interface do usuário do
Material Design.
Button
: componente circular clicável projetado para conter um ícone.Chip
: componente clicável em formato de estádio projetado para conter até duas linhas de texto e um ícone opcional.CompactChip
: componente clicável em formato de estádio projetado para conter uma linha de texto.TitleChip
: componente clicável em formato de estádio semelhante aChip
, mas com uma altura maior para acomodar o texto do título.CircularProgressIndicator
: indicador de progresso circular que pode ser colocado dentro de umEdgeContentLayout
para mostrar o progresso ao redor das bordas da tela.
Contêineres de layout
Os contêineres abaixo têm suporte nos layouts do Material Design:
Row
: mostra os elementos filhos horizontalmente, um após o outro.Column
: mostra os elementos filhos verticalmente, um após o outro.Box
: sobrepõe elementos filhos uns sobre os outros.Arc
: mostra os elementos filhos em um círculo.Spannable
: aplicaFontStyles
específicos a seções de texto, bem como texto e imagens intercalados. Para mais informações, consulte Spannables.
Cada contêiner pode conter um ou mais filhos, que também podem ser
contêineres. Por exemplo, uma Column
pode conter vários elementos Row
como
filhos, resultando em um layout parecido com uma grade.
Um bloco com um layout de contêiner e dois elementos de layout filhos pode ser parecido com este exemplo:
Kotlin
private fun myLayout(): LayoutElement = Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VERTICAL_ALIGN_BOTTOM) .addContent(Text.Builder() .setText("Hello world") .build() ) .addContent(Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build()
Java
private LayoutElement myLayout() { return new Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_BOTTOM) .addContent(new Text.Builder() .setText("Hello world") .build() ) .addContent(new Image.Builder() .setResourceId("image_id") .setWidth(dp(24f)) .setHeight(dp(24f)) .build() ).build(); }
Layouts do Material Design
Além dos layouts básicos, a biblioteca protolayout-material
fornece alguns
layouts opinativos feitos para manter elementos em "slots" específicos.
PrimaryLayout
: posiciona uma única ação principalCompactChip
na parte de baixo com o conteúdo centralizado acima dela.MultiSlotLayout
: posiciona os rótulos primário e secundário com conteúdo opcional entre eles e umCompactChip
opcional na parte de baixo da tela.MultiButtonLayout
: posiciona um conjunto de botões organizados de acordo com as diretrizes do Material Design.EdgeContentLayout
: posiciona o conteúdo ao redor da borda de uma tela, como umCircularProgressIndicator
. Ao usar esse layout, o conteúdo dele tem as margens e o padding adequados aplicados automaticamente.
Arcos
Há suporte para os filhos de contêiner Arc
abaixo:
ArcLine
: renderiza uma linha curva ao redor do arco.ArcText
: renderiza texto curvado no arco.ArcAdapter
: renderiza um elemento de layout básico no arco, mostrado em uma tangente em relação ao arco.
Para mais informações, consulte a documentação de referência de cada um dos tipos de elemento.
Modificadores
Como alternativa, todos os elementos de layout disponíveis podem ter modificadores. Use esses modificadores para as finalidades abaixo:
- Mudar a aparência do layout. Por exemplo, adicionar um plano de fundo, uma borda ou um padding ao elemento de layout.
- Adicionar metadados sobre o layout. Por exemplo, adicionar um modificador de semântica ao elemento de layout que vai ser usado por leitores de tela.
- Adicionar funcionalidade. Por exemplo, adicione um modificador clicável ao elemento de layout para tornar o bloco interativo. Para mais informações, consulte Interagir com blocos.
Por exemplo, podemos personalizar a aparência e os metadados padrão de uma Image
,
conforme mostrado no exemplo de código abaixo:
Kotlin
private fun myImage(): LayoutElement = Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(Modifiers.Builder() .setBackground(Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(Padding.Builder().setStart(dp(12f)).build()) .setSemantics(Semantics.builder() .setContentDescription("Image description") .build() ).build() ).build()
Java
private LayoutElement myImage() { return new Image.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .setModifiers(new Modifiers.Builder() .setBackground(new Background.Builder().setColor(argb(0xFFFF0000)).build()) .setPadding(new Padding.Builder().setStart(dp(12f)).build()) .setSemantics(new Semantics.Builder() .setContentDescription("Image description") .build() ).build() ).build(); }
Spannables
Um Spannable
é um tipo especial de contêiner que apresenta elementos de maneira parecida com um
texto. Isso é útil quando você quer aplicar um estilo diferente a apenas uma
substring em um bloco de texto maior, algo que não é possível com o
elemento Text
.
Um contêiner Spannable
é preenchido com filhos Span
. Outros filhos ou
instâncias Spannable
aninhadas não são permitidos.
Há dois tipos de filhos Span
:
SpanText
: renderiza o texto com um estilo específico.SpanImage
: renderiza uma imagem inline com texto.
Por exemplo, você pode aplicar itálico à palavra "world" em um bloco "Hello world" e inserir uma imagem entre as palavras, conforme mostrado neste exemplo de código:
Kotlin
private fun mySpannable(): LayoutElement = Spannable.Builder() .addSpan(SpanText.Builder() .setText("Hello ") .build() ) .addSpan(SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(SpanText.Builder() .setText("world") .setFontStyle(FontStyle.Builder() .setItalic(true) .build()) .build() ).build()
Java
private LayoutElement mySpannable() { return new Spannable.Builder() .addSpan(new SpanText.Builder() .setText("Hello ") .build() ) .addSpan(new SpanImage.Builder() .setWidth(dp(24f)) .setHeight(dp(24f)) .setResourceId("image_id") .build() ) .addSpan(new SpanText.Builder() .setText("world") .setFontStyle(newFontStyle.Builder() .setItalic(true) .build()) .build() ).build(); }
Trabalhar com recursos
Os blocos não têm acesso a nenhum dos recursos do seu app. Isso significa que você
não pode transmitir um ID de imagem do Android a um elemento de layout Image
e esperar que ele seja
resolvido. Em vez disso, substitua o método onTileResourcesRequest()
e
forneça os recursos manualmente.
Há duas maneiras de fornecer imagens no método
onTileResourcesRequest()
:
- Forneça um recurso drawable usando
setAndroidResourceByResId()
. - Forneça uma imagem dinâmica como uma
ByteArray
usandosetInlineResource()
.
Kotlin
override fun onTileResourcesRequest( requestParams: ResourcesRequest ) = Futures.immediateFuture( Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", ImageResource.Builder() .setAndroidResourceByResId(AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", ImageResource.Builder() .setInlineResource(InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() )
Java
@Override protected ListenableFuture<Resources> onTileResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture( new Resources.Builder() .setVersion("1") .addIdToImageMapping("image_from_resource", new ImageResource.Builder() .setAndroidResourceByResId(new AndroidImageResourceByResId.Builder() .setResourceId(R.drawable.image_id) .build() ).build() ) .addIdToImageMapping("image_inline", new ImageResource.Builder() .setInlineResource(new InlineImageResource.Builder() .setData(imageAsByteArray) .setWidthPx(48) .setHeightPx(48) .setFormat(ResourceBuilders.IMAGE_FORMAT_RGB_565) .build() ).build() ).build() ); }
Recomendados para você
- Observação: o texto do link aparece quando o JavaScript está desativado.
- Migrar para namespaces ProtoLayout
ConstraintLayout
no Compose- Criar blocos personalizados de Configurações rápidas para seu app