Atelier de programmation: Créer des RRO avec des composants car-ui-lib à l'aide du système de compilation Gradle

Utilisez la bibliothèque car-ui-lib pour lancer des systèmes d'infodivertissement (IVI) intégrés au véhicule et cohérents. Cet atelier de programmation vous présente car-ui-lib et explique comment utiliser des superpositions de ressources d'exécution (RRO) pour personnaliser les composants de la bibliothèque.

Points abordés

Vous découvrirez comment effectuer les actions suivantes :

  • Incluez des composants car-ui-lib dans votre application Android.
  • Utilisez Gradle pour créer des applications Android et des RRO.
  • Utilisez des RRO avec car-ui-lib.

Cet atelier de programmation n'explique pas en détail le fonctionnement des RRO. Pour en savoir plus, consultez les pages Modifier la valeur des ressources d'une application au moment de l'exécution et Résoudre les problèmes liés aux superpositions de ressources d'exécution.

Avant de commencer

Prérequis

Avant de commencer, assurez-vous de disposer des éléments suivants:

Créer une application Android

Durée:15 minutes

Dans cette section, vous allez créer un projet Android Studio.

  1. Dans Android Studio, créez une application avec un EmptyActivity.

    Créer une activité vide
    Figure 1 : Créer une activité vide
  2. Nommez l'application CarUiCodelab, puis sélectionnez le langage Java. Vous pouvez également sélectionner un emplacement de fichier si vous le souhaitez. Acceptez les valeurs par défaut pour les autres paramètres.

     Nommer votre application
    Figure 2. Nommer votre application
  3. Remplacez activity_main.xml par le bloc de code suivant:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/sample_text"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    

    Ce bloc de code affiche la chaîne sample_text, qui n'est pas définie.

  4. Ajoutez la chaîne de ressources sample_text et définissez-la sur "Hello World!" dans votre fichier strings.xml. Pour ouvrir ce fichier, sélectionnez app > src > main > res > values > strings.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiCodelab</string>
        <string name="sample_text">Hello World!</string>
    </resources>
    
  5. Pour compiler votre application, cliquez sur le bouton vert Play (Lire) en haut à droite. L'APK est alors automatiquement installé sur votre émulateur ou votre appareil Android via Gradle.

    Bouton &quot;Lecture&quot;

La nouvelle application devrait s'ouvrir automatiquement sur votre émulateur ou votre appareil Android. Si ce n'est pas le cas, ouvrez l'application CarUiCodelab depuis le lanceur d'applications, qui est maintenant installé. Il se présente comme suit:

Ouvrir la nouvelle application CarUiCodelab
Figure 3. Ouvrir la nouvelle application CarUiCodelab

Ajouter car-ui-lib à votre application Android

Durée:15 minutes

Ajoutez car-ui-lib à votre application:

  1. Pour ajouter la dépendance car-ui-lib au fichier build.gradle de votre projet, sélectionnez app > build.gradle. Vos dépendances doivent se présenter comme suit:

    dependencies {
        implementation 'com.android.car.ui:car-ui-lib:2.0.0'
        implementation 'androidx.appcompat:appcompat:1.4.1'
        implementation 'com.google.android.material:material:1.4.0'
        implementation 'androidx.constraintlayout:constraintlayout:2.1.4'
    }
    

Utiliser les composants de la bibliothèque car-ui-lib dans votre application Android

Maintenant que vous avez car-ui-lib, ajoutez une barre d'outils à votre application.

  1. Dans votre fichier MainActivity.java, remplacez la méthode onCreate:

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        // Get the toolbar controller instance.
        ToolbarController toolbar = CarUi.getToolbar(this);
        // Set the title on toolbar.
        toolbar.setTitle(getTitle());
        // Set the logo to be shown with the title.
        toolbar.setLogo(R.mipmap.ic_launcher_round);
    }
    
  2. Veillez à importer ToolbarController:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Pour utiliser le thème Theme.CarUi.WithToolbar, sélectionnez app > src > main > AndroidManifest.xml, puis mettez à jour AndroidManifest.xml pour qu'il s'affiche comme suit:

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:tools="http://schemas.android.com/tools"
        package="com.example.caruicodelab">
    
        <application
            android:allowBackup="true"
            android:dataExtractionRules="@xml/data_extraction_rules"
            android:fullBackupContent="@xml/backup_rules"
            android:icon="@mipmap/ic_launcher"
            android:label="@string/app_name"
            android:roundIcon="@mipmap/ic_launcher_round"
            android:supportsRtl="true"
            android:theme="@style/Theme.CarUi.WithToolbar"
            tools:targetApi="31">
            <activity
                android:name=".MainActivity"
                android:exported="true">
                <intent-filter>
                    <action android:name="android.intent.action.MAIN" />
    
                    <category android:name="android.intent.category.LAUNCHER" />
                </intent-filter>
            </activity>
        </application>
    
    </manifest>
    
  4. Pour créer l'application, appuyez sur le bouton vert Play (Lire) comme précédemment.

    Créer l&#39;application

