Ćwiczenie z programowania: tworzenie RRO z komponentami car-ui-lib przy użyciu systemu kompilacji Gradle

Korzystaj z biblioteki car-ui-lib, aby wprowadzać spójne funkcje multimedialne w pojazdach (IVI). Dzięki tym ćwiczeniom w Codelabs poznasz car-ui-lib i dowiesz się, jak za pomocą nakładek zasobów środowiska wykonawczego (RRO) w celu dostosowania komponentów w bibliotece

Czego się nauczysz

Instrukcje:

  • Dodaj komponenty car-ui-lib do swojej aplikacji na Androida.
  • Używaj Gradle do tworzenia aplikacji na Androida i RRO.
  • Używaj RRO w car-ui-lib.

To ćwiczenie w Codelabs nie opisuje szczegółowo, jak działają RRO. Zobacz zmieniać wartość zasobów aplikacji w czasie działania; Rozwiązywanie problemów z nakładkami zasobów środowiska wykonawczego aby dowiedzieć się więcej.

Zanim rozpoczniesz

Wymagania wstępne

Zanim zaczniesz, upewnij się, że:

Utwórz nową aplikację na Androida

Czas trwania: 15 minut

W tej sekcji utworzysz nowy projekt Android Studio.

  1. W Android Studio utwórz aplikację za pomocą interfejsu EmptyActivity.

    Utwórz pustą aktywność
    Rysunek 1.Tworzenie pustej aktywności
  2. Nazwij aplikację CarUiCodelab i wybierz język Java. Dostępne opcje i w razie potrzeby wybierz lokalizację pliku. Zaakceptuj domyślne wartości dla parametru pozostałych ustawień.

     Nazwij aplikację
    Rysunek 2. Nazwij aplikację
    .
  3. 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 sample_text, który nie został zdefiniowany.

  4. Dodaj ciąg zasobów sample_text i ustaw go na „Hello, World!” w strings.xml. Aby otworzyć ten plik, wybierz aplikacja > src > główny > res > wartości > string.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiCodelab</string>
        <string name="sample_text">Hello World!</string>
    </resources>
    
  5. Aby utworzyć aplikację, w prawym górnym rogu kliknij zielony przycisk Zagraj. Robię to automatycznie instaluje plik APK w emulatorze lub na urządzeniu z Androidem za pomocą Gradle.

    Przycisk odtwarzania

Nowa aplikacja powinna otworzyć się automatycznie w emulatorze lub na urządzeniu z Androidem. Jeśli nie, otwórz aplikację CarUiCodelab z poziomu menu z aplikacjami, który jest teraz zainstalowany. Wygląda on tak:

Otwórz nową aplikację CarUiCodelab
Rysunek 3. Otwórz nową aplikację CarUiCodelab
.

Dodawanie car-ui-lib do aplikacji na Androida

Czas trwania: 15 minut

Dodaj car-ui-lib do swojej aplikacji:

  1. Aby dodać zależność car-ui-lib do pliku build.gradle projektu: wybierz aplikacja > build.gradle. Zależności powinny 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'
    }
    

Używanie komponentów car-ui-lib w aplikacji na Androida

Teraz gdy masz już aplikację car-ui-lib, dodaj do niej pasek narzędzi.

  1. 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);
    }
    
  2. Pamiętaj, aby zaimportować ToolbarController:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Aby użyć motywu Theme.CarUi.WithToolbar, wybierz aplikacja > src > główna > Plik AndroidManifest.xml, a następnie zaktualizuj AndroidManifest.xml będą 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>
    
  4. Aby utworzyć aplikację, naciśnij zielony przycisk Zagraj tak jak poprzednio.

    Utwórz aplikację

Dodaj RRO do aplikacji

Czas trwania: 30 minut

Jeśli korzystasz już z RRO, przejdź do następnego sekcji, Dodaj do aplikacji kontroler uprawnień. W przeciwnym razie, aby poznać podstawowe informacje na temat RRO, zapoznaj się z artykułem zmieniać wartość zasobów aplikacji w czasie działania;

