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

Usa la libreria car-ui-lib per avviare in modo coerente, nel veicolo e di infotainment (IVI). Questo codelab ti introduce a car-ui-lib e a come puoi utilizzare gli overlay di risorse runtime per personalizzare i componenti della libreria.

Cosa imparerai a fare

Istruzioni:

  • Includi componenti car-ui-lib nella tua app per Android.
  • Usa Gradle per creare app per Android e RRO.
  • Utilizza RRO con car-ui-lib.

Questo codelab non descrive in dettaglio il funzionamento degli RRO. Consulta Modificare il valore delle risorse di un'app in fase di runtime e Risoluzione dei problemi relativi agli overlay delle risorse di runtime per saperne di più.

Prima di iniziare

Prerequisiti

Prima di iniziare, assicurati di avere:

Crea una nuova app per Android

Durata: 15 minuti

In questa sezione creerai un nuovo progetto Android Studio.

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

    Crea un'attività vuota
    Figura 1.Creazione di un'attività vuota
  2. Assegna all'app il nome CarUiCodelab, quindi seleziona il linguaggio Java. Puoi seleziona anche la posizione del file, se vuoi. Accetta i valori predefiniti per le altre impostazioni.

     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 visualizza la stringa sample_text, che non è definita.

  4. Aggiungi la stringa della risorsa sample_text e impostala su "Hello World!". nel tuo strings.xml file. Per aprire questo file, seleziona app > src > principale > res > valori > stringhe.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 la tua app, fai clic sul pulsante verde Riproduci in alto a destra. In questo modo installa automaticamente l'APK sull'emulatore o sul dispositivo Android tramite Gradle,

    Pulsante Riproduci

La nuova app dovrebbe aprirsi automaticamente sull'emulatore o sul dispositivo Android. Se non devi aprire l'app CarUiCodelab da Avvio applicazioni, che è stata installata. L'URL avrà il seguente aspetto:

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

Aggiungi 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 simili alle seguenti:

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

Utilizza i componenti car-ui-lib nella tua 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 > principale > AndroidManifest.xml, quindi aggiorna AndroidManifest.xml affinché appaia 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&#39;app

Aggiungi RRO all'app

Durata: 30 minuti

Se hai familiarità con gli RRO, vai al prossimo sezione, Aggiungi un controller delle autorizzazioni all'app. In caso contrario, per apprendere le nozioni di base sugli RRO, consulta Modifica il valore delle risorse di un'app in fase di runtime.

Aggiungere un controller di autorizzazioni all'app

Per controllare a quali risorse viene sovrapposto un pacchetto RRO, aggiungi un file denominato overlayable.xml nella cartella /res dell'app. Questo file funge da autorizzazione 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 tuo 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 parametro del nome della risorsa nel file overlayable.xml dell'app.

    Il tuo file overlayable.xml DEVE risiedere in res/values/. In caso contrario, OverlayManagerService non riesce a localizzarlo.

    Per saperne di più sulle risorse sovrapponibili e su come utilizzarle configurati, consulta l'articolo Limitare l'overlay Google Cloud.

Creare un pacchetto RRO

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

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

    Le configurazioni hanno un aspetto simile a quello illustrato di seguito. La posizione in cui vengono salvati può variare:

  2. Dopo aver creato il nuovo progetto CarUiRRO, dichiara il progetto 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>
    

    Questa operazione genera un errore in @xml/sample_overlay. resourcesMap il file mappa i nomi delle risorse dal pacchetto di destinazione al pacchetto RRO.

  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>
    
    Build Gradle di RRO creata
  5. Per creare il target RRO, premi il pulsante verde Riproduci per creare un Gradle build del tuo RRO sull'emulatore o sul dispositivo Android.

  6. Per verificare che il 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 visualizza 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] indica che l'RRO è installato e attivato.

    Se il tuo RRO contiene errori, consulta Risolvere i problemi relativi agli overlay delle risorse di runtime prima di continuare.

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

    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
    

L'app mostra la stringa "Hello World RRO".

Ciao mondo RRO!
Figura 4: Hello World RRO!

Complimenti! Hai creato il tuo primo RRO.

Quando utilizzi i RRO, ti consigliamo di usare lo strumento Android Asset Packaging Tool (AAPT2) segnala --no-resource-deduping e --no-resource-removal descritti in Opzioni di collegamento. Non è necessario aggiungere flag in questo codelab, ma ti consigliamo di utilizzarli nei tuoi RRO per evitare la rimozione delle risorse (e problemi di debug). Tu puoi aggiungerli al file build.gradle dell'RRO in questo modo:

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

Per scoprire di più su questi flag, consulta Creare il pacchetto e AAPT2.

Modifica i componenti car-ui-lib utilizzando gli RRO nell'app per Android

In questa pagina viene descritto come utilizzare un overlay delle risorse di runtime (RRO) per modificare componenti dalla raccolta car-ui-lib nell'app per Android.