Ajouter des RRO à votre application

Durée:30 minutes

Si vous connaissez les RRO, passez à la section suivante, Ajouter un contrôleur d'autorisation à votre application. Sinon, pour découvrir les principes de base des RRO, consultez Modifier la valeur des ressources d'une application au moment de l'exécution.

Ajouter un contrôleur d'autorisations à votre application

Pour contrôler les ressources qu'un package RRO superpose, ajoutez un fichier nommé overlayable.xml au dossier /res de votre application. Ce fichier sert de contrôleur d'autorisation entre votre application (la cible) et votre package RRO (la superposition).

  1. Ajoutez res/values/overlayable.xml à votre application et copiez le contenu suivant dans votre fichier:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <overlayable name="CarUiCodelab">
            <policy type="public">
                <item type="string" name="sample_text"/>
            </policy>
        </overlayable>
    </resources>
    

    Étant donné que la chaîne sample_text doit pouvoir être superposée par un RRO, incluez le nom de la ressource dans le fichier overlayable.xml de l'application.

    Votre fichier overlayable.xml DOIT se trouver dans res/values/. Sinon, OverlayManagerService ne peut pas le localiser.

    Pour en savoir plus sur les ressources superposables et leur configuration, consultez la section Limiter les ressources superposables.

Créer un package RRO

Dans cette section, vous allez créer un package RRO pour remplacer la chaîne affichée ci-dessus de "Hello World!" par "Hello World RRO".

  1. Pour créer un projet, sélectionnez File > New > New Project (Fichier > Nouveau > Nouveau projet). Veillez à sélectionner Aucune activité au lieu d'"Activité vide", car les packages RRO ne contiennent que des ressources.

    Vos configurations ressemblent à celles illustrées ci-dessous. L'emplacement où elles sont enregistrées peut varier:

  2. Après avoir créé le projet CarUiRRO, déclarez-le comme RRO en modifiant AndroidManifest.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.caruirro">
    
        <application android:hasCode="false" />
    
        <uses-sdk
            android:minSdkVersion="29"
            android:targetSdkVersion="29"/>
    
        <overlay
            android:targetPackage="com.example.caruicodelab"
            android:targetName="CarUiCodelab"
            android:isStatic="false"
            android:resourcesMap="@xml/sample_overlay"
            />
    </manifest>
    

    Cette opération génère une erreur avec @xml/sample_overlay. Le fichier resourcesMap mappe les noms de ressources du package cible au package RRO. Définir l'indicateur hasCode sur false est obligatoire pour les packages RRO. De plus, les packages RRO ne sont pas autorisés à contenir des fichiers DEX.

  3. Copiez le bloc de code suivant dans …/res/xml/sample_overlay.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
    </overlay>
    
  4. Ajoutez sample_text à …/res/values/strings.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiRRO</string>
        <string name="sample_text">Hello World RRO</string>
    </resources>
    
    Création d&#39;un build Gradle de RRO
  5. Pour compiler votre cible RRO, appuyez sur le bouton vert Play (Lire) pour créer un build Gradle de votre RRO sur votre émulateur ou votre appareil Android.

  6. Pour vérifier que votre RRO est correctement installé, exécutez la commande suivante:

    shell:~$ adb shell cmd overlay list --user current | grep -i com.example
    com.example.caruicodelab
    [ ] com.example.caruirro
    

    Cette commande affiche des informations utiles sur l'état des packages RRO sur le système.

    • [ ] indique que le RRO est installé et prêt à être activé.
    • --- indique que le RRO est installé, mais contient des erreurs.
    • [X] signifie que le RRO est installé et activé.

    Si votre superposition de ressources d'exécution contient des erreurs, consultez la section Résoudre les problèmes liés aux superpositions de ressources d'exécution avant de continuer.

  7. Pour activer le RRO et vérifier qu'il est activé:

    shell:~$ adb shell cmd overlay enable --user current com.example.caruirro
    shell:~$ adb shell cmd overlay list --user current | grep -i com.example
    com.example.caruicodelab
    [x] com.example.caruirro
    

Votre application affiche la chaîne "Hello World RRO".

Hello World RRO !
Figure 4: Hello World RRO!

Félicitations ! Vous avez créé votre premier RRO.

Lorsque vous utilisez des RRO, vous pouvez utiliser les indicateurs --no-resource-deduping et --no-resource-removal d'Android Asset Packaging Tool (AAPT2) décrits dans la section Options de lien. Il n'est pas nécessaire d'ajouter les indicateurs dans cet atelier de programmation, mais nous vous suggérons de les utiliser dans vos RRO pour éviter la suppression de ressources (et les problèmes de débogage). Vous pouvez les ajouter au fichier build.gradle de votre RRO comme suit:

android {
    …
    aaptOptions {
        additionalParameters "--no-resource-deduping", "--no-resource-removal"
    }
}

