Codelab: RROs mit „car-ui-lib“-Komponenten mithilfe des Gradle-Build-Systems erstellen

Verwenden Sie die car-ui-lib-Bibliothek, um konsistente Infotainmentsysteme (In-Vehicle Infotainment, IVI) zu starten. In diesem Codelab lernen Sie car-ui-lib kennen und erfahren, wie Sie mithilfe von Laufzeitressourcen-Overlays (RROs) Komponenten in der Bibliothek anpassen können.

Lerninhalte

Anleitung:

  • Fügen Sie Ihrer Android-App car-ui-lib-Komponenten hinzu.
  • Verwenden Sie Gradle, um Android-Apps und RROs zu erstellen.
  • Verwenden Sie RROs mit car-ui-lib.

In diesem Codelab wird nicht detailliert beschrieben, wie RROs funktionieren. Weitere Informationen finden Sie unter Wert der Ressourcen einer App zur Laufzeit ändern und Fehlerbehebung bei Laufzeit-Ressourcenüberlagerungen.

Vorbereitung

Voraussetzungen

Bevor Sie beginnen, benötigen Sie Folgendes:

  • Computer mit Befehlszeile (Linux-, Mac- oder Windows-Computer mit Windows-Subsystem für Linux)

  • Android Studio

  • Ein Android-Gerät oder Emulator, das bzw. der mit Ihrem Computer verbunden ist. Weitere Informationen finden Sie unter Android-Quellcode herunterladen und Android erstellen.

  • Grundkenntnisse zu RROs

Neue Android-App erstellen

Dauer:15 Minuten

In diesem Abschnitt erstellen Sie ein neues Android Studio-Projekt.

  1. Erstellen Sie in Android Studio eine App mit einem EmptyActivity.

    Leere Aktivität erstellen
    Abbildung 1: Leere Aktivität erstellen
  2. Benennen Sie die App CarUiCodelab und wählen Sie die Sprache Java aus. Optional können Sie auch einen Speicherort für die Datei auswählen. Akzeptieren Sie für die restlichen Einstellungen die Standardwerte.

     App benennen
    Abbildung 2. Geben Sie einen Namen für Ihre App ein.
  3. Ersetzen Sie activity_main.xml durch den folgenden Codeblock:

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

    In diesem Codeblock wird der nicht definierte String sample_text angezeigt.

  4. Fügen Sie den sample_text-Ressourcenstring hinzu und setzen Sie ihn in der Datei strings.xml auf „Hallo Welt!“. Wählen Sie zum Öffnen dieser Datei app > src > main > res > values > strings.xml aus.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiCodelab</string>
        <string name="sample_text">Hello World!</string>
    </resources>
    
  5. Klicken Sie rechts oben auf die grüne Schaltfläche Abspielen, um Ihre App zu erstellen. Dadurch wird die APK automatisch über Gradle auf Ihrem Emulator oder Android-Gerät installiert.

    Schaltfläche für die Wiedergabe

Die neue App sollte automatisch auf Ihrem Emulator oder Android-Gerät geöffnet werden. Andernfalls öffnen Sie die CarUiCodelab App über den App Launcher, der jetzt installiert ist. Sie sieht so aus:

Neue CarUiCodelab App öffnen
Abbildung 3 Neue CarUiCodelab App öffnen

car-ui-lib zu Ihrer Android-App hinzufügen

Dauer:15 Minuten

Fügen Sie Ihrer App car-ui-lib hinzu:

  1. Wenn Sie der Datei build.gradle Ihres Projekts die Abhängigkeit car-ui-lib hinzufügen möchten, wählen Sie app > build.gradle aus. Ihre Abhängigkeiten sollten so aussehen:

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

car-ui-lib-Komponenten in Ihrer Android-App verwenden

Jetzt, da Sie car-ui-lib haben, fügen Sie Ihrer App eine Symbolleiste hinzu.

  1. Überschreiben Sie in der Datei MainActivity.java die Methode 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. Achten Sie darauf, ToolbarController zu importieren:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Wenn Sie das Theme.CarUi.WithToolbar-Design verwenden möchten, wählen Sie app > src > main > AndroidManifest.xml aus und aktualisieren Sie AndroidManifest.xml so, dass er so aussieht:

    <?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. Drücken Sie wie zuvor auf die grüne Schaltfläche Wiedergabe, um die App zu erstellen.

    App erstellen

Ihrer App RROs hinzufügen

Dauer: 30 Minuten

Wenn Sie mit RROs vertraut sind, fahren Sie mit dem nächsten Abschnitt Ihrer App einen Berechtigungscontroller hinzufügen fort. Andernfalls finden Sie die Grundlagen von RROs unter Wert der Ressourcen einer App zur Laufzeit ändern.

