Korzystaj z biblioteki car-ui-lib
, aby uruchamiać spójne systemy multimedialne w samochodzie (IVI). W tym ćwiczeniu z programowania poznasz car-ui-lib
oraz dowiesz się, jak używać nakładek zasobów w czasie wykonywania (RRO) do dostosowywania komponentów w bibliotece.
Czego się nauczysz
Instrukcje:
- Uwzględnij komponenty
car-ui-lib
w aplikacji na Androida. - Używaj Gradle do kompilowania aplikacji i pakietów RRO na Androida.
- Używaj RRO w przypadku
car-ui-lib
.
To ćwiczenie nie opisuje szczegółowo działania RRO. Aby dowiedzieć się więcej, przeczytaj artykuły Zmienianie wartości zasobów aplikacji w czasie wykonywania i Rozwiązywanie problemów z nakładkami zasobów w czasie wykonywania.
Zanim rozpoczniesz
Wymagania wstępne
Zanim zaczniesz, upewnij się, że:
Komputer z wierszem poleceń (Linux, Mac lub Windows z systemem Windows dla Linuxa).
urządzenie z Androidem lub emulator podłączony do komputera. Zapoznaj się z informacjami o pobieraniu kodu źródłowego Androida i kompilowaniu Androida.
podstawową wiedzę o RRO;
Tworzenie nowej aplikacji na Androida
Czas trwania: 15 minut
W tej sekcji utworzysz nowy projekt w Android Studio.
W Android Studio utwórz aplikację z
EmptyActivity
.Rysunek 1. Tworzenie pustej aktywności Nazwij aplikację
CarUiCodelab
, a następnie wybierz język Java. W razie potrzeby możesz też wybrać lokalizację pliku. Zaakceptuj domyślne wartości pozostałych ustawień.Rysunek 2. Nazwij aplikację Zastąp
activity_main.xml
tym blokiem kodu:<?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>
Ten blok kodu wyświetla ciąg znaków
sample_text
, który nie jest zdefiniowany.Dodaj ciąg znaków zasobu
sample_text
i ustaw go na „Hello World!” w plikustrings.xml
. Aby otworzyć ten plik, wybierz aplikacja > src > main > res > values > strings.xml.<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">CarUiCodelab</string> <string name="sample_text">Hello World!</string> </resources>
Aby utworzyć aplikację, w prawym górnym rogu kliknij zielony przycisk Odtwórz. Spowoduje to automatyczne zainstalowanie pliku APK na emulatorze lub urządzeniu z Androidem za pomocą Gradle.
Nowa aplikacja powinna otworzyć się automatycznie na emulatorze lub urządzeniu z Androidem. Jeśli nie, otwórz aplikację CarUiCodelab
z poziomu menu z aplikacjami, która jest teraz zainstalowana.
Wygląda to tak:

Dodawanie biblioteki car-ui-lib do aplikacji na Androida
Czas trwania: 15 minut
Dodaj car-ui-lib
do aplikacji:
Aby dodać zależność
car-ui-lib
do plikubuild.gradle
projektu, wybierz aplikacja > build.gradle. Zależność powinna wyglądać tak: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' }
Korzystanie z komponentów z biblioteki car-ui-lib w aplikacji na Androida
Teraz, gdy masz już car-ui-lib
, dodaj do aplikacji pasek narzędzi.
W pliku
MainActivity.java
zastąp metodę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); }
Pamiętaj, aby zaimportować
ToolbarController
:import com.android.car.ui.core.CarUi; import com.android.car.ui.toolbar.ToolbarController;
Aby użyć motywu
Theme.CarUi.WithToolbar
, wybierz aplikacja > src > main > AndroidManifest.xml, a następnie zaktualizuj elementAndroidManifest.xml
, aby wyglądał tak:<?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>
Aby skompilować aplikację, tak jak poprzednio naciśnij zielony przycisk Odtwórz.
Dodawanie funkcji RRO do aplikacji
Czas trwania: 30 minut
Jeśli znasz już podstawy RRO, przejdź do następnej sekcji Dodaj kontroler uprawnień do aplikacji. Jeśli nie, zapoznaj się z artykułem Zmiana wartości zasobów aplikacji w czasie wykonywania.
Dodawanie do aplikacji kontrolera uprawnień
Aby określić, które zasoby mają być nakładane przez pakiet RRO, dodaj do folderu /res
aplikacji plik o nazwie overlayable.xml
. Ten plik pełni funkcję kontrolera uprawnień między aplikacją (obiektem) a pakietem RRO (nakładką).
Dodaj do aplikacji
res/values/overlayable.xml
i skopiuj do pliku te treści:<?xml version="1.0" encoding="utf-8"?> <resources> <overlayable name="CarUiCodelab"> <policy type="public"> <item type="string" name="sample_text"/> </policy> </overlayable> </resources>
Ciąg znaków
sample_text
musi być nakładany przez RRO, dlatego dodaj nazwę zasobu w pliku overlayable.xml aplikacji.Plik
overlayable.xml
MUSI znajdować się w folderzeres/values/
. Jeśli nie,OverlayManagerService
nie będzie go w stanie znaleźć.Więcej informacji o zasobach z możliwością nakładania i o tym, jak je skonfigurować, znajdziesz w artykule Ograniczanie zasobów z możliwością nakładania.
Tworzenie pakietu RRO
W tej sekcji utworzysz pakiet RRO, aby zmienić wyświetlany powyżej ciąg znaków z „Hello World!” na „Hello World RRO”.
Aby utworzyć nowy projekt, kliknij Plik > Nowy > Nowy projekt. Pamiętaj, aby zamiast opcji Pusta aktywność wybrać opcję Brak aktywności, ponieważ pakiety RRO zawierają tylko zasoby.
Twoje konfiguracje wyglądają podobnie do tych przedstawionych poniżej. Miejsce, w którym są one zapisywane, może się różnić:
Po utworzeniu nowego projektu
CarUiRRO
oznaj go jako RRO, modyfikując plikAndroidManifest.xml
.<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.caruirro"> <application android:hasCode="false" /> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <overlay android:targetPackage="com.example.caruicodelab" android:targetName="CarUiCodelab" android:isStatic="false" android:resourcesMap="@xml/sample_overlay" /> </manifest>
Spowoduje to błąd w usłudze
@xml/sample_overlay
. PlikresourcesMap
mapuje nazwy zasobów z docelowego pakietu do pakietu RRO. W przypadku pakietów RRO obowiązkowe jest ustawienie flagihasCode
nafalse
. Ponadto pakiety RRO nie mogą zawierać plików DEX.Skopiuj ten blok kodu do pliku
…/res/xml/sample_overlay.xml
:<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="string/sample_text" value="@string/sample_text"/> </overlay>
Dodaj
sample_text
do…/res/values/strings.xml
:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">CarUiRRO</string> <string name="sample_text">Hello World RRO</string> </resources>
Aby utworzyć wersję docelową RRO, naciśnij zielony przycisk Odtwórz, aby utworzyć wersję Gradle RRO na emulatorze lub urządzeniu z Androidem.
Aby sprawdzić, czy usługa RRO jest prawidłowo zainstalowana, uruchom:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirro
To polecenie wyświetla przydatne informacje o stanie pakietów RRO w systemie.
[ ]
oznacza, że RRO jest zainstalowany i gotowy do aktywacji.---
oznacza, że RRO jest zainstalowany, ale zawiera błędy.[X]
oznacza, że RRO jest zainstalowany i aktywowany.
Jeśli RRO zawiera błędy, przed kontynuowaniem zapoznaj się z artykułem Rozwiązywanie problemów z nakładkami zasobów w czasie wykonywania.
Aby włączyć RRO i sprawdzić, czy jest włączone:
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
Aplikacja wyświetla ciąg tekstowy „Hello World RRO”.