Pour en savoir plus sur ces options, consultez les sections Créer le package et AAPT2.

Modifier les composants car-ui-lib à l'aide de RRO dans votre application Android

Cette page explique comment utiliser une superposition de ressources d'exécution (RRO) pour modifier les composants de la bibliothèque car-ui-lib dans votre application Android.

Définir la couleur d'arrière-plan de la barre d'outils

Durée:15 minutes

Pour modifier la couleur d'arrière-plan de la barre d'outils:

  1. Ajoutez la valeur suivante à votre application RRO et définissez la ressource sur vert clair (#0F0):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <drawable name="car_ui_toolbar_background">#0F0</drawable>
    </resources>
    

    La bibliothèque car-ui-lib contient une ressource nommée car_ui_toolbar_background. Lorsque cette ressource est contenue dans la configuration d'un RRO, la barre d'outils ne change pas, car la mauvaise valeur est ciblée.

  2. Dans le fichier AndroidManifest.xml de votre RRO, mettez à jour targetName pour qu'il pointe vers car-ui-lib:

    …
    android:targetName="car-ui-lib"
    …
    

    Vous devez créer un package de RRO pour chaque package cible que vous souhaitez utiliser. Par exemple, lorsque vous créez des superpositions pour deux cibles différentes, vous devez créer deux APK de superposition.

  3. Créez, vérifiez, installez et activez le RRO de la même manière que précédemment.

Votre application se présente comme suit:

Couleur de l&#39;arrière-plan de la nouvelle barre d&#39;outils
Figure 5: Nouvelle couleur d'arrière-plan de la barre d'outils

Mises en page et styles des ROP

Durée:15 minutes

Dans cet exercice, vous allez créer une application semblable à celle que vous avez créée précédemment. Cette application permet de superposer la mise en page. Suivez la même procédure que précédemment ou modifiez votre application existante.

  1. Veillez à ajouter les lignes suivantes à overlayable.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
      <overlayable name="CarUiCodelab">
        <policy type="public">
          <item type="string" name="sample_text"/>
          <item type="layout" name="activity_main"/>
          <item type="id" name="textView"/>
        </policy>
      </overlayable>
    </resources>
    
  2. Assurez-vous que activity_main.xml s'affiche comme suit:

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        xmlns:tools="http://schemas.android.com/tools"
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        tools:context=".MainActivity">
    
        <TextView
            android:id="@+id/textView"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:text="@string/sample_text"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  3. Dans votre application RRO, créez un res/layout/activity_main.xml et ajoutez les éléments suivants:

    <?xml version="1.0" encoding="utf-8"?>
    <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="match_parent"
        android:layout_height="match_parent">
      <TextView
          android:id="@+id/textView"
          android:layout_width="wrap_content"
          android:layout_height="wrap_content"
          android:text="@string/sample_text"
          android:textAppearance="@style/TextAppearance.CarUi"
          android:layout_gravity="center_vertical|center_horizontal"/>
    </FrameLayout>
    
  4. Mettez à jour res/values/styles.xml pour ajouter notre style à la RRO:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <style name="TextAppearance.CarUi" parent="android:TextAppearance.DeviceDefault">
            <item name="android:textColor">#0f0</item>
            <item name="android:textSize">100sp</item>
        </style>
    </resources>
    
  5. Modifiez le targetName dans AndroidManifest.xml pour qu'il pointe vers le nom de votre nouvelle application:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Ajoutez les ressources au fichier sample_overlay.xml de votre RRO:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
        <item target="id/textView" value="@id/textView"/>
        <item target="layout/activity_main" value="@layout/activity_main"/>
    </overlay>
    
  7. Créez et installez l'application et le RRO de la même manière qu'auparavant (bouton Play vert). Veillez à activer votre RRO.

L'application et le RRO s'affichent comme suit. Le texte Hello World de la disposition RRO est vert et centré, comme indiqué dans la disposition RRO.

RRO Hello World
Figure 6: Hello World RRO

Ajouter CarUiRecyclerView à votre application

Durée:15 minutes

L'interface CarUiRecyclerView fournit des API pour accéder à un RecyclerView personnalisé via des ressources car-ui-lib. Par exemple, CarUiRecyclerView vérifie un indicateur au moment de l'exécution pour déterminer si la barre de défilement doit être activée ou non, puis sélectionne la mise en page correspondante.

CarUiRecyclerViewContainer
Figure 7 : CarUiRecyclerViewContainer
  1. Pour ajouter un CarUiRecyclerView, ajoutez-le à vos fichiers activity_main.xml et MainActivity.java. Vous pouvez créer une application à partir de zéro ou modifier l'application existante. Si vous modifiez l'application existante, veillez à supprimer les ressources non déclarées de overlayable.xml.

    activity_main.xml

    <?xml version="1.0" encoding="utf-8"?>
    <com.android.car.ui.recyclerview.CarUiRecyclerView
        android:id="@+id/list"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>
    

    L'erreur suivante peut s'afficher, mais vous pouvez l'ignorer:

    Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerView

    Tant que votre classe est correctement orthographiée et que vous avez ajouté car-ui-lib comme dépendance, vous pouvez compiler et compiler votre APK. Pour supprimer l'erreur, sélectionnez File > Invalidate Caches (Fichier > Invalider les caches), puis cliquez sur Invalidate and Restart (Invalider et redémarrer).

    Ajoutez le code suivant à MainActivity.java

    package com.example.caruicodelab;
    
    import android.app.Activity;
    import android.os.Bundle;
    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.recyclerview.CarUiContentListItem;
    import com.android.car.ui.recyclerview.CarUiListItem;
    import com.android.car.ui.recyclerview.CarUiListItemAdapter;
    import com.android.car.ui.recyclerview.CarUiRecyclerView;
    import com.android.car.ui.toolbar.ToolbarController;
    import java.util.ArrayList;
    
    /** Activity with a simple car-ui layout. */
    public class MainActivity extends Activity {
    
        private final ArrayList<CarUiListItem> mData = new ArrayList<>();
        private CarUiListItemAdapter mAdapter;
    
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            setContentView(R.layout.activity_main);
            ToolbarController toolbar = CarUi.getToolbar(this);
            toolbar.setTitle(getTitle());
            toolbar.setLogo(R.mipmap.ic_launcher_round);
    
            CarUiRecyclerView recyclerView = findViewById(R.id.list);
            mAdapter = new CarUiListItemAdapter(generateSampleData());
            recyclerView.setAdapter(mAdapter);
        }
    
        private ArrayList<CarUiListItem> generateSampleData() {
            for (int i = 0; i < 20; i++) {
                CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.ICON);
                item.setTitle("Title " + i);
                item.setPrimaryIconType(CarUiContentListItem.IconType.CONTENT);
                item.setIcon(getDrawable(R.drawable.ic_launcher_foreground));
                item.setBody("body " + i);
                mData.add(item);
            }
            return mData;
    }
    
  2. Compilez et installez votre application comme d'habitude.

