Codelab: Erstellen Sie RROs mit Car-UI-Lib-Komponenten mithilfe des Gradle-Build-Systems

Verwenden Sie die Bibliothek car-ui-lib um selbstkonsistente fahrzeuginterne Infotainmentsysteme (IVI) zu starten. Dieses Codelab führt Sie in car-ui-lib ein und zeigt Ihnen, wie Sie Runtime Resource Overlays (RROs) verwenden können, um Komponenten in der Bibliothek anzupassen.

Was Sie lernen werden

Wie man:

  • Integrieren Sie car-ui-lib Komponenten in Ihre Android-App.
  • 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 „Ändern des Werts der Ressourcen einer App zur Laufzeit“ und „Fehlerbehebung bei Laufzeitressourcenüberlagerungen“ .

Bevor du anfängst

Voraussetzungen

Bevor Sie beginnen, stellen Sie sicher, dass Sie Folgendes haben:

Erstellen Sie eine neue Android-App

Dauer: 15 Minuten

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

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

    Erstellen Sie eine leere Aktivität
    Abbildung 1. Erstellen Sie eine leere Aktivität
  2. Benennen Sie die App CarUiCodelab und wählen Sie dann die Java-Sprache aus. Bei Bedarf können Sie auch einen Dateispeicherort auswählen. Übernehmen Sie die Standardwerte für die übrigen Einstellungen.

    Benennen Sie Ihre App
    Abbildung 2. Benennen Sie Ihre App
  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>
    

    Dieser Codeblock zeigt die Zeichenfolge sample_text an, die nicht definiert ist.

  4. Fügen Sie die Ressourcenzeichenfolge sample_text hinzu und legen Sie sie auf „Hello World!“ fest. in Ihrer strings.xml -Datei. Um diese Datei zu öffnen, wählen Sie app > src > main > res > value > 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. Um Ihre App zu erstellen, klicken Sie oben rechts auf die grüne Play- Schaltfläche. Dadurch wird die APK automatisch über Gradle auf Ihrem Emulator oder Android-Gerät installiert.

    Play-Taste

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

Öffnen Sie die neue CarUiCodelab-App
Abbildung 3. Neue CarUiCodelab-App öffnen

Fügen Sie car-ui-lib zu Ihrer Android-App hinzu

Dauer: 15 Minuten

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

  1. Um die car-ui-lib Abhängigkeit zur build.gradle Datei Ihres Projekts hinzuzufügen, wählen Sie app > build.gradle aus. Ihre Abhängigkeiten sollten wie folgt 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'
    }
    

Verwenden Sie car-ui-lib-Komponenten in Ihrer Android-App

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

  1. Überschreiben Sie in Ihrer MainActivity.java Datei die onCreate Methode:

    @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. Stellen Sie sicher, dass Sie ToolbarController importieren:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Um das Theme.CarUi.WithToolbar -Design zu verwenden, wählen Sie app > src > main > AndroidManifest.xml aus und aktualisieren Sie dann AndroidManifest.xml so, dass es wie folgt 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. Um die App zu erstellen, drücken Sie wie zuvor die grüne Play- Taste.

    Erstellen Sie die App

Fügen Sie Ihrer App RROs hinzu

Dauer: 30 Minuten

Wenn Sie mit RROs vertraut sind, fahren Sie mit dem nächsten Abschnitt fort: Hinzufügen eines Berechtigungscontrollers zu Ihrer App . Ansonsten erfahren Sie, wie Sie die Grundlagen von RROs erlernen: Ändern des Werts der Ressourcen einer App zur Laufzeit .

Fügen Sie Ihrer App einen Berechtigungscontroller hinzu

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

  1. Fügen Sie res/values/overlayable.xml zu Ihrer App hinzu und kopieren Sie den folgenden Inhalt in Ihre 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 die Zeichenfolge sample_text von einem RRO überlagerbar sein muss, fügen Sie den Ressourcennamen in die Datei „overlayable.xml“ der App ein.

    Ihre Datei overlayable.xml MUSS sich in res/values/ befinden. Wenn nicht, kann der OverlayManagerService es nicht finden.

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

Erstellen Sie ein RRO-Paket