Dodaj kontroler uprawnień do aplikacji

Aby kontrolować, które zasoby są nakładane na pakiety RRO, dodaj plik o nazwie overlayable.xml do folderu /res aplikacji. Ten plik służy jako uprawnienie między aplikacją (elementem docelowym) a pakietem RRO (nakładką).

  1. Dodaj res/values/overlayable.xml do swojej aplikacji i skopiuj tę treść do pliku:

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

    Ponieważ ciąg sample_text musi być nakładany przez RRO, umieść makro w nazwie zasobu w plikuOverlayable.xml aplikacji.

    Twój plik z overlayable.xml MUSI znajdować się w regionie res/values/. Jeśli nie, parametr OverlayManagerService nie może go znaleźć.

    Dowiedz się więcej o zasobach, które można nakładać, i o tym, jak można je skonfigurowane, patrz Ograniczanie możliwości nakładania .

Utwórz pakiet RRO

W tej sekcji utworzysz pakiet RRO, aby zmienić wyświetlany powyżej ciąg znaków z filmu „Hello, World!” do „Hello World RRO”.

  1. Aby utworzyć nowy projekt, wybierz Plik > Nowe > Nowy projekt. Koniecznie wybierz Brak aktywności zamiast pustej aktywności, ponieważ pakiety RRO zawierają i tylko zasoby.

    Twoje konfiguracje są podobne do tych na ilustracji poniżej. lokalizacja, w której są zapisywane, może się różnić:

  2. Po utworzeniu nowego projektu CarUiRRO zadeklaruj go jako RRO przez modyfikację 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>
    

    Powoduje to błąd w zasadzie @xml/sample_overlay. resourcesMap mapuje nazwy zasobów z pakietu docelowego na pakiet RRO.

  3. Skopiuj ten blok kodu do …/res/xml/sample_overlay.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
    </overlay>
    
  4. 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>
    
    Utworzono kompilację Gradle dla RRO
  5. Aby utworzyć wartość docelową RRO, naciśnij zielony przycisk Zagraj w celu utworzenia Gradle. ale możesz utworzyć własną wersję RRO w emulatorze lub na urządzeniu z Androidem.

  6. Aby sprawdzić, czy RRO jest prawidłowo zainstalowane, uruchom polecenie:

    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 zainstalowana i gotowa do aktywacji.
    • --- oznacza, że RRO jest zainstalowana, ale zawiera błędy.
    • [X] oznacza, że RRO została zainstalowana i aktywowana.

    Jeśli RRO zawiera błędy, zapoznaj się z Rozwiązywanie problemów z nakładkami zasobów środowiska wykonawczego zanim przejdziesz dalej.

  7. Aby włączyć RRO i sprawdzić, czy jest włączony:

    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świetli ciąg „Hello World RRO”.

Witaj świecie, RRO!
Rysunek 4. Hello World (RRO)

Gratulacje! Udało Ci się utworzyć pierwszą reklamę RRO.

Jeśli używasz RRO, warto używać narzędzia Android Asset Packaging Tool (AAPT2) flagi --no-resource-deduping i --no-resource-removal opisane w Opcje linków. W tym ćwiczeniu w programie nie musisz dodawać flag, ale zalecamy ich użycie w RRO, aby uniknąć usuwania zasobów (i rozwiązywania problemów). Ty możesz je dodać do pliku RRO build.gradle w ten sposób:

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

Więcej informacji o tych flagach znajdziesz na stronie Utwórz pakiet AAPT2

Modyfikowanie komponentów car-ui-lib za pomocą RRO w aplikacji na Androida

Na tej stronie dowiesz się, jak używać nakładki zasobów środowiska wykonawczego do modyfikować komponenty z biblioteki car-ui-lib w aplikacji na Androida.