Un CarUiRecyclerView s'affiche alors:

CarUiRecyclerView
Figure 7 : CarUiRecyclerView

Utiliser une RRO pour supprimer la barre de défilement

Durée:10 minutes

Cet exercice vous explique comment utiliser un RRO pour supprimer la barre de défilement de CarUiRecyclerView.

  1. Dans votre RRO, ajoutez et modifiez les fichiers suivants:

    AndroidManifest.xml

    <?xml version="1.0" encoding="utf-8"?>
    <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.example.caruirro">
    
        <application android:hasCode="false" />
    
        <uses-sdk
            android:minSdkVersion="29"
            android:targetSdkVersion="29"/>
    
        <overlay
            android:targetPackage="com.example.caruicodelab"
            android:targetName="car-ui-lib"
            android:isStatic="false"
            android:resourcesMap="@xml/sample_overlay"
            />
    </manifest>
    

    res/values/bools.xml

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <bool name="car_ui_scrollbar_enable">false</bool>
    </resources>
    

    La ressource car_ui_scrollbar_enable est une ressource booléenne car-ui-lib, qui contrôle si la barre de défilement optimisée pour les voitures avec les boutons "Haut" et "Bas" dans CarUiRecyclerView est présente ou non. Lorsque CarUiRecyclerView est défini sur false, il se comporte comme un RecyclerView AndroidX.

    res/xml/sample_overlay.xml

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable"/>
    </overlay>
    

Compilez et installez votre application comme d'habitude. La barre de défilement est désormais supprimée de CarUiRecyclerView:

CarUiRecyclerView sans barre de défilement
Figure 8 : CarUiRecyclerView sans barre de défilement

Utiliser une mise en page pour superposer la barre de défilement de CarUiRecyclerView

Durée:15 minutes