In diesem Abschnitt erstellen Sie ein RRO-Paket, um die oben angezeigte Zeichenfolge von „Hello World!“ zu ändern. zu „Hallo Welt RRO“.

  1. Um ein neues Projekt zu erstellen, wählen Sie Datei > Neu > Neues Projekt . Stellen Sie sicher, dass Sie „Keine Aktivität“ anstelle von „Leere Aktivität“ auswählen, da RRO-Pakete nur Ressourcen enthalten.

    Ihre Konfigurationen ähneln den unten dargestellten. Der Speicherort kann unterschiedlich sein:

  2. Nachdem Sie das neue CarUiRRO Projekt erstellt haben, deklarieren Sie das Projekt 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 entsteht ein Fehler mit @xml/sample_overlay . Die resourcesMap Datei ordnet Ressourcennamen vom Zielpaket dem RRO-Paket zu.

  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. Fügen Sie sample_text zu …/res/values/strings.xml hinzu:

    <?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 Ihr RRO-Ziel zu erstellen, drücken Sie die grüne Play- Taste, um einen Gradle-Build Ihres RRO auf Ihrem Emulator oder Android-Gerät zu erstellen.

  6. Führen Sie Folgendes aus, um zu überprüfen, ob Ihr RRO ordnungsgemäß installiert ist:

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

    Dieser Befehl zeigt nützliche Informationen über den Status von RRO-Paketen auf dem System an.

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

    Wenn Ihr RRO Fehler enthält, lesen Sie den Abschnitt Fehlerbehebung bei Laufzeitressourcen-Overlays, bevor Sie fortfahren.

  7. So aktivieren Sie das RRO und überprüfen, ob es 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 die Zeichenfolge „Hello World RRO“ an.

Hallo Welt RRO!
Abbildung 4 : Hallo Welt RRO!

Glückwunsch! Sie haben Ihr erstes RRO erstellt.

Wenn Sie RROs verwenden, möchten Sie möglicherweise die unter Link-Optionen beschriebenen Flags --no-resource-deduping und --no-resource-removal des Android Asset Packaging Tool (AAPT2) verwenden. Es ist nicht notwendig, die Flags in diesem Codelab hinzuzufügen, wir empfehlen Ihnen jedoch, sie in Ihren RROs zu verwenden, um das Entfernen von Ressourcen (und Debugging-Probleme) zu vermeiden. Sie können sie wie folgt zur build.gradle Datei Ihres RRO hinzufügen:

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

Weitere Informationen zu diesen Flags finden Sie unter Erstellen des Pakets und AAPT2 .

Ändern Sie car-ui-lib Komponenten mithilfe von RROs in Ihrer Android-App

Auf dieser Seite wird beschrieben, wie Sie ein Runtime Resource Overlay (RRO) verwenden können, um Komponenten aus der car-ui-lib Bibliothek in Ihrer Android-App zu ändern.

Legen Sie die Hintergrundfarbe der Symbolleiste fest

Dauer: 15 Minuten

So ändern Sie die Hintergrundfarbe der Symbolleiste:

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

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

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

  2. Aktualisieren Sie in der AndroidManifest.xml für Ihr RRO targetName so, dass es auf car-ui-lib verweist:

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

    Sie MÜSSEN für jedes Zielpaket, für das Sie RRO erstellen 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, überprüfen, installieren und aktivieren Sie das RRO auf die gleiche Weise wie zuvor.

Ihre App sieht folgendermaßen aus:

Neue Hintergrundfarbe für die Symbolleiste
Abbildung 5 : Neue Hintergrundfarbe der Symbolleiste

RRO-Layouts und -Stile

Dauer: 15 Minuten

In dieser Übung erstellen Sie eine neue App, die der zuvor erstellten App ähnelt. Diese App ermöglicht die Überlagerung des Layouts. Befolgen Sie die gleichen Schritte wie zuvor oder ändern Sie Ihre vorhandene App.

  1. Stellen Sie sicher, dass Sie die folgenden Zeilen zu overlayable.xml hinzufügen:

    <?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. Stellen Sie sicher, dass activity_main.xml wie folgt aussieht:

    <?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 unseren Stil zum RRO 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 den targetName in AndroidManifest.xml so, dass er auf den Namen Ihrer neuen App verweist:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Fügen Sie die Ressourcen zur Datei sample_overlay.xml in Ihrem 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 RRO auf die gleiche Weise wie zuvor (grüne Play- Schaltfläche). Stellen Sie sicher, dass Sie Ihr RRO aktivieren.

Die App und RRO rendern wie folgt. Der „Hello World“-RRO-Text ist grün und wird gemäß der Layout-RRO-Angabe zentriert.

Hallo Welt RRO
Abbildung 6 : Hello World RRO

Fügen Sie CarUiRecyclerView zu Ihrer App hinzu

Dauer: 15 Minuten