Ustaw kolor tła paska narzędzi

Czas trwania: 15 minut

Aby zmienić kolor tła paska narzędzi:

  1. Dodaj poniższą wartość do aplikacji RRO i ustaw jasność zasobu zielony (#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 nazwie car_ui_toolbar_background Gdy zasób znajdzie się w sekcji konfiguracji RRO, pasek narzędzi nie zmienia się, ponieważ błędna wartość reklamy są kierowane.

  2. W polu AndroidManifest.xml dla RRO zaktualizuj targetName, tak by wskazywał car-ui-lib:

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

    Musisz utworzyć nowy pakiet RRO dla każdego pakietu docelowego, który chcesz w nim kierować. Na przykład przy tworzeniu nakładek dla dwóch różnych celów musisz utworzyć dwa pliki APK nakładane.

  3. Zbuduj, zweryfikuj, zainstaluj i włącz RRO w taki sam sposób jak wcześniej.

Twoja aplikacja wygląda tak:

Nowy kolor tła paska narzędzi Toolbar
Rys. 5. Nowy kolor tła paska narzędzi

Układy i style RRO

Czas trwania: 15 minut

W tym ćwiczeniu tworzysz nową aplikację podobną do tej, którą stworzyłeś wcześniej. Ten umożliwia nakładanie się układu. Wykonaj te same czynności co poprzednio lub zmodyfikuj istniejącej aplikacji.

  1. Pamiętaj, aby dodać 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>
    
  2. Sprawdź, czy 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>
    
  3. W aplikacji RRO utwórz res/layout/activity_main.xml i dodaj do :

    <?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. Zaktualizuj aplikację 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>
    
  5. Zmień targetName w AndroidManifest.xml, by wskazywał nazwę nowa aplikacja:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Dodaj zasoby do pliku sample_overlay.xml w RRO:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
        <item target="id/textView" value="@id/textView"/>
        <item target="layout/activity_main" value="@layout/activity_main"/>
    </overlay>
    
  7. Skompiluj i zainstaluj aplikację oraz wskaźnik RRO w taki sam sposób jak wcześniej (zielony przycisk Play). ). Pamiętaj, aby włączyć RRO.

Aplikacja i RRO renderują się w ten sposób. Tekst RRO „Hello World” ma kolor zielony i jest jest wyśrodkowany zgodnie z wartością RRO układu.

Hello World
Rysunek 6. Hello World RRO

Dodaj CarUiRecyclerView do swojej aplikacji

Czas trwania: 15 minut

Interfejs CarUiRecyclerView udostępnia interfejsy API umożliwiające dostęp do RecyclerView które są dostosowywane na podstawie materiałów z car-ui-lib. Na przykład: CarUiRecyclerView sprawdza flagę w czasie działania, aby określić, czy pasek przewijania powinien być włączony i wybiera odpowiedni układ.

Kontener CarUiRecyclerViewContainer
Rysunek 7. CarUiRecyclerViewContainer
.
  1. Aby dodać usługę CarUiRecyclerView, dodaj ją do aplikacji activity_main.xml i MainActivity.java plików. Możesz utworzyć nową aplikację od zera lub modyfikować istniejącą aplikację. Jeśli modyfikujesz istniejącą aplikację, pamiętaj, aby usunąć niezadeklarowane zasoby z projektu 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 zajęcia są poprawnie napisane i dodano car-ui-lib jako możesz utworzyć i skompilować pakiet apk. Aby usunąć ten błąd, wybierz Plik > Unieważnij pamięci podręczne, a następnie kliknij Unieważnij i uruchom ponownie.

    Dodaj do MainActivity.java te elementy

    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. Skompiluj i zainstaluj aplikację tak jak poprzednio.

Wyświetlana jest teraz CarUiRecyclerView:

Widok systemu CarUiRecyclerView
Rysunek 7. : CarUiRecyclerView

Aby usunąć pasek przewijania, użyj RRO