Dans cet exercice, vous allez modifier la mise en page de la barre de défilement CarUiRecyclerView.

  1. Ajoutez et modifiez les fichiers suivants dans votre application RRO.

    res/layout/car_ui_recycler_view_scrollbar.xml

    <?xml version="1.0" encoding="utf-8"?>
    <RelativeLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:layout_width="112dp"
        android:layout_height="match_parent"
        android:id="@+id/car_ui_scroll_bar">
        <!-- View height is dynamically calculated during layout. -->
        <View
            android:id="@+id/car_ui_scrollbar_thumb"
            android:layout_width="6dp"
            android:layout_height="20dp"
            android:layout_alignParentTop="true"
            android:layout_centerHorizontal="true"
            android:background="@drawable/car_ui_recyclerview_scrollbar_thumb"/>
        <View
            android:id="@+id/car_ui_scrollbar_track"
            android:layout_width="10dp"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            android:layout_centerHorizontal="true"
            android:layout_above="@+id/car_ui_scrollbar_page_up"/>
        <View
            android:layout_width="2dp"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            android:background="#323232"
            android:layout_toLeftOf="@+id/car_ui_scrollbar_thumb"
            android:layout_above="@+id/car_ui_scrollbar_page_up"
            android:layout_marginRight="5dp"/>
        <View
            android:layout_width="2dp"
            android:layout_height="match_parent"
            android:layout_marginTop="10dp"
            android:background="#323232"
            android:layout_toRightOf="@+id/car_ui_scrollbar_thumb"
            android:layout_above="@+id/car_ui_scrollbar_page_up"
            android:layout_marginLeft="5dp"/>
        <ImageView
            android:id="@+id/car_ui_scrollbar_page_up"
            android:layout_width="75dp"
            android:layout_height="75dp"
            android:focusable="false"
            android:hapticFeedbackEnabled="false"
            android:src="@drawable/car_ui_recyclerview_ic_up"
            android:scaleType="centerInside"
            android:background="?android:attr/selectableItemBackgroundBorderless"
            android:layout_centerHorizontal="true"
            android:layout_above="@+id/car_ui_scrollbar_page_down"/>
        <ImageView
            android:id="@+id/car_ui_scrollbar_page_down"
            android:layout_width="75dp"
            android:layout_height="75dp"
            android:focusable="false"
            android:hapticFeedbackEnabled="false"
            android:src="@drawable/car_ui_recyclerview_ic_down"
            android:scaleType="centerInside"
            android:background="?android:attr/selectableItemBackgroundBorderless"
            android:layout_centerHorizontal="true"
            android:layout_alignParentBottom="true"/>
    </RelativeLayout>
    

    Pour superposer un fichier de mise en page, vous devez ajouter tous les ID et les attributs d'espace de noms à l'overlay.xml de votre RRO. Consultez les fichiers ci-dessous.

    res/xml/sample_overlay.xml

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
       <item target="drawable/car_ui_recyclerview_ic_down" value="@drawable/car_ui_recyclerview_ic_down"/>
       <item target="drawable/car_ui_recyclerview_ic_up" value="@drawable/car_ui_recyclerview_ic_up"/>
       <item target="drawable/car_ui_recyclerview_scrollbar_thumb" value="@drawable/car_ui_recyclerview_scrollbar_thumb"/>
       <item target="id/car_ui_scroll_bar" value="@id/car_ui_scroll_bar"/>
       <item target="id/car_ui_scrollbar_thumb" value="@id/car_ui_scrollbar_thumb"/>
       <item target="id/car_ui_scrollbar_track" value="@id/car_ui_scrollbar_track"/>
       <item target="id/car_ui_scrollbar_page_up" value="@id/car_ui_scrollbar_page_up"/>
       <item target="id/car_ui_scrollbar_page_down" value="@id/car_ui_scrollbar_page_down"/>
       <item target="layout/car_ui_recyclerview_scrollbar" value="@layout/car_ui_recyclerview_scrollbar"/>
    </overlay>
    

    res/drawable/car_ui_recyclerview_ic_up.xml

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="48.0"
        android:viewportHeight="48.0">
        <path
            android:pathData="M14.83,30.83L24,21.66l9.17,9.17L36,28 24,16 12,28z"
            android:fillColor="#0000FF"/>
    </vector>
    

    res/drawable/car_ui_recyclerview_ic_down.xml

    <?xml version="1.0" encoding="utf-8"?>
    <vector xmlns:android="http://schemas.android.com/apk/res/android"
        android:width="48dp"
        android:height="48dp"
        android:viewportWidth="48.0"
        android:viewportHeight="48.0">
        <path
            android:pathData="M14.83,16.42L24,25.59l9.17,-9.17L36,19.25l-12,12 -12,-12z"
            android:fillColor="#0000FF"/>
    </vector>
    

    res/drawable/car_ui_recyclerview_scrollbar_thumb.xml

    <?xml version="1.0" encoding="utf-8"?>
    <shape
        xmlns:android="http://schemas.android.com/apk/res/android"
        android:shape="rectangle">
        <solid android:color="#0000FF" />
        <corners android:radius="100dp"/>
    </shape>
    

    Nous vous recommandons d'examiner la façon dont ces fichiers interagissent.

    Pour plus de simplicité, les dimensions et les couleurs sont codées en dur. Toutefois, il est recommandé de déclarer ces valeurs dans dimens.xml et colors.xml, ou même de les désigner comme fichiers de couleurs dans le dossier res/color/. Pour en savoir plus, consultez le style de code Java AOSP pour les contributeurs.

  2. Compilez et installez votre application comme d'habitude. Vous avez créé CarUiRecyclerView avec une barre de défilement bleue et des rails gris.

Félicitations ! Les deux flèches apparaissent en bas de la barre de défilement. Vous avez appliqué avec succès une RRO à un fichier de ressources de mise en page car-ui-lib à l'aide du système de compilation Gradle via Android Studio.