Gratulacje! Udało Ci się utworzyć pierwszy RRO.
Jeśli używasz RRO, możesz użyć flag narzędzia Android Asset Packaging Tool (AAPT2) --no-resource-deduping
i --no-resource-removal
opisanych w sekcji Opcje linku.
Nie musisz dodawać flag w tym ćwiczeniu z programowania, ale zalecamy używanie ich w Twoich RRO, aby uniknąć usuwania zasobów (i problemów z debugowaniem). Możesz je dodać do pliku build.gradle
RRO w ten sposób:
android {
…
aaptOptions {
additionalParameters "--no-resource-deduping", "--no-resource-removal"
}
}
Więcej informacji o tych flagach znajdziesz w artykułach Tworzenie pakietu i AAPT2.
Modyfikowanie komponentów car-ui-lib
za pomocą RRO w aplikacji na Androida
Na tej stronie opisano, jak za pomocą nakładki zasobów w czasie wykonywania (RRO) modyfikować komponenty z biblioteki car-ui-lib
w aplikacji na Androida.
Ustawianie koloru tła paska narzędzi
Czas trwania: 15 minut
Aby zmienić kolor tła paska narzędzi:
Dodaj tę wartość do aplikacji RRO i ustaw zasób na jasnozielony (
#0F0
):<?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="car_ui_toolbar_background">#0F0</drawable> </resources>
Biblioteka
car-ui-lib
zawiera zasób o nazwiecar_ui_toolbar_background
. Gdy ten zasób jest zawarty w konfiguracji RRO, pasek narzędzi nie zmienia się, ponieważ jest kierowany na nieprawidłową wartość.W pliku
AndroidManifest.xml
dla RRO zaktualizuj elementtargetName
, aby wskazywał adrescar-ui-lib
:… android:targetName="car-ui-lib" …
W przypadku każdego docelowego pakietu, który chcesz przekazać do RRO, MUSISZ utworzyć nowy pakiet RRO. Jeśli na przykład tworzysz nakładki dla 2 różnych grup docelowych, musisz utworzyć 2 apki nakładki.
Utwórz, zweryfikuj, zainstaluj i włącz RRO w taki sam sposób jak wcześniej.
Aplikacja będzie wyglądać tak:

Układy i style reklam typu RRO
Czas trwania: 15 minut
W tym ćwiczeniu utworzysz nową aplikację podobną do tej, którą utworzyliśmy wcześniej. Ta aplikacja umożliwia nakładanie układu. Wykonaj te same czynności jak poprzednio lub zmodyfikuj już zainstalowaną aplikację.
Dodaj do pliku
overlayable.xml
te wiersze:<?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>
Upewnij się, że
activity_main.xml
wygląda tak:<?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>
W aplikacji RRO utwórz
res/layout/activity_main.xml
i dodaj te informacje:<?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>
Zaktualizuj plik
res/values/styles.xml
, aby dodać nasz styl do RRO:<?xml version="1.0" encoding="utf-8"?> <resources> <style name="TextAppearance.CarUi" parent="android:TextAppearance.DeviceDefault"> <item name="android:textColor">#0f0</item> <item name="android:textSize">100sp</item> </style> </resources>
Zmień
targetName
wAndroidManifest.xml
, aby wskazywało nazwę nowej aplikacji:… android:targetName="CarUiCodelab" …
Dodaj zasoby do pliku
sample_overlay.xml
w pliku RRO:<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="string/sample_text" value="@string/sample_text"/> <item target="id/textView" value="@id/textView"/> <item target="layout/activity_main" value="@layout/activity_main"/> </overlay>
Utwórz i zainstaluj aplikację oraz RRO w taki sam sposób jak wcześniej (zielony przycisk Graj). Pamiętaj, aby włączyć RRO.
Aplikacja i RRO są renderowane w ten sposób. Tekst „Hello World” w RRO jest zielony i wyśrodkowany zgodnie z wymaganym układem RRO.