Imposta il colore di sfondo della barra degli strumenti

Durata: 15 minuti

Per modificare il colore di sfondo della barra degli strumenti:

  1. Aggiungi il valore seguente all'app RRO e imposta la risorsa su luminoso verde (#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 configurazione di un RRO, la barra degli strumenti non cambia perché il valore errato viene scelto come target.

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

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

    Devi creare un nuovo pacchetto RRO per ogni pacchetto di destinazione che vuoi impostare come RRO. Ad esempio, quando crei overlay per due target diversi, devi creare due apk di overlay.

  3. Crea, verifica, installa e abilita l'RRO come hai fatto prima.

La tua app avrà il seguente aspetto:

Nuovo colore di sfondo della 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. Questo consente di sovrapporre il layout. Segui gli stessi passaggi di prima oppure modifica all'app esistente.

  1. Assicurati di aggiungere le righe seguenti 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 sia 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. Nell'app RRO, crea un res/layout/activity_main.xml e aggiungi seguenti:

    <?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 all'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. Cambia targetName in AndroidManifest.xml in modo che punti al nome di la 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 come hai fatto prima (Play verde ). Assicurati di attivare il tuo RRO.

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

RRO Hello World
Figura 6: RRO Hello World

Aggiungi CarUiRecyclerView alla tua app

Durata: 15 minuti

L'interfaccia CarUiRecyclerView fornisce le 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 abilitata o meno e seleziona il layout corrispondente.

Container con visualizzazione CarUiRecycler
Figura 7. CarUiRecyclerViewContainer
.
    .
  1. Per aggiungere un CarUiRecyclerView, aggiungilo a activity_main.xml e MainActivity.java file. Puoi creare una nuova app da zero oppure modificare l'app esistente. Se modifichi l'app esistente, assicurati di rimuoverla risorse non dichiarate di 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

    Purché lo spelling del corso sia corretto e tu abbia aggiunto car-ui-lib come una dipendenza, puoi creare e compilare il tuo apk. Per rimuovere l'errore, Seleziona File > Disattiva le cache, quindi fai clic su Annulla convalida e riavvia.

    Aggiungi il seguente codice 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:

Visualizzazione riciclo CarUi
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 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 se la barra di scorrimento ottimizzata per auto con i pulsanti Su e Giù in CarUiRecyclerView è presente o meno. Se impostato su false, CarUiRecyclerView si comporta come un RecyclerView di 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 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 modificherai il layout della barra di scorrimento CarUiRecyclerView.

  1. Aggiungi e modifica i seguenti file nella tua 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 lo spazio dei nomi attributi al overlay.xml del tuo RRO. Visualizza 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 come questi file interagiscono.

    Per semplicità, le dimensioni e i colori sono impostati come hardcoded. Tuttavia, una pratica è dichiarare questi valori in dimens.xml e colors.xml o anche designati come file colore nella cartella res/color/. Per saperne di più, vedi 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 guide grigie.

Complimenti! Entrambe le frecce appaiono lungo la parte inferiore della barra di scorrimento: ha applicato correttamente un RRO a un file di risorse di layout car-ui-lib utilizzando la 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

A questo punto, hai applicato un RRO ai componenti di car-ui-lib utilizzando il framework componenti (non AndroidX). Per utilizzare i componenti AndroidX in un RRO, devi aggiungere le dipendenze di quel componente sia dall'app che dall'RRO build.gradle. devi anche aggiungere il valore attrs di quel componente a overlayable.xml nell'app, oltre come sample_overlay.xml nel tuo RRO.

La nostra libreria (car-ui-lib) utilizza ConstraintLayout e altri dispositivi AndroidX quindi il suo overlayable.xml potrebbe avere il seguente 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 riferimenti a diversi componenti/ a risorse non incluse come dipendenze dell'app. Queste sono car-ui-lib risorse. Puoi risolvere il problema aggiungendo car-ui-lib come una dipendenza dalla tua 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'
    }
    

Titolo e corpo ora sono allineati a destra anziché a sinistra.

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

Abbiamo applicato un RRO a car-ui-lib solo utilizzando i componenti AndroidX (ConstraintLayout) quando i relativi attributi erano presenti in car-ui-lib denominato overlayable.xml e il RRO sample_overlay.xml. È fare qualcosa di simile nella tua app. Devi solo aggiungere tutti i token attrs a overlayable.xml della tua app, simile a car-ui-lib.

Tuttavia, non è possibile eseguire il RRO di un'app utilizzando i componenti AndroidX quando l'app ha car-ui-lib come dipendenza nel suo build.gradle (quando l'app utilizza car-ui-lib componenti). Poiché le mappature degli attributi erano già definite in overlayable.xml della raccolta car-ui-lib, aggiungendoli ai tuoi il valore overlayable.xml dell'app con car-ui-lib come dipendenza, può causare un mergeDebugResources errore simile al seguente. Il motivo è che questi attributi sono presenti in più file overlayable.xml:

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