CarUiRecyclerView avec une barre de défilement bleue avec des rails gris
Figure 9. CarUiRecyclerView avec une barre de défilement bleue avec des rails gris

Éléments de liste RRO

Durée:15 minutes

À ce stade, vous avez appliqué un RRO aux composants car-ui-lib à l'aide de composants de framework (et non d'AndroidX). Pour utiliser des composants AndroidX dans une RRO, vous devez ajouter les dépendances de ce composant à la fois à l'application et à la build.gradle. de la RRO. Vous devez également ajouter le attrs de ce composant à overlayable.xml dans votre application, ainsi que le sample_overlay.xml dans votre RRO.

Notre bibliothèque (car-ui-lib) utilise ConstraintLayout ainsi que d'autres composants AndroidX. Son overlayable.xml peut donc se présenter comme suit:

<?xml version='1.0' encoding='UTF-8'?>
<resources>
    <overlayable name="car-ui-lib">
        
        <item type="attr" name="layout_constraintBottom_toBottomOf"/>
        <item type="attr" name="layout_constraintBottom_toTopOf"/>
        <item type="attr" name="layout_constraintCircle"/>
        <item type="attr" name="layout_constraintCircleAngle"/>
        <item type="attr" name="layout_constraintCircleRadius"/>
        <item type="attr" name="layout_constraintDimensionRatio"/>
        <item type="attr" name="layout_constraintEnd_toEndOf"/>
        <item type="attr" name="layout_constraintEnd_toStartOf"/>
        <item type="attr" name="layout_constraintGuide_begin"/>
        <item type="attr" name="layout_constraintGuide_end"/>
        <item type="attr" name="layout_constraintGuide_percent"/>
        <item type="attr" name="layout_constraintHeight_default"/>
        <item type="attr" name="layout_constraintHeight_max"/>
        <item type="attr" name="layout_constraintHeight_min"/>
        <item type="attr" name="layout_constraintHeight_percent"/>
        <item type="attr" name="layout_constraintHorizontal_bias"/>
        <item type="attr" name="layout_constraintHorizontal_chainStyle"/>
        <item type="attr" name="layout_constraintHorizontal_weight"/>
        <item type="attr" name="layout_constraintLeft_creator"/>
        <item type="attr" name="layout_constraintLeft_toLeftOf"/>
        <item type="attr" name="layout_constraintLeft_toRightOf"/>
        <item type="attr" name="layout_constraintRight_creator"/>
        <item type="attr" name="layout_constraintRight_toLeftOf"/>
        <item type="attr" name="layout_constraintRight_toRightOf"/>
        <item type="attr" name="layout_constraintStart_toEndOf"/>
        <item type="attr" name="layout_constraintStart_toStartOf"/>
        <item type="attr" name="layout_constraintTag"/>
        <item type="attr" name="layout_constraintTop_creator"/>
        <item type="attr" name="layout_constraintTop_toBottomOf"/>
        <item type="attr" name="layout_constraintTop_toTopOf"/>
        <item type="attr" name="layout_constraintVertical_bias"/>
        <item type="attr" name="layout_constraintVertical_chainStyle"/>
        
    </overlayable>