Dodawanie widoku CarUiRecyclerView do aplikacji
Czas trwania: 15 minut
Interfejs CarUiRecyclerView
udostępnia interfejsy API umożliwiające dostęp do RecyclerView
, który jest dostosowywany za pomocą zasobów car-ui-lib
. Na przykład funkcja CarUiRecyclerView
sprawdza flagę w czasie wykonywania, aby określić, czy pasek przewijania powinien być włączony, i wybrać odpowiedni układ.

Aby dodać
CarUiRecyclerView
, dodaj go do plikówactivity_main.xml
iMainActivity.java
. Możesz utworzyć nową aplikację od podstaw lub zmodyfikować istniejącą. Jeśli zmodyfikujesz istniejącą aplikację, pamiętaj, aby usunąć niezadeklarowane zasoby z elementuoverlayable.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"/>
Może pojawić się ten błąd, który możesz zignorować:
Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerView
Jeśli nazwa klasy jest zapisana poprawnie i dodasz
car-ui-lib
jako zależność, możesz skompilować plik APK. Aby usunąć błąd, wybierz Plik > Nieważne pamięci podręcznej, a następnie kliknij Nieważne i uruchom ponownie.Dodaj te informacje do pliku
MainActivity.java
package com.example.caruicodelab; import android.app.Activity; import android.os.Bundle; import com.android.car.ui.core.CarUi; import com.android.car.ui.recyclerview.CarUiContentListItem; import com.android.car.ui.recyclerview.CarUiListItem; import com.android.car.ui.recyclerview.CarUiListItemAdapter; import com.android.car.ui.recyclerview.CarUiRecyclerView; import com.android.car.ui.toolbar.ToolbarController; import java.util.ArrayList; /** Activity with a simple car-ui layout. */ public class MainActivity extends Activity { private final ArrayList<CarUiListItem> mData = new ArrayList<>(); private CarUiListItemAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ToolbarController toolbar = CarUi.getToolbar(this); toolbar.setTitle(getTitle()); toolbar.setLogo(R.mipmap.ic_launcher_round); CarUiRecyclerView recyclerView = findViewById(R.id.list); mAdapter = new CarUiListItemAdapter(generateSampleData()); recyclerView.setAdapter(mAdapter); } private ArrayList<CarUiListItem> generateSampleData() { for (int i = 0; i < 20; i++) { CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.ICON); item.setTitle("Title " + i); item.setPrimaryIconType(CarUiContentListItem.IconType.CONTENT); item.setIcon(getDrawable(R.drawable.ic_launcher_foreground)); item.setBody("body " + i); mData.add(item); } return mData; }
Utwórz i zainstaluj aplikację jak dotąd.
Teraz zobaczysz CarUiRecyclerView
:

Usuwanie paska przewijania za pomocą RRO
Czas trwania: 10 minut
To ćwiczenie pokazuje, jak za pomocą RRO usunąć suwak z poziomuCarUiRecyclerView
.
W pliku RRO dodaj i zmodyfikuj te pliki:
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>
Zasób
car_ui_scrollbar_enable
to zasób logicznycar-ui-lib
, który określa, czy suwak z przyciskami w górę i w dół zoptymalizowany pod kątem samochodów jest obecny wCarUiRecyclerView
. Gdy ustawisz wartośćfalse
,CarUiRecyclerView
będzie działać jak AndroidXRecyclerView
.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>
Utwórz i zainstaluj aplikację jak dotąd. Suwak został usunięty z CarUiRecyclerView
:

Użyj układu, aby nałożyć suwak CarUiRecyclerView
Czas trwania: 15 minut
W tym ćwiczeniu zmodyfikujesz układ suwaka CarUiRecyclerView
.
Dodaj i zmodyfikuj te pliki w aplikacji RRO:
res/layout/car_ui_recycler_view_scrollbar.xml
<?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="112dp" android:layout_height="match_parent" android:id="@+id/car_ui_scroll_bar"> <!-- View height is dynamically calculated during layout. --> <View android:id="@+id/car_ui_scrollbar_thumb" android:layout_width="6dp" android:layout_height="20dp" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:background="@drawable/car_ui_recyclerview_scrollbar_thumb"/> <View android:id="@+id/car_ui_scrollbar_track" android:layout_width="10dp" android:layout_height="match_parent" android:layout_marginTop="10dp" android:layout_centerHorizontal="true" android:layout_above="@+id/car_ui_scrollbar_page_up"/> <View android:layout_width="2dp" android:layout_height="match_parent" android:layout_marginTop="10dp" android:background="#323232" android:layout_toLeftOf="@+id/car_ui_scrollbar_thumb" android:layout_above="@+id/car_ui_scrollbar_page_up" android:layout_marginRight="5dp"/> <View android:layout_width="2dp" android:layout_height="match_parent" android:layout_marginTop="10dp" android:background="#323232" android:layout_toRightOf="@+id/car_ui_scrollbar_thumb" android:layout_above="@+id/car_ui_scrollbar_page_up" android:layout_marginLeft="5dp"/> <ImageView android:id="@+id/car_ui_scrollbar_page_up" android:layout_width="75dp" android:layout_height="75dp" android:focusable="false" android:hapticFeedbackEnabled="false" android:src="@drawable/car_ui_recyclerview_ic_up" android:scaleType="centerInside" android:background="?android:attr/selectableItemBackgroundBorderless" android:layout_centerHorizontal="true" android:layout_above="@+id/car_ui_scrollbar_page_down"/> <ImageView android:id="@+id/car_ui_scrollbar_page_down" android:layout_width="75dp" android:layout_height="75dp" android:focusable="false" android:hapticFeedbackEnabled="false" android:src="@drawable/car_ui_recyclerview_ic_down" android:scaleType="centerInside" android:background="?android:attr/selectableItemBackgroundBorderless" android:layout_centerHorizontal="true" android:layout_alignParentBottom="true"/> </RelativeLayout>
Aby nałożyć plik układu, musisz dodać wszystkie identyfikatory i atrybuty przestrzeni nazw do
overlay.xml
w RRO. Zobacz pliki poniżej.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>
Zalecamy sprawdzenie, jak te pliki ze sobą współdziałają.
Ze względu na prostotę wymiary i kolory są zakodowane na stałe. Najlepszym rozwiązaniem jest jednak zadeklarowanie tych wartości w elementach
dimens.xml
icolors.xml
lub nawet w plikach kolorów w folderzeres/color/
. Więcej informacji znajdziesz w stylu kodu Java AOSP dla autorów.Utwórz i zainstaluj aplikację jak dotąd. Udało Ci się utworzyć
CarUiRecyclerView
z niebieskim paskiem przewijania i szarymi szynami.
Gratulacje! Obie strzałki pojawiają się u dołu suwaka. Oznacza to, że RRO został zastosowany do pliku zasobu układu car-ui-lib
za pomocą systemu kompilacji Gradle w Android Studio.