Czas trwania: 10 minut

To ćwiczenie pokazuje, jak za pomocą RRO usunąć pasek przewijania CarUiRecyclerView

  1. W 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 jest zasobem logicznym car-ui-lib, który określa, czy samochód optymalizuje pasek przewijania (w górę i w dół) w CarUiRecyclerView jest albo nie ma. Gdy ustawisz wartość false, CarUiRecyclerView działa jak RecyclerView AndroidaX.

    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>
    

Skompiluj i zainstaluj aplikację tak jak poprzednio. Pasek przewijania został usunięty z CarUiRecyclerView:

CarUiRecyclerView bez paska przewijania
Rysunek 8. CarUiRecyclerView bez paska przewijania
.

Użyj układu, aby nakładać na pasek przewijania CarUiRecyclerView

Czas trwania: 15 minut

W tym ćwiczeniu zmienisz układ paska przewijania CarUiRecyclerView.

  1. 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 nakładać plik układu, musisz dodać wszystkie identyfikatory i przestrzeń nazw wartość atrybutu overlay.xml 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 współdziałają te pliki.

    Dla uproszczenia wymiary i kolory są zakodowane na stałe. Najlepiej jednak praktyką jest zadeklarowanie tych wartości w polach dimens.xml i colors.xml lub nawet oznaczonych jako pliki koloru w folderze res/color/. Aby dowiedzieć się więcej, zobacz Styl kodu Java AOSP dla współtwórców.

  2. Skompiluj i zainstaluj aplikację tak jak poprzednio. Udało Ci się zbudować aplikację CarUiRecyclerView z niebieskim paskiem przewijania i szarymi szynami.

Gratulacje! Obie strzałki pojawiają się u dołu paska przewijania. udało się zastosować RRO do pliku zasobów układu car-ui-lib za pomocą kompilacji Gradle za pomocą Android Studio.

CarUiRecyclerView z niebieskim paskiem przewijania i szarymi szynami
Rysunek 9. CarUiRecyclerView z niebieskim paskiem przewijania i szarymi szynami.
.

Pozycje listy RRO

Czas trwania: 15 minut

Do tej pory zastosowaliśmy RRO do car-ui-lib komponentów za pomocą platformy komponentów (nie AndroidX). Aby w ARRO używać komponentów AndroidaX, musisz dodać zależności tego komponentu zarówno od aplikacji, jak i do RRO build.gradle. należy też dodać do komponentu attrs tego komponentu do elementu overlayable.xml w swojej aplikacji, jako sample_overlay.xml w RRO.