</resources>
  1. Modifiez la mise en page des éléments de la liste dans CarUiRecyclerView à l'aide de ConstraintLayout. Ajoutez ou modifiez les fichiers suivants dans votre RRO:

    res/xml/sample_overlay.xml

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
       <item target="id/car_ui_list_item_touch_interceptor" value="@id/car_ui_list_item_touch_interceptor"/>
       <item target="id/car_ui_list_item_reduced_touch_interceptor" value="@id/car_ui_list_item_reduced_touch_interceptor"/>
       <item target="id/car_ui_list_item_start_guideline" value="@id/car_ui_list_item_start_guideline"/>
       <item target="id/car_ui_list_item_icon_container" value="@id/car_ui_list_item_icon_container"/>
       <item target="id/car_ui_list_item_icon" value="@id/car_ui_list_item_icon"/>
       <item target="id/car_ui_list_item_content_icon" value="@id/car_ui_list_item_content_icon"/>
       <item target="id/car_ui_list_item_avatar_icon" value="@id/car_ui_list_item_avatar_icon"/>
       <item target="id/car_ui_list_item_title" value="@id/car_ui_list_item_title"/>
       <item target="id/car_ui_list_item_body" value="@id/car_ui_list_item_body"/>
       <item target="id/car_ui_list_item_action_container_touch_interceptor" value="@id/car_ui_list_item_action_container_touch_interceptor"/>
       <item target="id/car_ui_list_item_action_container" value="@id/car_ui_list_item_action_container"/>
       <item target="id/car_ui_list_item_action_divider" value="@id/car_ui_list_item_action_divider"/>
       <item target="id/car_ui_list_item_switch_widget" value="@id/car_ui_list_item_switch_widget"/>
       <item target="id/car_ui_list_item_checkbox_widget" value="@id/car_ui_list_item_checkbox_widget"/>
       <item target="id/car_ui_list_item_radio_button_widget" value="@id/car_ui_list_item_radio_button_widget"/>
       <item target="id/car_ui_list_item_supplemental_icon" value="@id/car_ui_list_item_supplemental_icon"/>
       <item target="id/car_ui_list_item_end_guideline" value="@id/car_ui_list_item_end_guideline"/>
       <item target="attr/layout_constraintBottom_toBottomOf" value="@attr/layout_constraintBottom_toBottomOf"/>
       <item target="attr/layout_constraintBottom_toTopOf" value="@attr/layout_constraintBottom_toTopOf"/>
       <item target="attr/layout_constraintEnd_toEndOf" value="@attr/layout_constraintEnd_toEndOf"/>
       <item target="attr/layout_constraintEnd_toStartOf" value="@attr/layout_constraintEnd_toStartOf"/>
       <item target="attr/layout_constraintGuide_begin" value="@attr/layout_constraintGuide_begin"/>
       <item target="attr/layout_constraintGuide_end" value="@attr/layout_constraintGuide_end"/>
       <item target="attr/layout_constraintHorizontal_bias" value="@attr/layout_constraintHorizontal_bias"/>
       <item target="attr/layout_constraintLeft_toLeftOf" value="@attr/layout_constraintLeft_toLeftOf"/>
       <item target="attr/layout_constraintLeft_toRightOf" value="@attr/layout_constraintLeft_toRightOf"/>
       <item target="attr/layout_constraintRight_toLeftOf" value="@attr/layout_constraintRight_toLeftOf"/>
       <item target="attr/layout_constraintRight_toRightOf" value="@attr/layout_constraintRight_toRightOf"/>
       <item target="attr/layout_constraintStart_toEndOf" value="@attr/layout_constraintStart_toEndOf"/>
       <item target="attr/layout_constraintStart_toStartOf" value="@attr/layout_constraintStart_toStartOf"/>
       <item target="attr/layout_constraintTop_toBottomOf" value="@attr/layout_constraintTop_toBottomOf"/>
       <item target="attr/layout_constraintTop_toTopOf" value="@attr/layout_constraintTop_toTopOf"/>
       <item target="attr/layout_goneMarginBottom" value="@attr/layout_goneMarginBottom"/>
       <item target="attr/layout_goneMarginEnd" value="@attr/layout_goneMarginEnd"/>
       <item target="attr/layout_goneMarginLeft" value="@attr/layout_goneMarginLeft"/>
       <item target="attr/layout_goneMarginRight" value="@attr/layout_goneMarginRight"/>
       <item target="attr/layout_goneMarginStart" value="@attr/layout_goneMarginStart"/>
       <item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/>
       <item target="attr/layout_constraintVertical_chainStyle" value="@attr/layout_constraintVertical_chainStyle"/>
       <item target="layout/car_ui_list_item" value="@layout/car_ui_list_item"/>
    </overlay>
    

    res/layout/car_ui_list_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:tag="carUiListItem"
        android:minHeight="@dimen/car_ui_list_item_height">
    
        <!-- The following touch interceptor views are sized to encompass the specific sub-sections of
        the list item view to easily control the bounds of a background ripple effects. -->
        <com.android.car.ui.SecureView
            android:id="@+id/car_ui_list_item_touch_interceptor"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/car_ui_list_item_background"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <!-- This touch interceptor does not include the action container -->
        <com.android.car.ui.SecureView
            android:id="@+id/car_ui_list_item_reduced_touch_interceptor"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/car_ui_list_item_background"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/car_ui_list_item_action_container"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/car_ui_list_item_start_guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_begin="@dimen/car_ui_list_item_start_inset" />
    
        <FrameLayout
            android:id="@+id/car_ui_list_item_icon_container"
            android:layout_width="@dimen/car_ui_list_item_icon_container_width"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="@+id/car_ui_list_item_start_guideline"
            app:layout_constraintTop_toTopOf="parent">
    
            <ImageView
                android:id="@+id/car_ui_list_item_icon"
                android:layout_width="@dimen/car_ui_list_item_icon_size"
                android:layout_height="@dimen/car_ui_list_item_icon_size"
                android:layout_gravity="center"
                android:visibility="gone"
                android:scaleType="fitCenter" />
    
            <ImageView
                android:id="@+id/car_ui_list_item_content_icon"
                android:layout_width="@dimen/car_ui_list_item_content_icon_width"
                android:layout_height="@dimen/car_ui_list_item_content_icon_height"
                android:layout_gravity="center"
                android:visibility="gone"
                android:scaleType="fitCenter" />
    
            <ImageView
                android:id="@+id/car_ui_list_item_avatar_icon"
                android:background="@drawable/car_ui_list_item_avatar_icon_outline"
                android:layout_width="@dimen/car_ui_list_item_avatar_icon_width"
                android:layout_height="@dimen/car_ui_list_item_avatar_icon_height"
                android:layout_gravity="center"
                android:visibility="gone"
                android:scaleType="fitCenter" />
        </FrameLayout>
    
        <CarUiTextView
            android:id="@+id/car_ui_list_item_title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin"
            android:singleLine="@bool/car_ui_list_item_single_line_title"
            android:textAppearance="@style/TextAppearance.CarUi.ListItem"
            android:layout_gravity="right"
            android:gravity="right"
            android:textAlignment="viewEnd"
            app:layout_constraintBottom_toTopOf="@+id/car_ui_list_item_body"
            app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container"
            app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_chainStyle="packed"
            app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" />
        <CarUiTextView
            android:id="@+id/car_ui_list_item_body"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin"
            android:textAppearance="@style/TextAppearance.CarUi.ListItem.Body"
            android:layout_gravity="right"
            android:gravity="right"
            android:textAlignment="viewEnd"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container"
            app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container"
            app:layout_constraintTop_toBottomOf="@+id/car_ui_list_item_title"
            app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" />
    
        <!-- This touch interceptor is sized and positioned to encompass the action container   -->
        <com.android.car.ui.SecureView
            android:id="@+id/car_ui_list_item_action_container_touch_interceptor"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/car_ui_list_item_background"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="@id/car_ui_list_item_action_container"
            app:layout_constraintEnd_toEndOf="@id/car_ui_list_item_action_container"
            app:layout_constraintStart_toStartOf="@id/car_ui_list_item_action_container"
            app:layout_constraintTop_toTopOf="@id/car_ui_list_item_action_container" />
    
        <FrameLayout
            android:id="@+id/car_ui_list_item_action_container"
            android:layout_width="wrap_content"
            android:minWidth="@dimen/car_ui_list_item_icon_container_width"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="@+id/car_ui_list_item_end_guideline"
            app:layout_constraintTop_toTopOf="parent">
    
            <View
                android:id="@+id/car_ui_list_item_action_divider"
                android:layout_width="@dimen/car_ui_list_item_action_divider_width"
                android:layout_height="@dimen/car_ui_list_item_action_divider_height"
                android:layout_gravity="start|center_vertical"
                android:background="@drawable/car_ui_list_item_divider" />
    
            <Switch
                android:id="@+id/car_ui_list_item_switch_widget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:clickable="false"
                android:focusable="false" />
    
            <CheckBox
                android:id="@+id/car_ui_list_item_checkbox_widget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:clickable="false"
                android:focusable="false" />
    
            <RadioButton
                android:id="@+id/car_ui_list_item_radio_button_widget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:clickable="false"
                android:focusable="false" />
    
            <ImageView
                android:id="@+id/car_ui_list_item_supplemental_icon"
                android:layout_width="@dimen/car_ui_list_item_supplemental_icon_size"
                android:layout_height="@dimen/car_ui_list_item_supplemental_icon_size"
                android:layout_gravity="center"
                android:scaleType="fitCenter" />
        </FrameLayout>
    
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/car_ui_list_item_end_guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_end="@dimen/car_ui_list_item_end_inset" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. car_ui_list_item.xml fait référence à plusieurs composants/ressources qui ne sont pas inclus en tant que dépendances de l'application. Il s'agit de ressources car-ui-lib. Pour résoudre ce problème, ajoutez car-ui-lib en tant que dépendance à votre application RRO dans app/build.gradle:

    dependencies {
        implementation 'com.android.car.ui:car-ui-lib:2.0.0'
        implementation 'androidx.appcompat:appcompat:1.4.1'
        implementation 'com.google.android.material:material:1.4.0'
    }
    

Le titre et le corps du texte sont désormais alignés à droite au lieu de l'être à gauche.

Titre et corps alignés à droite
Figure 10. Titre et corps alignés à droite

Nous n'avons appliqué une RRO à car-ui-lib qu'à l'aide de composants AndroidX (ConstraintLayout) lorsque ses attributs étaient présents dans le fichier car-ui-lib nommé overlayable.xml ainsi que dans la RRO sample_overlay.xml. Vous pouvez faire quelque chose de similaire dans votre propre application. Il vous suffit d'ajouter tous les attrs correspondants au overlayable.xml de votre application, comme pour car-ui-lib.

Toutefois, il n'est pas possible de RRO une application utilisant des composants AndroidX lorsque l'application a car-ui-lib comme dépendance dans son build.gradle (lorsque l'application utilise des composants car-ui-lib). Étant donné que les mappages d'attributs étaient déjà définis dans le fichier overlayable.xml de la bibliothèque car-ui-lib, les ajouter au fichier overlayable.xml de votre application avec car-ui-lib en tant que dépendance entraînerait une erreur mergeDebugResources comme celle ci-dessous. En effet, ces attributs sont présents dans plusieurs fichiers overlayable.xml:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'