Ihrer App einen Berechtigungscontroller hinzufügen

Wenn Sie steuern möchten, welche Ressourcen ein RRO-Paket überlagert, fügen Sie dem Ordner /res Ihrer App eine Datei mit dem Namen overlayable.xml hinzu. Diese Datei dient als Berechtigungscontroller zwischen Ihrer App (dem Ziel) und Ihrem RRO-Paket (dem Overlay).

  1. Fügen Sie Ihrer App res/values/overlayable.xml hinzu und kopieren Sie den folgenden Inhalt in die Datei:

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

    Da der String sample_text von einer RRO überlagert werden muss, fügen Sie den Ressourcennamen in „overlayable.xml“ der App ein.

    Die Datei overlayable.xml MUSS sich in res/values/ befinden. Andernfalls kann die OverlayManagerService sie nicht finden.

    Weitere Informationen zu überlagerbaren Ressourcen und ihrer Konfiguration finden Sie unter Überlagerbare Ressourcen einschränken.

RRO-Paket erstellen

In diesem Abschnitt erstellen Sie ein RRO-Paket, um den oben angezeigten String von „Hello World!“ in „Hello World RRO“ zu ändern.

  1. Wenn Sie ein neues Projekt erstellen möchten, wählen Sie Datei > Neu > Neues Projekt aus. Wählen Sie Keine Aktivität anstelle von „Leere Aktivität“ aus, da RRO-Pakete nur Ressourcen enthalten.

    Ihre Konfigurationen sollten in etwa so aussehen wie unten dargestellt. Der Speicherort kann variieren:

  2. Nachdem Sie das neue CarUiRRO-Projekt erstellt haben, deklarieren Sie es als RRO, indem Sie AndroidManifest.xml ändern.

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

    Dadurch wird ein Fehler mit @xml/sample_overlay ausgegeben. In der Datei resourcesMap werden Ressourcennamen aus dem Zielpaket dem RRO-Paket zugeordnet. Für RRO-Pakete ist es obligatorisch, das Flag hasCode auf false zu setzen. Außerdem dürfen RRO-Pakete keine DEX-Dateien enthalten.

  3. Kopieren Sie den folgenden Codeblock 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. sample_text zu …/res/values/strings.xml hinzufügen:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiRRO</string>
        <string name="sample_text">Hello World RRO</string>
    </resources>
    
    Gradle-Build von RRO erstellt
  5. Um das RRO-Ziel zu erstellen, klicken Sie auf die grüne Schaltfläche Wiedergabe, um einen Gradle-Build Ihrer RRO auf Ihrem Emulator oder Android-Gerät zu erstellen.

  6. Führen Sie folgenden Befehl aus, um zu prüfen, ob die RRO richtig installiert ist:

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

    Mit diesem Befehl werden nützliche Informationen zum Status der RRO-Pakete im System angezeigt.

    • [ ] gibt an, dass die RRO installiert und zur Aktivierung bereit ist.
    • --- gibt an, dass die RRO installiert ist, aber Fehler enthält.
    • [X] bedeutet, dass die RRO installiert und aktiviert ist.

    Wenn Ihre Laufzeitressourcen-Overlays Fehler enthalten, lesen Sie den Hilfeartikel Fehlerbehebung bei Laufzeitressourcen-Overlays, bevor Sie fortfahren.

  7. So aktivieren Sie die RRO und prüfen, ob sie aktiviert ist:

    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
    

Ihre App zeigt den String „Hello World RRO“ an.

Hallo Welt RRO!
Abbildung 4: Hallo Welt-RRO

Glückwunsch! Sie haben Ihre erste RRO erstellt.

Wenn Sie RROs verwenden, können Sie die Flags --no-resource-deduping und --no-resource-removal des Android Asset Packaging Tools (AAPT2) verwenden, die unter Link-Optionen beschrieben werden. Sie müssen die Flags in diesem Codelab nicht hinzufügen. Wir empfehlen Ihnen jedoch, sie in Ihren RROs zu verwenden, um das Entfernen von Ressourcen und Probleme beim Debuggen zu vermeiden. Sie können sie der build.gradle-Datei Ihrer RRO so hinzufügen:

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

Weitere Informationen zu diesen Flags finden Sie unter Paket erstellen und AAPT2.

car-ui-lib-Komponenten in Ihrer Android-App mit RROs ändern

Auf dieser Seite wird beschrieben, wie Sie mit einem Laufzeit-Ressourcen-Overlay (RRO) Komponenten aus der car-ui-lib-Bibliothek in Ihrer Android-App ändern können.

Hintergrundfarbe der Symbolleiste festlegen

Dauer:15 Minuten