Nasza biblioteka (car-ui-lib) używa ConstraintLayout i innych AndroidaX komponentów, więc jego 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>
  1. Zmień układ elementów listy w CarUiRecyclerView za pomocą ConstraintLayout Dodaj lub zmodyfikuj te pliki w RRO:

    res/xml/sample_overlay.xml

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
       <item target="id/car_ui_list_item_touch_interceptor" value="@id/car_ui_list_item_touch_interceptor"/>
       <item target="id/car_ui_list_item_reduced_touch_interceptor" value="@id/car_ui_list_item_reduced_touch_interceptor"/>
       <item target="id/car_ui_list_item_start_guideline" value="@id/car_ui_list_item_start_guideline"/>
       <item target="id/car_ui_list_item_icon_container" value="@id/car_ui_list_item_icon_container"/>
       <item target="id/car_ui_list_item_icon" value="@id/car_ui_list_item_icon"/>
       <item target="id/car_ui_list_item_content_icon" value="@id/car_ui_list_item_content_icon"/>
       <item target="id/car_ui_list_item_avatar_icon" value="@id/car_ui_list_item_avatar_icon"/>
       <item target="id/car_ui_list_item_title" value="@id/car_ui_list_item_title"/>
       <item target="id/car_ui_list_item_body" value="@id/car_ui_list_item_body"/>
       <item target="id/car_ui_list_item_action_container_touch_interceptor" value="@id/car_ui_list_item_action_container_touch_interceptor"/>
       <item target="id/car_ui_list_item_action_container" value="@id/car_ui_list_item_action_container"/>
       <item target="id/car_ui_list_item_action_divider" value="@id/car_ui_list_item_action_divider"/>
       <item target="id/car_ui_list_item_switch_widget" value="@id/car_ui_list_item_switch_widget"/>
       <item target="id/car_ui_list_item_checkbox_widget" value="@id/car_ui_list_item_checkbox_widget"/>
       <item target="id/car_ui_list_item_radio_button_widget" value="@id/car_ui_list_item_radio_button_widget"/>
       <item target="id/car_ui_list_item_supplemental_icon" value="@id/car_ui_list_item_supplemental_icon"/>
       <item target="id/car_ui_list_item_end_guideline" value="@id/car_ui_list_item_end_guideline"/>
       <item target="attr/layout_constraintBottom_toBottomOf" value="@attr/layout_constraintBottom_toBottomOf"/>
       <item target="attr/layout_constraintBottom_toTopOf" value="@attr/layout_constraintBottom_toTopOf"/>
       <item target="attr/layout_constraintEnd_toEndOf" value="@attr/layout_constraintEnd_toEndOf"/>
       <item target="attr/layout_constraintEnd_toStartOf" value="@attr/layout_constraintEnd_toStartOf"/>
       <item target="attr/layout_constraintGuide_begin" value="@attr/layout_constraintGuide_begin"/>
       <item target="attr/layout_constraintGuide_end" value="@attr/layout_constraintGuide_end"/>
       <item target="attr/layout_constraintHorizontal_bias" value="@attr/layout_constraintHorizontal_bias"/>
       <item target="attr/layout_constraintLeft_toLeftOf" value="@attr/layout_constraintLeft_toLeftOf"/>
       <item target="attr/layout_constraintLeft_toRightOf" value="@attr/layout_constraintLeft_toRightOf"/>
       <item target="attr/layout_constraintRight_toLeftOf" value="@attr/layout_constraintRight_toLeftOf"/>
       <item target="attr/layout_constraintRight_toRightOf" value="@attr/layout_constraintRight_toRightOf"/>
       <item target="attr/layout_constraintStart_toEndOf" value="@attr/layout_constraintStart_toEndOf"/>
       <item target="attr/layout_constraintStart_toStartOf" value="@attr/layout_constraintStart_toStartOf"/>
       <item target="attr/layout_constraintTop_toBottomOf" value="@attr/layout_constraintTop_toBottomOf"/>
       <item target="attr/layout_constraintTop_toTopOf" value="@attr/layout_constraintTop_toTopOf"/>
       <item target="attr/layout_goneMarginBottom" value="@attr/layout_goneMarginBottom"/>
       <item target="attr/layout_goneMarginEnd" value="@attr/layout_goneMarginEnd"/>
       <item target="attr/layout_goneMarginLeft" value="@attr/layout_goneMarginLeft"/>
       <item target="attr/layout_goneMarginRight" value="@attr/layout_goneMarginRight"/>
       <item target="attr/layout_goneMarginStart" value="@attr/layout_goneMarginStart"/>
       <item target="attr/layout_goneMarginTop" value="@attr/layout_goneMarginTop"/>
       <item target="attr/layout_constraintVertical_chainStyle" value="@attr/layout_constraintVertical_chainStyle"/>
       <item target="layout/car_ui_list_item" value="@layout/car_ui_list_item"/>
    </overlay>
    

    res/layout/car_ui_list_item.xml

    <?xml version="1.0" encoding="utf-8"?>
    <androidx.constraintlayout.widget.ConstraintLayout
        xmlns:android="http://schemas.android.com/apk/res/android"
        xmlns:app="http://schemas.android.com/apk/res-auto"
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:tag="carUiListItem"
        android:minHeight="@dimen/car_ui_list_item_height">
    
        <!-- The following touch interceptor views are sized to encompass the specific sub-sections of
        the list item view to easily control the bounds of a background ripple effects. -->
        <com.android.car.ui.SecureView
            android:id="@+id/car_ui_list_item_touch_interceptor"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/car_ui_list_item_background"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="parent"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <!-- This touch interceptor does not include the action container -->
        <com.android.car.ui.SecureView
            android:id="@+id/car_ui_list_item_reduced_touch_interceptor"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/car_ui_list_item_background"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@id/car_ui_list_item_action_container"
            app:layout_constraintStart_toStartOf="parent"
            app:layout_constraintTop_toTopOf="parent" />
    
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/car_ui_list_item_start_guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_begin="@dimen/car_ui_list_item_start_inset" />
    
        <FrameLayout
            android:id="@+id/car_ui_list_item_icon_container"
            android:layout_width="@dimen/car_ui_list_item_icon_container_width"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintStart_toStartOf="@+id/car_ui_list_item_start_guideline"
            app:layout_constraintTop_toTopOf="parent">
    
            <ImageView
                android:id="@+id/car_ui_list_item_icon"
                android:layout_width="@dimen/car_ui_list_item_icon_size"
                android:layout_height="@dimen/car_ui_list_item_icon_size"
                android:layout_gravity="center"
                android:visibility="gone"
                android:scaleType="fitCenter" />
    
            <ImageView
                android:id="@+id/car_ui_list_item_content_icon"
                android:layout_width="@dimen/car_ui_list_item_content_icon_width"
                android:layout_height="@dimen/car_ui_list_item_content_icon_height"
                android:layout_gravity="center"
                android:visibility="gone"
                android:scaleType="fitCenter" />
    
            <ImageView
                android:id="@+id/car_ui_list_item_avatar_icon"
                android:background="@drawable/car_ui_list_item_avatar_icon_outline"
                android:layout_width="@dimen/car_ui_list_item_avatar_icon_width"
                android:layout_height="@dimen/car_ui_list_item_avatar_icon_height"
                android:layout_gravity="center"
                android:visibility="gone"
                android:scaleType="fitCenter" />
        </FrameLayout>
    
        <CarUiTextView
            android:id="@+id/car_ui_list_item_title"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin"
            android:singleLine="@bool/car_ui_list_item_single_line_title"
            android:textAppearance="@style/TextAppearance.CarUi.ListItem"
            android:layout_gravity="right"
            android:gravity="right"
            android:textAlignment="viewEnd"
            app:layout_constraintBottom_toTopOf="@+id/car_ui_list_item_body"
            app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container"
            app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container"
            app:layout_constraintTop_toTopOf="parent"
            app:layout_constraintVertical_chainStyle="packed"
            app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" />
        <CarUiTextView
            android:id="@+id/car_ui_list_item_body"
            android:layout_width="0dp"
            android:layout_height="wrap_content"
            android:layout_marginStart="@dimen/car_ui_list_item_text_start_margin"
            android:textAppearance="@style/TextAppearance.CarUi.ListItem.Body"
            android:layout_gravity="right"
            android:gravity="right"
            android:textAlignment="viewEnd"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toStartOf="@+id/car_ui_list_item_action_container"
            app:layout_constraintStart_toEndOf="@+id/car_ui_list_item_icon_container"
            app:layout_constraintTop_toBottomOf="@+id/car_ui_list_item_title"
            app:layout_goneMarginStart="@dimen/car_ui_list_item_text_no_icon_start_margin" />
    
        <!-- This touch interceptor is sized and positioned to encompass the action container   -->
        <com.android.car.ui.SecureView
            android:id="@+id/car_ui_list_item_action_container_touch_interceptor"
            android:layout_width="0dp"
            android:layout_height="0dp"
            android:background="@drawable/car_ui_list_item_background"
            android:visibility="gone"
            app:layout_constraintBottom_toBottomOf="@id/car_ui_list_item_action_container"
            app:layout_constraintEnd_toEndOf="@id/car_ui_list_item_action_container"
            app:layout_constraintStart_toStartOf="@id/car_ui_list_item_action_container"
            app:layout_constraintTop_toTopOf="@id/car_ui_list_item_action_container" />
    
        <FrameLayout
            android:id="@+id/car_ui_list_item_action_container"
            android:layout_width="wrap_content"
            android:minWidth="@dimen/car_ui_list_item_icon_container_width"
            android:layout_height="0dp"
            app:layout_constraintBottom_toBottomOf="parent"
            app:layout_constraintEnd_toEndOf="@+id/car_ui_list_item_end_guideline"
            app:layout_constraintTop_toTopOf="parent">
    
            <View
                android:id="@+id/car_ui_list_item_action_divider"
                android:layout_width="@dimen/car_ui_list_item_action_divider_width"
                android:layout_height="@dimen/car_ui_list_item_action_divider_height"
                android:layout_gravity="start|center_vertical"
                android:background="@drawable/car_ui_list_item_divider" />
    
            <Switch
                android:id="@+id/car_ui_list_item_switch_widget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:clickable="false"
                android:focusable="false" />
    
            <CheckBox
                android:id="@+id/car_ui_list_item_checkbox_widget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:clickable="false"
                android:focusable="false" />
    
            <RadioButton
                android:id="@+id/car_ui_list_item_radio_button_widget"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_gravity="center"
                android:clickable="false"
                android:focusable="false" />
    
            <ImageView
                android:id="@+id/car_ui_list_item_supplemental_icon"
                android:layout_width="@dimen/car_ui_list_item_supplemental_icon_size"
                android:layout_height="@dimen/car_ui_list_item_supplemental_icon_size"
                android:layout_gravity="center"
                android:scaleType="fitCenter" />
        </FrameLayout>
    
        <androidx.constraintlayout.widget.Guideline
            android:id="@+id/car_ui_list_item_end_guideline"
            android:layout_width="wrap_content"
            android:layout_height="wrap_content"
            android:orientation="vertical"
            app:layout_constraintGuide_end="@dimen/car_ui_list_item_end_inset" />
    
    </androidx.constraintlayout.widget.ConstraintLayout>
    
  2. car_ui_list_item.xml odwołuje się do kilku elementów, które odwołują się do kilku komponentów/ zasobów, które nie są uwzględnione jako zależności aplikacji. Oto car-ui-lib zasoby. Możesz to naprawić, dodając użytkownika car-ui-lib jako zależność od aplikacji RRO w 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 treść są teraz wyrównane do prawej, a nie do lewej.

Tytuł i treść wyrównane do prawej
Rysunek 10. Tytuł i treść wyrównane do prawej
.

Do aplikacji car-ui-lib zastosowaliśmy RRO tylko przy użyciu komponentów AndroidaX (ConstraintLayout), gdy jego atrybuty znajdowały się w car-ui-lib o nazwie overlayable.xml oraz RRO sample_overlay.xml. Jest zrobić coś podobnego we własnej aplikacji. Wystarczy dodać wszystkie attrs w stosunku do wskaźników overlayable.xml Twojej aplikacji, podobnie jak w przypadku car-ui-lib.

Nie można jednak wykonać takiej operacji w przypadku aplikacji, która korzysta z komponentów Androida X, aplikacja car-ui-lib jest uzależniona od build.gradle (gdy aplikacja korzysta car-ui-lib komponentów). Ponieważ mapowania atrybutów zostały już zdefiniowane w overlayable.xml z biblioteki car-ui-lib, dodaję je do overlayable.xml aplikacji z zależnością car-ui-lib spowodowałby mergeDebugResources podobny błąd poniżej. To dlatego, że te atrybuty znajdują się w kilku plikach overlayable.xml:

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