Codelab: creare RRO con componenti car-ui-lib utilizzando il sistema di build Gradle

Utilizza la libreria car-ui-lib per avviare sistemi di infotainment (IVI) coerenti, in-vehicle. Questo codelab introduce car-ui-lib e mostra come utilizzare gli overlay delle risorse di runtime (RRO) per personalizzare i componenti della libreria.

Obiettivi didattici

Procedura:

  • Includi i componenti car-ui-lib nella tua app per Android.
  • Utilizza Gradle per creare app Android e RRO.
  • Utilizzare gli overlay di risorse di runtime con car-ui-lib.

Questo codelab non descrive in dettaglio il funzionamento degli RRO. Per saperne di più, consulta Modificare il valore delle risorse di un'app in fase di runtime e Risolvere i problemi relativi alle sovrapposizioni delle risorse in fase di runtime.

Prima di iniziare

Prerequisiti

Prima di iniziare, assicurati di avere:

  • Computer con riga di comando (macchina Linux, Mac o Windows con Windows Subsystem for Linux).

  • Android Studio.

  • Dispositivo Android o emulatore connesso al tuo computer. Consulta Scarica l'origine Android e Crea Android.

  • Conoscenza di base degli overlay delle risorse di runtime.

Crea una nuova app per Android

Durata: 15 minuti

In questa sezione, crei un nuovo progetto Android Studio.

  1. In Android Studio crea un'app con un EmptyActivity.

    Crea un'attività vuota
    Figura 1.Crea un'attività vuota
  2. Assegna un nome all'app CarUiCodelab e poi seleziona il linguaggio Java. Se vuoi, puoi selezionare anche una posizione del file. Accetta i valori predefiniti per le impostazioni rimanenti.

     Assegna un nome all'app
    Figura 2. Assegna un nome all'app
  3. Sostituisci activity_main.xml con il seguente blocco di codice:

    <?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>
    

    Questo blocco di codice mostra la stringa sample_text, che non è definita.

  4. Aggiungi la stringa di risorse sample_text e impostala su "Hello World!" nel file strings.xml. Per aprire questo file, seleziona 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. Per creare l'app, fai clic sul pulsante verde Riproduci in alto a destra. In questo modo, l'APK viene installato automaticamente sull'emulatore o sul dispositivo Android tramite Gradle.

    Pulsante di riproduzione

La nuova app dovrebbe aprirsi automaticamente sull'emulatore o sul dispositivo Android. In caso contrario, apri l'app CarUiCodelab da Avvio app, che ora è installata. Ecco come appare:

Apri la nuova app CarUiCodelab
Figura 3. Apri la nuova app CarUiCodelab

Aggiungere car-ui-lib alla tua app per Android

Durata: 15 minuti

Aggiungi car-ui-lib alla tua app:

  1. Per aggiungere la dipendenza car-ui-lib al file build.gradle del progetto, seleziona app > build.gradle. Le dipendenze dovrebbero essere visualizzate nel seguente modo:

    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'
    }
    

Utilizzare i componenti di car-ui-lib nell'app per Android

Ora che hai car-ui-lib, aggiungi una barra degli strumenti alla tua app.

  1. Nel file MainActivity.java, sovrascrivi il metodo 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. Assicurati di importare ToolbarController:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Per utilizzare il tema Theme.CarUi.WithToolbar, seleziona app > src > main > AndroidManifest.xml e poi aggiorna AndroidManifest.xml in modo che venga visualizzato come segue:

    <?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. Per creare l'app, premi il pulsante verde Riproduci come prima.

    Crea l'app

Aggiungere RRO alla tua app

Durata: 30 minuti

Se hai familiarità con gli RRO, vai alla sezione successiva, Aggiungi un controller delle autorizzazioni alla tua app. Altrimenti, per scoprire le nozioni di base degli RRO, consulta Modificare il valore delle risorse di un'app in fase di runtime.

Aggiungere un controller delle autorizzazioni all'app

