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'infoloisirs (IVI) cohérents dans les véhicules. Cet atelier de programmation vous présente car-ui-lib et vous explique comment utiliser les superpositions de ressources d'exécution (RRO) pour personnaliser les composants de la bibliothèque.

Points abordés

Procédure :

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

Cet atelier de programmation ne décrit pas en détail le fonctionnement des RRO. Pour en savoir plus, consultez Modifier la valeur des ressources d'une application au moment de l'exécution et Résoudre les problèmes de superposition de ressources au moment de l'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 paramètres restants.

     Nommez votre application
    Figure 2. Nommez 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 ressource 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 de lecture

La nouvelle application devrait s'ouvrir automatiquement sur votre émulateur ou votre appareil Android. Sinon, 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. Ouvrez 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 devraient 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 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 se présente 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 compiler l'application, appuyez sur le bouton vert Play (Exécuter) comme précédemment.

    Compiler l'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 en savoir plus sur les bases des RRO, consultez Modifier la valeur des ressources d'une application au moment de l'exécution.

Ajouter un contrôleur d'autorisation à votre application

Pour contrôler les ressources qu'un package RRO recouvre, 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 couche de 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 pourra pas le trouver.

    Pour en savoir plus sur les ressources superposables et leur configuration, consultez Restreindre 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 par "Hello World RRO" au lieu de "Hello World!".

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

    Vos configurations doivent ressembler à celles illustrées ci-dessous. L'emplacement où ils sont enregistrés peut varier :

  2. Une fois le projet CarUiRRO créé, 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>
    

    Cela génère une erreur avec @xml/sample_overlay. Le fichier resourcesMap mappe les noms de ressources du package cible au package RRO. Il est obligatoire de définir l'indicateur hasCode sur false 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'une version Gradle de RRO
  5. Pour compiler votre cible RRO, appuyez sur le bouton vert Play afin de créer une compilation 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 l'overlay de ressources est installé, mais qu'il contient des erreurs.
    • [X] signifie que l'ORR est installé et activé.

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

  7. Pour activer l'overlay de ressources 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".

Bonjour le monde !
Figure 4 : RRO Hello World !

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

Lorsque vous utilisez des RRO, vous pouvez utiliser les indicateurs Android Asset Packaging Tool (AAPT2) --no-resource-deduping et --no-resource-removal décrits dans 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 maux de tête liés au 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 Compiler 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 vif (#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 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 RRO pour chaque package cible que vous souhaitez RRO. Par exemple, lorsque vous créez des couches pour deux cibles différentes, vous devez créer deux APK de couche.

  3. Créez, vérifiez, installez et activez l'overlay de ressources de la même manière que précédemment.

Votre application se présente comme suit :

Nouvelle couleur d'arrière-plan de la barre d'outils
Figure 5 : Nouvelle couleur d'arrière-plan de la barre d'outils

Mises en page et styles des RRO

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 fichier res/layout/activity_main.xml et ajoutez-y le contenu suivant :

    <?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 au 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 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 RRO de la même manière qu'avant (bouton Play vert). Veillez à activer votre RRO.

L'application et le RRO s'affichent comme suit. Le texte "Hello World RRO" est vert et centré, comme spécifié dans le RRO de mise en page.

Hello World RRO
Figure 6 : RRO Hello World

Ajouter CarUiRecyclerView à votre application

Durée : 15 minutes

L'interface CarUiRecyclerView fournit des API permettant d'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, et 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 en tant que dépendance, vous pouvez créer et compiler votre fichier APK. Pour supprimer l'erreur, sélectionnez Fichier > Invalider les caches, puis cliquez sur 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 auparavant.

Vous voyez maintenant un CarUiRecyclerView :

CarUiRecyclerView
Figure 7  : CarUiRecyclerView

Utiliser un RRO pour supprimer la barre de défilement

Durée : 10 minutes

Cet exercice vous montre 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 la présence ou non de la barre de défilement optimisée pour les voitures avec boutons Haut et Bas dans CarUiRecyclerView. Lorsqu'il est défini sur false, CarUiRecyclerView 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 auparavant. 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 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 attributs d'ID et d'espace de noms au 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 suggérons d'examiner comment 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 couleur dans le dossier res/color/. Pour en savoir plus, consultez Style de code Java AOSP pour les contributeurs.

  2. Compilez et installez votre application comme auparavant. 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 un 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 et des rails gris
Figure 9. CarUiRecyclerView avec une barre de défilement bleue et des rails gris

Éléments de liste RRO

Durée : 15 minutes

Jusqu'à présent, vous avez appliqué un RRO aux composants car-ui-lib à l'aide de composants de framework (et non AndroidX). Pour utiliser des composants AndroidX dans un RRO, vous devez ajouter les dépendances de ce composant à l'application et au fichier build.gradle. du 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 ressembler à ceci :

<?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 d'être alignés à gauche.

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

Nous n'avons appliqué un RRO à car-ui-lib à l'aide des composants AndroidX (ConstraintLayout) que lorsque ses attributs étaient présents dans le fichier car-ui-lib nommé overlayable.xml ainsi que dans le RRO sample_overlay.xml. Il est possible de 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 d'effectuer un RRO sur 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 ont déjà été définis dans le overlayable.xml de la bibliothèque car-ui-lib, les ajouter au overlayable.xml de votre application avec car-ui-lib comme dépendance entraînerait une erreur mergeDebugResources semblable à 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'