So ändern Sie die Hintergrundfarbe der Symbolleiste:

  1. Fügen Sie Ihrer RRO-App den folgenden Wert hinzu und legen Sie die Ressource auf knallgrün (#0F0) fest:

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

    Die car-ui-lib-Bibliothek enthält eine Ressource namens car_ui_toolbar_background. Wenn diese Ressource in der Konfiguration einer RRO enthalten ist, ändert sich die Symbolleiste nicht, da der falsche Wert als Ziel festgelegt ist.

  2. Aktualisieren Sie in der AndroidManifest.xml für Ihre RRO den Wert für targetName so, dass er auf car-ui-lib verweist:

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

    Sie MÜSSEN für jedes Zielpaket, das Sie mit der Funktion „RRO“ bearbeiten möchten, ein neues RRO-Paket erstellen. Wenn Sie beispielsweise Overlays für zwei verschiedene Ziele erstellen, müssen Sie zwei Overlay-APKs erstellen.

  3. Erstellen, prüfen, installieren und aktivieren Sie die RRO wie zuvor.

Ihre App wird so angezeigt:

Neue Hintergrundfarbe der Symbolleiste
Abbildung 5: Neue Hintergrundfarbe der Symbolleiste

Layouts und Stile für responsive Suchanzeigen

Dauer:15 Minuten

In dieser Übung erstellen Sie eine neue App, die der App ähnelt, die Sie zuvor erstellt haben. Mit dieser App kann das Layout überlagert werden. Folgen Sie denselben Schritten wie zuvor oder ändern Sie Ihre vorhandene App.

  1. Fügen Sie overlayable.xml die folgenden Zeilen hinzu:

    <?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. activity_main.xml sollte so angezeigt werden:

    <?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. Erstellen Sie in Ihrer RRO-App eine res/layout/activity_main.xml und fügen Sie Folgendes hinzu:

    <?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. Aktualisieren Sie res/values/styles.xml, um dem RRO unseren Stil hinzuzufügen:

    <?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. Ändern Sie targetName in AndroidManifest.xml, sodass es auf den Namen Ihrer neuen App verweist:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Fügen Sie die Ressourcen der sample_overlay.xml-Datei in Ihrer RRO hinzu:

    <?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. Erstellen und installieren Sie die App und die RRO wie zuvor (grüne Schaltfläche Wiedergabe). Achten Sie darauf, dass Ihre RRO aktiviert ist.

Die App und die RRO werden so gerendert: Der RRO-Text „Hallo Welt“ ist grün und wie im Layout-RRO angegeben zentriert.

Hello World RRO
Abbildung 6: Hello World-RRO

CarUiRecyclerView zur App hinzufügen

Dauer:15 Minuten

Die CarUiRecyclerView-Schnittstelle bietet APIs für den Zugriff auf eine RecyclerView, die über car-ui-lib-Ressourcen angepasst wird. Beispielsweise prüft CarUiRecyclerView bei der Laufzeit ein Flag, um festzustellen, ob die Bildlaufleiste aktiviert werden soll oder nicht, und wählt das entsprechende Layout aus.

CarUiRecyclerViewContainer
Abbildung 7: CarUiRecyclerViewContainer
  1. Wenn Sie CarUiRecyclerView hinzufügen möchten, fügen Sie ihn den Dateien activity_main.xml und MainActivity.java hinzu. Sie können entweder eine neue App von Grund auf neu erstellen oder die vorhandene App ändern. Wenn Sie die vorhandene App ändern, entfernen Sie unbedingt nicht deklarierte Ressourcen aus 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"/>
    

    Möglicherweise wird der folgende Fehler angezeigt, den Sie ignorieren können:

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

    Solange die Schreibweise Ihrer Klasse korrekt ist und Sie car-ui-lib als Abhängigkeit hinzugefügt haben, können Sie Ihre APK erstellen und kompilieren. Wählen Sie Datei > Caches ungültig machen aus und klicken Sie dann auf Ungültig machen und neu starten, um den Fehler zu beheben.

    Fügen Sie MainActivity.java Folgendes hinzu:

    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. Erstellen und installieren Sie Ihre App wie gewohnt.

Sie sehen jetzt ein CarUiRecyclerView:

CarUiRecyclerView
Abbildung 7 : CarUiRecyclerView

Bildlaufleiste mit einem RRO entfernen

Dauer:10 Minuten

In dieser Übung erfahren Sie, wie Sie mithilfe eines RRO die Bildlaufleiste aus CarUiRecyclerView entfernen.

  1. Fügen Sie in Ihrer RRO die folgenden Dateien hinzu und ändern Sie sie:

    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>
    

    Die Ressource car_ui_scrollbar_enable ist eine boolesche car-ui-lib-Ressource, mit der gesteuert wird, ob die für Mobilgeräte optimierte Bildlaufleiste mit den Schaltflächen „Nach oben“ und „Nach unten“ in CarUiRecyclerView vorhanden ist oder nicht. Wenn false festgelegt ist, wirkt sich CarUiRecyclerView wie eine AndroidX-RecyclerView aus.

    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>
    

Erstellen und installieren Sie Ihre App wie gewohnt. Die Bildlaufleiste wurde aus CarUiRecyclerView entfernt:

CarUiRecyclerView ohne Bildlaufleiste
Abbildung 8. CarUiRecyclerView ohne Bildlaufleiste

Layout verwenden, um die Bildlaufleiste von CarUiRecyclerView zu überlagern

Dauer:15 Minuten

In dieser Übung ändern Sie das Layout der CarUiRecyclerView-Bildlaufleiste.

  1. Fügen Sie die folgenden Dateien in Ihrer RRO-App hinzu und ändern Sie sie.

    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>
    

    Wenn Sie eine Layoutdatei überlagern möchten, müssen Sie der overlay.xml Ihrer RRO alle IDs und Namespaceattribute hinzufügen. Siehe die Dateien unten.

    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>
    

    Es wird empfohlen, die Interaktion dieser Dateien zu prüfen.

    Zur Vereinfachung sind Dimensionen und Farben hartcodiert. Es wird jedoch empfohlen, diese Werte in dimens.xml und colors.xml anzugeben oder sie sogar als Farbdateien im Ordner res/color/ zu bezeichnen. Weitere Informationen finden Sie unter AOSP Java-Codestil für Mitwirkende.

  2. Erstellen und installieren Sie Ihre App wie gewohnt. Sie haben CarUiRecyclerView mit einer blauen Bildlaufleiste und grauen Rändern erstellt.

Glückwunsch! Beide Pfeile werden unten in der Bildlaufleiste angezeigt. Sie haben eine RRO mit dem Gradle-Build-System über Android Studio auf eine car-ui-lib-Layout-Ressourcendatei angewendet.

CarUiRecyclerView mit einer blauen Bildlaufleiste mit grauen Schienen
Abbildung 9. CarUiRecyclerView mit einer blauen Bildlaufleiste mit grauen Schienen

RRO-Listenelemente

Dauer:15 Minuten

Bisher haben Sie eine RRO auf car-ui-lib-Komponenten mit Framework-Komponenten (nicht AndroidX) angewendet. Wenn Sie AndroidX-Komponenten in einer RRO verwenden möchten, müssen Sie die Abhängigkeiten dieser Komponente sowohl der App als auch der RRO hinzufügen. build.gradle. Sie müssen auch die attrs dieser Komponente zu overlayable.xml in Ihrer App und zur sample_overlay.xml in Ihrer RRO hinzufügen.

Unsere Bibliothek (car-ui-lib) verwendet ConstraintLayout sowie andere AndroidX-Komponenten. Die overlayable.xml könnte also so aussehen:

<?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. Ändern Sie das Layout der Listenelemente in der CarUiRecyclerView mithilfe von ConstraintLayout. Fügen Sie die folgenden Dateien in Ihre RRO hinzu oder ändern Sie sie:

    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 verweist auf mehrere Komponenten/Ressourcen, die nicht als Abhängigkeiten der App enthalten sind. Das sind car-ui-lib-Ressourcen. Sie können das Problem beheben, indem Sie car-ui-lib in app/build.gradle als Abhängigkeit Ihrer RRO-App hinzufügen:

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

Der Titel und der Text sind jetzt rechtsbündig statt linksbündig ausgerichtet.

Titel und Textkörper rechtsbündig
Abbildung 10. Titel und Text rechtsbündig

Wir haben eine RRO nur dann auf car-ui-lib mit AndroidX-Komponenten (ConstraintLayout) angewendet, wenn ihre Attribute sowohl in der car-ui-lib-Datei mit dem Namen overlayable.xml als auch in der RRO sample_overlay.xml vorhanden waren. In Ihrer eigenen App ist etwas Ähnliches möglich. Fügen Sie einfach alle entsprechenden attrs zur overlayable.xml Ihrer App hinzu, ähnlich wie bei car-ui-lib.

Es ist jedoch nicht möglich, eine App mit AndroidX-Komponenten per RRO zu installieren, wenn die App car-ui-lib als Abhängigkeit in ihrer build.gradle hat (wenn die App car-ui-lib-Komponenten verwendet). Da die Attributzuordnungen bereits in der overlayable.xml der car-ui-lib-Bibliothek definiert waren, würde das Hinzufügen der Attributzuordnungen zur overlayable.xml Ihrer App mit car-ui-lib als Abhängigkeit zu einem mergeDebugResources-Fehler wie dem unten stehenden führen. Das liegt daran, dass diese Attribute in mehreren overlayable.xml-Dateien vorhanden sind:

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