Per controllare quali risorse sovrappone un pacchetto RRO, aggiungi un file denominato overlayable.xml alla cartella /res della tua app. Questo file funge da controller delle autorizzazioni tra la tua app (il target) e il tuo pacchetto RRO (l'overlay).

  1. Aggiungi res/values/overlayable.xml alla tua app e copia i seguenti contenuti nel file:

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

    Poiché la stringa sample_text deve essere sovrapponibile da un RRO, includi il nome della risorsa in overlayable.xml dell'app.

    Il file overlayable.xml DEVE trovarsi in res/values/. In caso contrario, il OverlayManagerService non riesce a trovarlo.

    Per saperne di più sulle risorse sovrapponibili e su come possono essere configurate, consulta Limitare le risorse sovrapponibili.

Crea un pacchetto RRO

In questa sezione, crei un pacchetto RRO per modificare la stringa visualizzata sopra da "Hello World!" a "Hello World RRO".

  1. Per creare un nuovo progetto, seleziona File > Nuovo > Nuovo progetto. Assicurati di selezionare Nessuna attività anziché Attività vuota, poiché i pacchetti RRO contengono solo risorse.

    Le configurazioni vengono visualizzate in modo simile a quelle illustrate di seguito. La posizione in cui vengono salvati può variare:

  2. Dopo aver creato il nuovo progetto CarUiRRO, dichiaralo come RRO modificando 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>
    

    In questo modo si genera un errore con @xml/sample_overlay. Il file resourcesMap mappa i nomi delle risorse dal pacchetto di destinazione al pacchetto RRO. L'impostazione del flag hasCode su false è obbligatoria per i pacchetti RRO. Inoltre, i pacchetti RRO non possono contenere file DEX.

  3. Copia il seguente blocco di codice in …/res/xml/sample_overlay.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
    </overlay>
    
  4. Aggiungi sample_text a …/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>
    
    Creata build Gradle di RRO
  5. Per creare la destinazione RRO, premi il pulsante verde Riproduci per creare una build Gradle del tuo RRO sull'emulatore o sul dispositivo Android.

  6. Per verificare che l'RRO sia installato correttamente, esegui:

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

    Questo comando mostra informazioni utili sullo stato dei pacchetti RRO sul sistema.

    • [ ] indica che l'RRO è installato e pronto per essere attivato.
    • --- indica che l'RRO è installato, ma contiene errori.
    • [X] significa che l'RRO è installato e attivato.

    Se l'RRO contiene errori, consulta la sezione Risolvere i problemi relativi alle overlay delle risorse di runtime prima di continuare.

  7. Per attivare l'RRO e verificare che sia attivo:

    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
    

La tua app mostra la stringa "Hello World RRO".

Hello World RRO!
Figura 4: Hello World RRO!

Complimenti! Hai creato il tuo primo RRO.

Quando utilizzi le sovrapposizioni di risorse, potresti voler utilizzare i flag --no-resource-deduping e --no-resource-removal di Android Asset Packaging Tool (AAPT2) descritti in Opzioni di collegamento. Non è necessario aggiungere i flag in questo codelab, ma ti consigliamo di utilizzarli nelle tue RRO per evitare la rimozione delle risorse (e problemi di debug). Puoi aggiungerli al file build.gradle del tuo RRO nel seguente modo:

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

Per saperne di più su questi flag, consulta Crea il pacchetto e AAPT2.

Modificare i componenti car-ui-lib utilizzando gli overlay di risorse in fase di runtime nell'app per Android

Questa pagina descrive come utilizzare una risorsa di overlay di runtime (RRO) per modificare i componenti della libreria car-ui-lib nella tua app per Android.

Impostare il colore di sfondo della barra degli strumenti

Durata: 15 minuti

Per modificare il colore di sfondo della barra degli strumenti:

  1. Aggiungi il seguente valore all'app RRO e imposta la risorsa su verde brillante (#0F0):

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

    La libreria car-ui-lib contiene una risorsa denominata car_ui_toolbar_background. Quando questa risorsa è contenuta nella configurazione di un RRO, la barra degli strumenti non cambia perché viene selezionato il valore errato.

  2. Nel AndroidManifest.xml per il tuo RRO, aggiorna targetName in modo che rimandi a car-ui-lib:

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

    DEVI creare un nuovo pacchetto RRO per ogni pacchetto di destinazione per cui vuoi eseguire l'RRO. Ad esempio, quando crei overlay per due target diversi, devi creare due APK di overlay.

  3. Crea, verifica, installa e attiva l'RRO nello stesso modo di prima.

La tua app viene visualizzata in questo modo:

Colore sfondo nuova barra degli strumenti
Figura 5: nuovo colore di sfondo della barra degli strumenti

Layout e stili RRO

Durata: 15 minuti

In questo esercizio, creerai una nuova app simile a quella creata in precedenza. Questa app consente di sovrapporre il layout. Segui la stessa procedura di prima o modifica l'app esistente.

  1. Assicurati di aggiungere le seguenti righe a 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. Assicurati che activity_main.xml venga visualizzato come segue:

    <?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. Nella tua app RRO, crea un res/layout/activity_main.xml e aggiungi quanto segue:

    <?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. Aggiorna res/values/styles.xml per aggiungere il nostro stile al 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. Modifica targetName in AndroidManifest.xml in modo che rimandi al nome della tua nuova app:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Aggiungi le risorse al file sample_overlay.xml nel tuo 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. Crea e installa l'app e l'RRO nello stesso modo di prima (pulsante Play verde). Assicurati di attivare il tuo RRO.

L'app e l'RRO vengono visualizzati come segue. Il testo RRO Hello World è verde ed è centrato come specificato nel RRO di layout.

Hello World RRO
Figura 6: Hello World RRO

Aggiungere CarUiRecyclerView alla tua app

Durata: 15 minuti

L'interfaccia CarUiRecyclerView fornisce API per accedere a un RecyclerView personalizzato tramite le risorse car-ui-lib. Ad esempio, CarUiRecyclerView controlla un flag in fase di runtime per determinare se la barra di scorrimento deve essere attivata o meno e seleziona il layout corrispondente.

CarUiRecyclerViewContainer
Figura 7. CarUiRecyclerViewContainer
  1. Per aggiungere un CarUiRecyclerView, aggiungilo ai file activity_main.xml e MainActivity.java. Puoi creare una nuova app da zero o modificare l'app esistente. Se modifichi l'app esistente, assicurati di rimuovere le risorse non dichiarate da 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"/>
    

    Potrebbe essere visualizzato il seguente errore, che puoi ignorare:

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

    Se la classe è scritta correttamente e hai aggiunto car-ui-lib come dipendenza, puoi creare e compilare l'APK. Per rimuovere l'errore, seleziona File > Invalida cache, poi fai clic su Invalida e riavvia.

    Aggiungi quanto segue a 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. Crea e installa l'app come prima.

Ora vedi un CarUiRecyclerView:

CarUiRecyclerView
Figura 7 : CarUiRecyclerView

Utilizzare un RRO per rimuovere la barra di scorrimento

Durata: 10 minuti

Questo esercizio mostra come utilizzare un RRO per rimuovere la barra di scorrimento da CarUiRecyclerView.

  1. Nel tuo RRO, aggiungi e modifica i seguenti file:

    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 risorsa car_ui_scrollbar_enable è una risorsa booleana car-ui-lib, che controlla la presenza o meno della barra di scorrimento ottimizzata per l'auto con i pulsanti Su e Giù in CarUiRecyclerView. Se impostato su false, CarUiRecyclerView si comporta come 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>
    

Crea e installa l'app come prima. La barra di scorrimento è stata rimossa da CarUiRecyclerView:

CarUiRecyclerView senza barra di scorrimento
Figura 8. CarUiRecyclerView senza barra di scorrimento

Utilizza un layout per sovrapporre la barra di scorrimento di CarUiRecyclerView

Durata: 15 minuti

In questo esercizio, modifichi il layout della barra di scorrimento CarUiRecyclerView.

  1. Aggiungi e modifica i seguenti file nell'app 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>
    

    Per sovrapporre un file di layout, devi aggiungere tutti gli ID e gli attributi dello spazio dei nomi a overlay.xml del tuo RRO. Vedi i file di seguito.

    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>
    

    Ti consigliamo di esaminare l'interazione tra questi file.

    Per semplicità, le dimensioni e i colori sono codificati. Tuttavia, una best practice consiste nel dichiarare questi valori in dimens.xml e colors.xml o anche designati come file di colori nella cartella res/color/. Per saperne di più, consulta Stile del codice Java AOSP per i collaboratori.

  2. Crea e installa l'app come prima. Hai creato CarUiRecyclerView con una barra di scorrimento blu e binari grigi.

Complimenti! Entrambe le frecce vengono visualizzate nella parte inferiore della barra di scorrimento. Hai applicato correttamente un RRO a un file di risorse di layout car-ui-lib utilizzando il sistema di build Gradle tramite Android Studio.

CarUiRecyclerView con una barra di scorrimento blu con guide grigie
Figura 9. CarUiRecyclerView con una barra di scorrimento blu con guide grigie

Voci elenco RRO

Durata: 15 minuti

Finora, hai applicato un RRO ai componenti car-ui-lib utilizzando i componenti del framework (non AndroidX). Per utilizzare i componenti AndroidX in un RRO, devi aggiungere le dipendenze del componente sia all'app sia all'RRO build.gradle. Devi anche aggiungere attrs del componente a overlayable.xml nella tua app, nonché sample_overlay.xml nel tuo RRO.

La nostra libreria (car-ui-lib) utilizza ConstraintLayout e altri componenti AndroidX, quindi il suo overlayable.xml potrebbe avere questo aspetto:

<?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. Modifica il layout degli elementi dell'elenco in CarUiRecyclerView utilizzando ConstraintLayout. Aggiungi o modifica i seguenti file nel tuo 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 fa riferimento a diversi componenti/risorse che non sono inclusi come dipendenze dell'app. Si tratta di risorse car-ui-lib. Puoi risolvere il problema aggiungendo car-ui-lib come dipendenza all'app RRO in 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'
    }
    

Il titolo e il corpo sono ora allineati a destra anziché a sinistra.

Titolo e corpo allineati a destra
Figura 10. Titolo e corpo allineati a destra

Abbiamo applicato un RRO solo a car-ui-lib utilizzando i componenti AndroidX (ConstraintLayout) quando i relativi attributi erano presenti nel file car-ui-lib denominato overlayable.xml e nell'RRO sample_overlay.xml. È possibile fare qualcosa di simile nella tua app. Basta aggiungere tutti i attrs corrispondenti al overlayable.xml della tua app, in modo simile a car-ui-lib.

Tuttavia, non è possibile eseguire l'RRO di un'app utilizzando i componenti AndroidX quando l'app ha car-ui-lib come dipendenza nel relativo build.gradle (quando l'app utilizza i componenti car-ui-lib). Poiché le mappature degli attributi sono già state definite in car-ui-lib di overlayable.xml, aggiungerle a overlayable.xml della tua app con car-ui-lib come dipendenza causerebbe un errore mergeDebugResources come quello riportato di seguito. Questo perché questi attributi sono presenti in più file overlayable.xml:

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