Die CarUiRecyclerView Schnittstelle stellt APIs für den Zugriff auf eine RecyclerView bereit, die über car-ui-lib Ressourcen angepasst wird. CarUiRecyclerView überprüft beispielsweise zur 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. Um eine CarUiRecyclerView hinzuzufügen, fügen Sie sie Ihren Dateien activity_main.xml und MainActivity.java hinzu. Sie können entweder eine neue App von Grund auf erstellen oder die vorhandene App ändern. Wenn Sie die vorhandene App ändern, müssen Sie nicht deklarierte Ressourcen aus overlayable.xml entfernen.

    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 erscheint der folgende Fehler, den Sie ignorieren können:

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

    Solange Ihre Klasse richtig geschrieben ist und Sie car-ui-lib als Abhängigkeit hinzugefügt haben, können Sie Ihre APK erstellen und kompilieren. Um den Fehler zu beheben, wählen Sie „Datei“ > „Caches ungültig machen“ und klicken Sie dann auf „Ungültig machen und neu starten“.

    Fügen Sie Folgendes zu MainActivity.java 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 zuvor.

Sie sehen jetzt eine CarUiRecyclerView :

CarUiRecyclerView
Abbildung 7 : CarUiRecyclerView

Verwenden Sie ein RRO, um die Bildlaufleiste zu entfernen

Dauer: 10 Minuten

Diese Übung zeigt Ihnen, wie Sie mit einem RRO die Bildlaufleiste aus CarUiRecyclerView entfernen.

  1. Fügen Sie in Ihrem 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, die steuert, ob die für Autos optimierte Bildlaufleiste mit den Auf- und Ab-Schaltflächen in CarUiRecyclerView vorhanden ist oder nicht. Wenn es auf false gesetzt ist, verhält sich CarUiRecyclerView wie ein AndroidX RecyclerView .

    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 zuvor. Die Bildlaufleiste wurde jetzt aus CarUiRecyclerView entfernt:

CarUiRecyclerView ohne Bildlaufleiste
Abbildung 8. CarUiRecyclerView ohne Bildlaufleiste

Verwenden Sie ein Layout, 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>
    

    Um eine Layoutdatei zu überlagern, müssen Sie alle IDs und Namespace-Attribute zur overlay.xml Ihres RRO 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 untersuchen.

    Der Einfachheit halber sind Abmessungen und Farben fest codiert. Eine bewährte Vorgehensweise besteht jedoch darin, diese Werte in dimens.xml und colors.xml zu deklarieren oder sie sogar als Farbdateien im Ordner res/color/ festzulegen. Weitere Informationen finden Sie unter AOSP Java-Codestil für Mitwirkende .

  2. Erstellen und installieren Sie Ihre App wie zuvor. Sie haben CarUiRecyclerView mit einer blauen Bildlaufleiste und grauen Schienen erstellt.

Glückwunsch! Beide Pfeile werden am unteren Rand der Bildlaufleiste angezeigt. Sie haben mit dem Gradle-Build-System über Android Studio erfolgreich ein RRO 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 mithilfe von Framework-Komponenten (nicht AndroidX) ein RRO auf car-ui-lib Komponenten angewendet. Um AndroidX-Komponenten in einem RRO zu verwenden, müssen Sie die Abhängigkeiten dieser Komponente sowohl zur App als auch zum RRO build.gradle. Sie müssen außerdem die attrs dieser Komponente zu overlayable.xml in Ihrer App sowie zu sample_overlay.xml in Ihrem RRO hinzufügen.

Unsere Bibliothek ( car-ui-lib ) verwendet ConstraintLayout sowie andere AndroidX-Komponenten, daher könnte ihre overlayable.xml 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 CarUiRecyclerView mit ConstraintLayout . Fügen Sie die folgenden Dateien in Ihrem 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 Referenzen auf mehrere Komponenten/Ressourcen, die nicht als Abhängigkeiten der App enthalten sind. Dies sind car-ui-lib Ressourcen. Sie können dies beheben, indem Sie car-ui-lib als Abhängigkeit zu Ihrer RRO-App in app/build.gradle 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'
    }
    

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

Rechtsbündiger Titel und Text
Abbildung 10. Rechtsbündiger Titel und Text

Wir haben nur dann ein RRO auf car-ui-lib mithilfe von AndroidX-Komponenten ( ConstraintLayout ) angewendet, wenn dessen Attribute in der car-ui-lib -Datei mit dem Namen overlayable.xml sowie im RRO sample_overlay.xml vorhanden waren. Es ist möglich, etwas Ähnliches in Ihrer eigenen App zu tun. 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 erstellen, wenn die App car-ui-lib als Abhängigkeit in ihrem build.gradle hat (wenn die App car-ui-lib Komponenten verwendet). Da die Attributzuordnungen bereits in der Datei „ overlayable.xml der Bibliothek car-ui-lib definiert wurden, würde das Hinzufügen zur Datei overlayable.xml Ihrer App mit car-ui-lib als Abhängigkeit zu einem mergeDebugResources Fehler wie dem folgenden führen. Dies liegt daran, dass diese Attribute in mehreren overlayable.xml Dateien vorhanden sind:

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