Pour commencer à fournir des cartes à partir de votre application, incluez les dépendances suivantes dans le fichier build.gradle
de votre application.
Groovy
dependencies { // Use to implement support for wear tiles implementation "androidx.wear.tiles:tiles:1.4.0" // Use to utilize standard components and layouts in your tiles implementation "androidx.wear.protolayout:protolayout:1.2.0" // Use to utilize components and layouts with Material Design in your tiles implementation "androidx.wear.protolayout:protolayout-material:1.2.0" // Use to include dynamic expressions in your tiles implementation "androidx.wear.protolayout:protolayout-expression:1.2.0" // Use to preview wear tiles in your own app debugImplementation "androidx.wear.tiles:tiles-renderer:1.4.0" // Use to fetch tiles from a tile provider in your tests testImplementation "androidx.wear.tiles:tiles-testing:1.4.0" }
Kotlin
dependencies { // Use to implement support for wear tiles implementation("androidx.wear.tiles:tiles:1.4.0") // Use to utilize standard components and layouts in your tiles implementation("androidx.wear.protolayout:protolayout:1.2.0") // Use to utilize components and layouts with Material Design in your tiles implementation("androidx.wear.protolayout:protolayout-material:1.2.0") // Use to include dynamic expressions in your tiles implementation("androidx.wear.protolayout:protolayout-expression:1.2.0") // Use to preview wear tiles in your own app debugImplementation("androidx.wear.tiles:tiles-renderer:1.4.0") // Use to fetch tiles from a tile provider in your tests testImplementation("androidx.wear.tiles:tiles-testing:1.4.0") }
Créer une carte
Pour fournir une carte à partir de votre application, créez une classe qui étend TileService
et implémentez les méthodes, comme indiqué dans l'exemple de code suivant :
Kotlin
// Uses the ProtoLayout namespace for tile timeline objects. // If you haven't done so already, migrate to the ProtoLayout namespace. import androidx.wear.protolayout.TimelineBuilders.Timeline import androidx.wear.protolayout.material.Text import androidx.wear.tiles.TileBuilders.Tile private val RESOURCES_VERSION = "1" 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_DISPLAY1) .setColor(argb(0xFF000000.toInt())) .build())) .build()) override fun onTileResourcesRequest(requestParams: ResourcesRequest) = Futures.immediateFuture(Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ) }
Java
// Uses the ProtoLayout namespace for tile timeline objects. // If you haven't done so already, migrate to the ProtoLayout namespace. import androidx.wear.protolayout.TimelineBuilders.Timeline; import androidx.wear.protolayout.material.Text; import androidx.wear.tiles.TileBuilders.Tile; public class MyTileService extends TileService { private static final String RESOURCES_VERSION = "1"; @NonNull @Override protected ListenableFuture<Tile> onTileRequest( @NonNull TileRequest requestParams ) { return Futures.immediateFuture(new Tile.Builder() .setResourcesVersion(RESOURCES_VERSION) .setTileTimeline( Timeline.fromLayoutElement( new Text.Builder(this, "Hello world!") .setTypography(Typography.TYPOGRAPHY_DISPLAY1) .setColor(ColorBuilders.argb(0xFF000000)) .build())) .build() ); } @NonNull @Override protected ListenableFuture<Resources> onTileResourcesRequest( @NonNull ResourcesRequest requestParams ) { return Futures.immediateFuture(new Resources.Builder() .setVersion(RESOURCES_VERSION) .build() ); } }
Ajoutez ensuite un service à l'intérieur de la balise <application>
de votre fichier AndroidManifest.xml
.
<service android:name=".MyTileService" android:label="@string/tile_label" android:description="@string/tile_description" android:icon="@drawable/tile_icon_round" android:roundIcon="@drawable/tile_icon_round" 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>
Le filtre d'intent et d'autorisation enregistre ce service en tant que fournisseur de cartes.
L'icône, le libellé et la description sont présentés à l'utilisateur lorsqu'il configure des cartes sur son téléphone ou sa montre.
Utilisez la balise de métadonnées d'aperçu pour afficher un aperçu de la carte lorsqu'elle est configurée sur votre téléphone.
Présentation du cycle de vie du service de cartes
Une fois que vous avez créé et déclaré votre TileService
dans le fichier manifeste de votre application, vous pouvez répondre aux changements d'état du service de cartes.
TileService
est un service lié. Votre TileService
est lié à la suite de votre requête d'application ou si le système doit communiquer avec lui. Un cycle de vie de service lié typique contient les quatre méthodes de rappel suivantes : onCreate()
, onBind()
, onUnbind()
et onDestroy()
. Le système appelle ces méthodes chaque fois que le service entre dans une nouvelle phase du cycle de vie.
En plus des rappels qui contrôlent le cycle de vie du service lié, vous pouvez implémenter d'autres méthodes spécifiques au cycle de vie d'une TileService
. Tous les services de cartes doivent implémenter onTileRequest()
et onTileResourcesRequest()
pour répondre aux requêtes de mises à jour du système.
onTileAddEvent()
: le système n'appelle cette méthode que lorsque l'utilisateur ajoute votre carte pour la première fois, et s'il la supprime, puis l'ajoute à nouveau. Il s'agit du meilleur moment pour effectuer une initialisation unique.onTileAddEvent()
n'est appelé que lorsque l'ensemble de tuiles est reconfiguré, et non chaque fois qu'une carte est créée par le système. Par exemple, lorsque l'appareil est redémarré ou allumé,onTileAddEvent()
n'est pas appelé pour les cartes qui ont déjà été ajoutées. Vous pouvez utilisergetActiveTilesAsync()
à la place pour obtenir un instantané des tuiles qui vous appartiennent qui sont actives.onTileRemoveEvent()
: le système n'appelle cette méthode que si l'utilisateur supprime votre carte.onTileEnterEvent()
: le système appelle cette méthode lorsqu'une carte fournie par ce fournisseur apparaît à l'écran.onTileLeaveEvent()
: le système appelle cette méthode lorsqu'une carte fournie par ce fournisseur n'est plus visible à l'écran.onTileRequest()
: le système appelle cette méthode lorsqu'il demande une nouvelle chronologie à ce fournisseur.onTileResourcesRequest()
: le système appelle cette méthode lorsqu'il demande un groupe de ressources à ce fournisseur. Cela peut se produire lors du premier chargement d'une carte ou chaque fois que la version de la ressource change.
Interroger les vignettes actives
Les cartes actives sont des cartes qui ont été ajoutées pour être affichées sur la montre. Utilisez la méthode statique getActiveTilesAsync()
de TileService
pour interroger les cartes appartenant à votre application qui sont actives.
Créer une UI pour les cartes
La disposition d'une carte est écrite à l'aide d'un modèle de compilateur. La mise en page d'une carte est construite comme une arborescence constituée de conteneurs de mise en page et d'éléments de mise en page de base. Chaque élément de mise en page possède des propriétés que vous pouvez définir à l'aide de différentes méthodes setter.
Éléments de mise en page de base
Les éléments visuels suivants de la bibliothèque protolayout
sont acceptés, ainsi que les composants Material :
Text
: affiche une chaîne de texte, avec éventuellement un retour à la ligne.Image
: affiche une image.Spacer
: fournit une marge intérieure entre les éléments ou peut servir de séparateur lorsque vous définissez sa couleur d'arrière-plan.
Composants Material
Outre les éléments de base, la bibliothèque protolayout-material
fournit des composants qui garantissent une conception de carte conforme aux recommandations de l'interface utilisateur de Material Design.
Button
: composant cliquable circulaire conçu pour contenir une icône.Chip
: composant cliquable en forme de stade conçu pour contenir jusqu'à deux lignes de texte et éventuellement une icône.CompactChip
: composant cliquable en forme de stade conçu pour contenir une ligne de texte.TitleChip
: composant cliquable en forme de stade semblable àChip
, mais avec une hauteur supérieure pour accueillir le texte du titre.CircularProgressIndicator
: indicateur de progression circulaire pouvant être placé à l'intérieur d'unEdgeContentLayout
pour afficher la progression autour des bords de l'écran.
Conteneurs de mise en page
Les conteneurs suivants sont acceptés, de même que les mises en page Material :
Row
: dispose les éléments enfants horizontalement, les uns après les autres.Column
: dispose les éléments enfants verticalement, les uns après les autres.Box
: superpose les éléments enfants les uns au-dessus des autres.Arc
: dispose les éléments enfants dans un cercle.Spannable
: applique desFontStyles
spécifiques aux sections de texte, avec entrelacement du texte et des images. Pour en savoir plus, consultez Spannables.
Chaque conteneur peut comporter un ou plusieurs enfants qui peuvent, à leur tour, être des conteneurs. Par exemple, un élément Column
peut contenir plusieurs éléments Row
en tant qu'enfants, ce qui se traduit par une mise en page en forme de grille.
Par exemple, une carte avec une mise en page de conteneur et deux éléments de mise en page enfants peut se présenter comme suit :
Kotlin
private fun myLayout(): LayoutElement = Row.Builder() .setWidth(wrap()) .setHeight(expand()) .setVerticalAlignment(VALIGN_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(); }
Mises en page Material
Outre les mises en page de base, la bibliothèque protolayout-material
fournit quelques mises en page conçues pour contenir des éléments à des "emplacements" spécifiques.
PrimaryLayout
: positionne une seule action principaleCompactChip
en bas, avec le contenu centré au-dessus.MultiSlotLayout
: positionne les libellés principaux et secondaires avec du contenu facultatif entre les deux, et unCompactChip
facultatif en bas.MultiButtonLayout
: positionne un ensemble de boutons disposés selon les directives de Material.EdgeContentLayout
: positionne le contenu autour du bord de l'écran, par exempleCircularProgressIndicator
. Lorsque vous utilisez cette mise en page, les marges et les marges intérieures appropriées sont automatiquement appliquées au contenu.
Arcs de cercle
Les conteneurs enfants Arc
suivants sont acceptés :
ArcLine
: affiche une ligne courbe autour de l'arc.ArcText
: affiche du texte incurvé dans l'arc.ArcAdapter
: affiche un élément de mise en page de base dans l'arc, tracé à une tangente par rapport à l'arc.
Pour en savoir plus, consultez la documentation de référence de chacun des types d'éléments.
Modificateurs
Des modificateurs peuvent éventuellement être appliqués à chaque élément de mise en page disponible. Utilisez ces modificateurs aux fins suivantes :
- Modifier l'apparence visuelle de la mise en page. Par exemple, ajouter un arrière-plan, une bordure ou une marge intérieure à votre élément de mise en page.
- Ajouter des métadonnées sur la mise en page. Par exemple, ajouter un modificateur de sémantique à votre élément de mise en page pour l'utiliser avec des lecteurs d'écran.
- Ajouter des fonctionnalités. Par exemple, ajouter un modificateur cliquable à votre élément de mise en page pour rendre la carte interactive. Pour en savoir plus, consultez Interagir avec les cartes.
Nous pouvons, par exemple, personnaliser l'apparence et les métadonnées par défaut d'une Image
, comme indiqué dans l'exemple de code suivant :
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
Un Spannable
est un type de conteneur spécial qui dispose les éléments de la même manière que le texte. Cela s'avère utile lorsque vous souhaitez appliquer un style différent à une seule sous-chaîne d'un bloc de texte plus grand, ce qui n'est pas possible avec l'élément Text
.
Un conteneur Spannable
est rempli d'éléments enfants Span
. Les autres éléments enfants, ou instances Spannable
imbriquées, ne sont pas autorisés.
Il existe deux types d'éléments enfants Span
:
SpanText
: affiche le texte avec un style spécifique.SpanImage
: affiche une image en l'alignant sur le texte.
Par exemple, vous pouvez mettre en italique le mot "world" dans une carte "Hello world" et insérer une image entre les mots, comme indiqué dans l'exemple de code suivant :
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(); }
Utiliser des ressources
Les cartes n'ont accès à aucune des ressources de votre application. Cela signifie que vous ne pouvez pas transmettre un ID d'image Android à un élément de mise en page Image
et vous attendre à ce qu'il soit résolu. Au lieu de cela, remplacez la méthode onTileResourcesRequest()
et fournissez des ressources manuellement.
Pour fournir des images au sein de la méthode onTileResourcesRequest()
, vous pouvez procéder de deux façons :
- Fournissez une ressource drawable à l'aide de
setAndroidResourceByResId()
. - Fournissez une image dynamique en tant que
ByteArray
à l'aide desetInlineResource()
.
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() ); }
Recommandations personnalisées
- Remarque : Le texte du lien s'affiche lorsque JavaScript est désactivé
- Migrer vers les espaces de noms ProtoLayout
ConstraintLayout
dans Compose- Créer des blocs "Réglages rapides" personnalisés pour votre application