RRO – elementy listy
Czas trwania: 15 minut
Do tego momentu zastosowałeś/zaaplikowałeś RRO do komponentów car-ui-lib
za pomocą komponentów frameworku (a nie AndroidX). Aby używać komponentów AndroidX w pakiecie RRO, musisz dodać zależności tego komponentu zarówno do aplikacji, jak i do pakietu RRO build.gradle.
. Musisz też dodać attrs
tego komponentu do overlayable.xml
w aplikacji oraz sample_overlay.xml
w pakiecie RRO.
Nasza biblioteka (car-ui-lib
) korzysta z ConstraintLayout
oraz innych komponentów AndroidX, więc jej overlayable.xml
może wyglądać tak:
<?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>
Zmień układ elementów listy w sekcji
CarUiRecyclerView
za pomocą opcjiConstraintLayout
. Dodaj lub zmodyfikuj te pliki w pliku RRO:res/xml/sample_overlay.xml
<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="id/car_ui_list_item_touch_interceptor" value="@id/car_ui_list_item_touch_interceptor"/> <item target="id/car_ui_list_item_reduced_touch_interceptor" value="@id/car_ui_list_item_reduced_touch_interceptor"/> <item target="id/car_ui_list_item_start_guideline" value="@id/car_ui_list_item_start_guideline"/> <item target="id/car_ui_list_item_icon_container" value="@id/car_ui_list_item_icon_container"/> <item target="id/car_ui_list_item_icon" value="@id/car_ui_list_item_icon"/> <item target="id/car_ui_list_item_content_icon" value="@id/car_ui_list_item_content_icon"/> <item target="id/car_ui_list_item_avatar_icon" value="@id/car_ui_list_item_avatar_icon"/> <item target="id/car_ui_list_item_title" value="@id/car_ui_list_item_title"/> <item target="id/car_ui_list_item_body" value="@id/car_ui_list_item_body"/> <item target="id/car_ui_list_item_action_container_touch_interceptor" value="@id/car_ui_list_item_action_container_touch_interceptor"/> <item target="id/car_ui_list_item_action_container" value="@id/car_ui_list_item_action_container"/> <item target="id/car_ui_list_item_action_divider" value="@id/car_ui_list_item_action_divider"/> <item target="id/car_ui_list_item_switch_widget" value="@id/car_ui_list_item_switch_widget"/> <item target="id/car_ui_list_item_checkbox_widget" value="@id/car_ui_list_item_checkbox_widget"/> <item target="id/car_ui_list_item_radio_button_widget" value="@id/car_ui_list_item_radio_button_widget"/> <item target="id/car_ui_list_item_supplemental_icon" value="@id/car_ui_list_item_supplemental_icon"/> <item target="id/car_ui_list_item_end_guideline" value="@id/car_ui_list_item_end_guideline"/> <item target="attr/layout_constraintBottom_toBottomOf" value="@attr/layout_constraintBottom_toBottomOf"/> <item target="attr/layout_constraintBottom_toTopOf" value="@attr/layout_constraintBottom_toTopOf"/> <item target="attr/layout_constraintEnd_toEndOf" value="@attr/layout_constraintEnd_toEndOf"/> <item target="attr/layout_constraintEnd_toStartOf" value="@attr/layout_constraintEnd_toStartOf"/> <item target="attr/layout_constraintGuide_begin" value="@attr/layout_constraintGuide_begin"/> <item target="attr/layout_constraintGuide_end" value="@attr/layout_constraintGuide_end"/> <item target="attr/layout_constraintHorizontal_bias" value="@attr/layout_constraintHorizontal_bias"/> <item target="attr/layout_constraintLeft_toLeftOf" value="@attr/layout_constraintLeft_toLeftOf"/> <item target="attr/layout_constraintLeft_toRightOf" value="@attr/layout_constraintLeft_toRightOf"/> <item target="attr/layout_constraintRight_toLeftOf" value="@attr/layout_constraintRight_toLeftOf"/> <item target="attr/layout_constraintRight_toRightOf" value="@attr/layout_constraintRight_toRightOf"/> <item target="attr/layout_constraintStart_toEndOf" value="@attr/layout_constraintStart_toEndOf"/> <item target="attr/layout_constraintStart_toStartOf" value="@attr/layout_constraintStart_toStartOf"/> <item target="attr/layout_constraintTop_toBottomOf" value="@attr/layout_constraintTop_toBottomOf"/> <item target="attr/layout_constraintTop_toTopOf" value="@attr/layout_constraintTop_toTopOf"/> <item target="attr/layout_goneMarginBottom" value="@attr/layout_goneMarginBottom"/> <item target="attr/layout_goneMarginEnd" value="@attr/layout_goneMarginEnd"/> <item target="attr/layout_goneMarginLeft" value="@attr/layout_goneMarginLeft"/> <item target="attr/layout_goneMarginRight" value="@attr/layout_goneMarginRight"/> <item target="attr/layout_goneMarginStart" value="@attr/layout_goneMarginStart"/> <item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/> <item target="attr/layout_constraintVertical_chainStyle" value="@attr/layout_constraintVertical_chainStyle"/> <item target="layout/car_ui_list_item" value="@layout/car_ui_list_item"/> </overlay>
res/layout/car_ui_list_item.xml
<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="wrap_content" android:tag="carUiListItem" android:minHeight="@dimen/car_ui_list_item_height"> <!-- The following touch interceptor views are sized to encompass the specific sub-sections of the list item view to easily control the bounds of a background ripple effects. --> <com.android.car.ui.SecureView android:id="@+id/car_ui_list_item_touch_interceptor" android:layout_width="0dp" android:layout_height="0dp" android:background="@drawable/car_ui_list_item_background" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <!-- This touch interceptor does not include the action container --> <com.android.car.ui.SecureView android:id="@+id/car_ui_list_item_reduced_touch_interceptor" android:layout_width="0dp" android:layout_height="0dp" android:background="@drawable/car_ui_list_item_background" android:visibility="gone" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@id/car_ui_list_item_action_container" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> <androidx.constraintlayout.widget.Guideline android:id="@+id/car_ui_list_item_start_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_begin="@dimen/car_ui_list_item_start_inset" /> <FrameLayout android:id="@+id/car_ui_list_item_icon_container" android:layout_width="@dimen/car_ui_list_item_icon_container_width" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintStart_toStartOf="@+id/car_ui_list_item_start_guideline" app:layout_constraintTop_toTopOf="parent"> <ImageView android:id="@+id/car_ui_list_item_icon" android:layout_width="@dimen/car_ui_list_item_icon_size" android:layout_height="@dimen/car_ui_list_item_icon_size" android:layout_gravity="center" android:visibility="gone" android:scaleType="fitCenter" /> <ImageView android:id="@+id/car_ui_list_item_content_icon" android:layout_width="@dimen/car_ui_list_item_content_icon_width" android:layout_height="@dimen/car_ui_list_item_content_icon_height" android:layout_gravity="center" android:visibility="gone" android:scaleType="fitCenter" /> <ImageView android:id="@+id/car_ui_list_item_avatar_icon" android:background="@drawable/car_ui_list_item_avatar_icon_outline" android:layout_width="@dimen/car_ui_list_item_avatar_icon_width" android:layout_height="@dimen/car_ui_list_item_avatar_icon_height" android:layout_gravity="center" android:visibility="gone" android:scaleType="fitCenter" /> </FrameLayout> <CarUiTextView android:id="@+id/car_ui_list_item_title" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin" android:singleLine="@bool/car_ui_list_item_single_line_title" android:textAppearance="@style/TextAppearance.CarUi.ListItem" android:layout_gravity="right" android:gravity="right" android:textAlignment="viewEnd" app:layout_constraintBottom_toTopOf="@+id/car_ui_list_item_body" app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container" app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container" app:layout_constraintTop_toTopOf="parent" app:layout_constraintVertical_chainStyle="packed" app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" /> <CarUiTextView android:id="@+id/car_ui_list_item_body" android:layout_width="0dp" android:layout_height="wrap_content" android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin" android:textAppearance="@style/TextAppearance.CarUi.ListItem.Body" android:layout_gravity="right" android:gravity="right" android:textAlignment="viewEnd" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container" app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container" app:layout_constraintTop_toBottomOf="@+id/car_ui_list_item_title" app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" /> <!-- This touch interceptor is sized and positioned to encompass the action container --> <com.android.car.ui.SecureView android:id="@+id/car_ui_list_item_action_container_touch_interceptor" android:layout_width="0dp" android:layout_height="0dp" android:background="@drawable/car_ui_list_item_background" android:visibility="gone" app:layout_constraintBottom_toBottomOf="@id/car_ui_list_item_action_container" app:layout_constraintEnd_toEndOf="@id/car_ui_list_item_action_container" app:layout_constraintStart_toStartOf="@id/car_ui_list_item_action_container" app:layout_constraintTop_toTopOf="@id/car_ui_list_item_action_container" /> <FrameLayout android:id="@+id/car_ui_list_item_action_container" android:layout_width="wrap_content" android:minWidth="@dimen/car_ui_list_item_icon_container_width" android:layout_height="0dp" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="@+id/car_ui_list_item_end_guideline" app:layout_constraintTop_toTopOf="parent"> <View android:id="@+id/car_ui_list_item_action_divider" android:layout_width="@dimen/car_ui_list_item_action_divider_width" android:layout_height="@dimen/car_ui_list_item_action_divider_height" android:layout_gravity="start|center_vertical" android:background="@drawable/car_ui_list_item_divider" /> <Switch android:id="@+id/car_ui_list_item_switch_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:clickable="false" android:focusable="false" /> <CheckBox android:id="@+id/car_ui_list_item_checkbox_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:clickable="false" android:focusable="false" /> <RadioButton android:id="@+id/car_ui_list_item_radio_button_widget" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_gravity="center" android:clickable="false" android:focusable="false" /> <ImageView android:id="@+id/car_ui_list_item_supplemental_icon" android:layout_width="@dimen/car_ui_list_item_supplemental_icon_size" android:layout_height="@dimen/car_ui_list_item_supplemental_icon_size" android:layout_gravity="center" android:scaleType="fitCenter" /> </FrameLayout> <androidx.constraintlayout.widget.Guideline android:id="@+id/car_ui_list_item_end_guideline" android:layout_width="wrap_content" android:layout_height="wrap_content" android:orientation="vertical" app:layout_constraintGuide_end="@dimen/car_ui_list_item_end_inset" /> </androidx.constraintlayout.widget.ConstraintLayout>
car_ui_list_item.xml
odwołuje się do kilku komponentów lub zasobów, które nie są uwzględnione jako zależności aplikacji. Są to zasobycar-ui-lib
. Aby to naprawić, dodajcar-ui-lib
jako zależność aplikacji RRO w plikuapp/build.gradle
:dependencies { implementation 'com.android.car.ui:car-ui-lib:2.0.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.4.0' }
Tytuł i tekst są teraz wyrównane do prawej, a nie do lewej.

RRO zastosowaliśmy tylko do car-ui-lib
korzystającego z komponentów AndroidX (ConstraintLayout
), gdy jego atrybuty były obecne w pliku car-ui-lib
o nazwie overlayable.xml
, a także w pliku RRO sample_overlay.xml
. W swojej aplikacji możesz zrobić coś podobnego. Wystarczy, że dodasz wszystkie odpowiednie attrs
do overlayable.xml
aplikacji, podobnie jak w przypadku car-ui-lib
.
Nie można jednak przekształcać aplikacji korzystającej z komponentów AndroidX, jeśli w jej pliku build.gradle
(gdy aplikacja używa komponentów car-ui-lib
) występuje zależność car-ui-lib
. Mapowania atrybutów zostały już zdefiniowane w bibliotece car-ui-lib
(overlayable.xml
), więc dodanie ich do overlayable.xml
aplikacji z zależnością car-ui-lib
spowoduje błąd mergeDebugResources
podobny do tego poniżej. Dzieje się tak, ponieważ te atrybuty występują w kilku plikach overlayable.xml
:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'