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-libw 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.xmltym 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_texti ustaw go na „Hello World!” w pliku- strings.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-libdo pliku- build.gradleprojektu, 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.javazastą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 element- AndroidManifest.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.xmli 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_textmusi być nakładany przez RRO, dlatego dodaj nazwę zasobu w pliku overlayable.xml aplikacji.- Plik - overlayable.xmlMUSI znajdować się w folderze- res/values/. Jeśli nie,- OverlayManagerServicenie 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 - CarUiRROoznaj go jako RRO, modyfikując plik- AndroidManifest.xml.- <?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.caruirro"> <application android:hasCode="false" /> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <overlay android:targetPackage="com.example.caruicodelab" android:targetName="CarUiCodelab" android:isStatic="false" android:resourcesMap="@xml/sample_overlay" /> </manifest>- Spowoduje to błąd w usłudze - @xml/sample_overlay. Plik- resourcesMapmapuje nazwy zasobów z docelowego pakietu do pakietu RRO. W przypadku pakietów RRO obowiązkowe jest ustawienie flagi- hasCodena- false. 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_textdo- …/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-libzawiera zasób o nazwie- car_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.xmldla RRO zaktualizuj element- targetName, aby wskazywał adres- car-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.xmlte 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.xmlwyglą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.xmli 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ń - targetNamew- AndroidManifest.xml, aby wskazywało nazwę nowej aplikacji:- … android:targetName="CarUiCodelab" …
- Dodaj zasoby do pliku - sample_overlay.xmlw 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 CarUiRecyclerViewsprawdza 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ów- activity_main.xmli- MainActivity.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 elementu- 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"/>- 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-libjako 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_enableto zasób logiczny- car-ui-lib, który określa, czy suwak z przyciskami w górę i w dół zoptymalizowany pod kątem samochodów jest obecny w- CarUiRecyclerView. Gdy ustawisz wartość- false,- CarUiRecyclerViewbędzie działać jak 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>
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.xmlw 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.xmli- colors.xmllub nawet w plikach kolorów w folderze- res/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ć - CarUiRecyclerViewz 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 - CarUiRecyclerViewza pomocą opcji- ConstraintLayout. 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.xmlodwołuje się do kilku komponentów lub zasobów, które nie są uwzględnione jako zależności aplikacji. Są to zasoby- car-ui-lib. Aby to naprawić, dodaj- car-ui-libjako zależność aplikacji RRO w pliku- app/build.gradle:- dependencies { implementation 'com.android.car.ui:car-ui-lib:2.0.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.4.0' }
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'
