אפשר להשתמש בספרייה car-ui-lib
כדי להפעיל מערכות מידע ובידור (IVI) עקביות בתוך הרכב. בקודלאב הזה תלמדו על car-ui-lib
ועל האופן שבו אפשר להשתמש בשכבות-על של משאבים בסביבת זמן הריצה (RRO) כדי להתאים אישית רכיבים בספרייה.
מה תלמדו
איך:
- מוסיפים רכיבי
car-ui-lib
לאפליקציה ל-Android. - שימוש ב-Gradle ליצירת אפליקציות Android ו-RRO.
- שימוש ב-RRO עם
car-ui-lib
.
בקודלאב הזה לא מוסבר בפירוט איך פועלים קובצי RRO. למידע נוסף, ראו שינוי הערך של משאבי האפליקציה בזמן הריצה ופתרון בעיות של שכבות-על של משאבים בזמן הריצה.
לפני שמתחילים
דרישות מוקדמות
לפני שמתחילים, חשוב לוודא שיש לכם:
מחשב עם שורת פקודה (מכונה עם Linux, Mac או Windows עם Windows Subsystem for Linux).
מכשיר Android או אמולטור שמחוברים למחשב. אפשר לעיין במאמרים הורדת קוד המקור של Android ופיתוח Android.
ידע בסיסי בנושא RRO.
יצירת אפליקציה חדשה ל-Android
משך: 15 דקות
בקטע הזה יוצרים פרויקט חדש ב-Android Studio.
יוצרים אפליקציה עם
EmptyActivity
ב-Android Studio.איור 1.יצירת פעילות ריקה נותנים לאפליקציה את השם
CarUiCodelab
ובוחרים את שפת Java. אפשר גם לבחור מיקום לקובץ. מאשרים את ערכי ברירת המחדל של ההגדרות הנותרות.איור 2. נותנים שם לאפליקציה מחליפים את
activity_main.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" 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>
בקוד הזה מוצגת המחרוזת
sample_text
, שלא מוגדרת.מוסיפים את מחרוזת המשאב
sample_text
ומגדירים אותה כ-'Hello World!' בקובץstrings.xml
. כדי לפתוח את הקובץ הזה, בוחרים באפשרות app > 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>
כדי ליצור את האפליקציה, לוחצים על הלחצן הירוק Play בפינה השמאלית העליונה. הפעולה הזו מתקינה את קובץ ה-APK באופן אוטומטי במהדמ או במכשיר Android דרך Gradle.
האפליקציה החדשה אמורה להיפתח באופן אוטומטי במהדורת האפליקציה לנייד או במכשיר Android. אם לא, פותחים את האפליקציה CarUiCodelab
ממרכז האפליקציות, שכבר מותקן.
הוא נראה כך:

הוספת car-ui-lib לאפליקציה ל-Android
משך: 15 דקות
מוסיפים את car-ui-lib
לאפליקציה:
כדי להוסיף את התלות ב-
car-ui-lib
לקובץbuild.gradle
של הפרויקט, בוחרים באפשרות 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' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' }
שימוש ברכיבים של car-ui-lib באפליקציה ל-Android
עכשיו, אחרי שהוספתם את car-ui-lib
, תוכלו להוסיף סרגל כלים לאפליקציה.
בקובץ
MainActivity.java
, מחליפים את השיטה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); }
חשוב לייבא את
ToolbarController
:import com.android.car.ui.core.CarUi; import com.android.car.ui.toolbar.ToolbarController;
כדי להשתמש בעיצוב
Theme.CarUi.WithToolbar
, בוחרים באפשרות app > src > main > AndroidManifest.xml ומעדכנים אתAndroidManifest.xml
כך שיופיע באופן הבא:<?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>
כדי ליצור את האפליקציה, לוחצים על הלחצן הירוק Play כמו קודם.
הוספת RROs לאפליקציה
משך: 30 דקות
אם אתם מכירים את קובצי ה-RRO, תוכלו לעבור לקטע הבא, הוספת רכיב לבקרת הרשאות לאפליקציה. אחרת, תוכלו לקרוא את המאמר שינוי הערך של המשאבים של אפליקציה בזמן הריצה כדי ללמוד את העקרונות הבסיסיים של קובצי RRO.
הוספת פקטור בקרה על הרשאות לאפליקציה
כדי לקבוע אילו משאבים חבילה של RRO תוסיף לשכבה, מוסיפים קובץ בשם overlayable.xml
לתיקייה /res
של האפליקציה. הקובץ הזה משמש כאמצעי לבקרת ההרשאות בין האפליקציה (היעד) לבין חבילת ה-RRO (שכבת-העל).
מוסיפים את
res/values/overlayable.xml
לאפליקציה ומעתיקים את התוכן הבא לקובץ:<?xml version="1.0" encoding="utf-8"?> <resources> <overlayable name="CarUiCodelab"> <policy type="public"> <item type="string" name="sample_text"/> </policy> </overlayable> </resources>
מאחר שאפשר להציג את המחרוזת
sample_text
בשכבת-על באמצעות RRO, צריך לכלול את שם המשאב בקובץ overlayable.xml של האפליקציה.קובץ
overlayable.xml
חייב להיות ב-res/values/
. אם לא, ה-OverlayManagerService
לא יוכל לאתר אותו.מידע נוסף על משאבים שאפשר להציג שכבה-על שלהם ועל האופן שבו אפשר להגדיר אותם זמין במאמר הגבלת משאבים שאפשר להציג שכבה-על שלהם.
יצירת חבילת RRO
בקטע הזה יוצרים חבילת RRO כדי לשנות את המחרוזת שמוצגת למעלה מ-'Hello World!' ל-'Hello World RRO'.
כדי ליצור פרויקט חדש, בוחרים באפשרות קובץ > חדש > פרויקט חדש. חשוב לבחור באפשרות No Activity במקום באפשרות Empty Activity, כי חבילות RRO מכילות רק משאבים.
ההגדרות שלכם ייראו דומות לאלה שמפורטות בהמשך. המיקום שבו הם נשמרים עשוי להיות שונה:
אחרי שיוצרים את הפרויקט החדש
CarUiRRO
, צריך לשנות אתAndroidManifest.xml
כדי להצהיר על הפרויקט כ-RRO.<?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>
הפעולה הזו תיצור שגיאה ב-
@xml/sample_overlay
. הקובץresourcesMap
ממפה את שמות המשאבים מחבילת היעד לחבילת ה-RRO. חובה להגדיר את הדגלhasCode
לערךfalse
בחבילות RRO. בנוסף, אסור שחבילות RRO יכילו קובצי DEX.מעתיקים את קטע הקוד הבא אל
…/res/xml/sample_overlay.xml
:<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="string/sample_text" value="@string/sample_text"/> </overlay>
מוסיפים את
sample_text
ל-…/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>
כדי ליצור את היעד של ה-RRO, לוחצים על הלחצן הירוק Play כדי ליצור build של Gradle של ה-RRO במהדורה של Android או במהדורה של Android ב-emulator.
כדי לוודא שה-RRO מותקן כמו שצריך, מריצים את הפקודה:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirro
הפקודה הזו מציגה מידע שימושי על מצב החבילות של RRO במערכת.
- הערך
[ ]
מציין שה-RRO מותקן ומוכן להפעלה. ---
מציין שה-RRO מותקן אבל מכיל שגיאות.[X]
מציין שה-RRO מותקן ומופעל.
אם קובץ ה-RRO מכיל שגיאות, כדאי לעיין במאמר פתרון בעיות בשכבות-על של משאבים בסביבת זמן ריצה לפני שממשיכים.
- הערך
כדי להפעיל את ה-RRO ולוודא שהוא מופעל:
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
באפליקציה תוצג המחרוזת 'Hello World RRO'.

מזל טוב! יצרתם את ה-RRO הראשון.
כשמשתמשים ב-RRO, מומלץ להשתמש בדגלים --no-resource-deduping
ו---no-resource-removal
של Android Asset Packaging Tool (AAPT2) שמפורטים בקטע אפשרויות קישור.
אין צורך להוסיף את הדגלים ב-codelab הזה, אבל מומלץ להשתמש בהם ב-RRO כדי למנוע הסרה של משאבים (והרבה כאבי ראש בניפוי באגים). אפשר להוסיף אותם לקובץ build.gradle
של ה-RRO באופן הבא:
android {
…
aaptOptions {
additionalParameters "--no-resource-deduping", "--no-resource-removal"
}
}
מידע נוסף על הדגלים האלה זמין במאמרים יצירת החבילה וAAPT2.
שינוי רכיבי car-ui-lib
באמצעות RROs באפליקציה ל-Android
בדף הזה נסביר איך משתמשים בשכבת-על של משאבים בסביבת זמן ריצה (RRO) כדי לשנות רכיבים מספריית car-ui-lib
באפליקציית Android.
הגדרת צבע הרקע של סרגל הכלים
משך: 15 דקות
כדי לשנות את צבע הרקע של סרגל הכלים:
מוסיפים את הערך הבא לאפליקציית ה-RRO ומגדירים את המשאב לירוק בהיר (
#0F0
):<?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="car_ui_toolbar_background">#0F0</drawable> </resources>
הספרייה
car-ui-lib
מכילה משאב בשםcar_ui_toolbar_background
. כשהמשאב הזה נכלל בתצורה של RRO, סרגל הכלים לא משתנה כי היעד הוא הערך הלא נכון.בקובץ
AndroidManifest.xml
של ה-RRO, מעדכנים אתtargetName
כך שיצביע עלcar-ui-lib
:… android:targetName="car-ui-lib" …
חובה ליצור חבילת RRO חדשה לכל חבילת יעד שרוצים להעביר ל-RRO. לדוגמה, כשיוצרים שכבות-על לשני יעדים שונים, צריך ליצור שני קובצי APK של שכבות-על.
יוצרים, מאמתים, מתקינים ומפעילים את ה-RRO באותו אופן כמו קודם.
האפליקציה שלכם תיראה כך:

פריסות וסגנונות של RRO
משך: 15 דקות
בתרגול הזה תייצרו אפליקציה חדשה שדומה לאפליקציה שיצרתם מקודם. האפליקציה הזו מאפשרת להציג את הפריסה בשכבה עליונה. פועלים לפי אותם שלבים כמו קודם, או משנים את האפליקציה הקיימת.
חשוב להוסיף את השורות הבאות לקובץ
overlayable.xml
:<?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>
מוודאים ש-
activity_main.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" 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>
באפליקציית ה-RRO, יוצרים קובץ
res/layout/activity_main.xml
ומוסיפים את הפרטים הבאים:<?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>
מעדכנים את
res/values/styles.xml
כדי להוסיף את הסגנון שלנו ל-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>
משנים את
targetName
ב-AndroidManifest.xml
כך שיצביע על שם האפליקציה החדשה:… android:targetName="CarUiCodelab" …
מוסיפים את המשאבים לקובץ
sample_overlay.xml
ב-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>
יוצרים ומתקינים את האפליקציה ואת ה-RRO באותו אופן כמו קודם (הלחצן Play הירוק). חשוב להפעיל את ה-RRO.
האפליקציה וה-RRO מוצגים באופן הבא. הטקסט של Hello World RRO הוא ירוק וממורכז כפי שצוין ב-RRO של הפריסה.

הוספת CarUiRecyclerView לאפליקציה
משך: 15 דקות
הממשק CarUiRecyclerView
מספק ממשקי API לגישה ל-RecyclerView
שמותאם אישית באמצעות משאבי car-ui-lib
. לדוגמה, CarUiRecyclerView
בודק דגל בזמן הריצה כדי לקבוע אם צריך להפעיל את פס ההזזה או לא
ובוחר את הפריסה המתאימה.

כדי להוסיף
CarUiRecyclerView
, מוסיפים אותו לקובציactivity_main.xml
ו-MainActivity.java
. אפשר ליצור אפליקציה חדשה מאפס או לשנות את האפליקציה הקיימת. אם משנים את האפליקציה הקיימת, חשוב להסיר מ-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"/>
יכול להיות שתופיע השגיאה הבאה, שאפשר להתעלם ממנה:
Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerView
כל עוד איות הכיתה נכון והוספתם את
car-ui-lib
כיחסי תלות, תוכלו ליצור ולקמפל את קובץ ה-apk. כדי להסיר את השגיאה, בוחרים באפשרות File (קובץ) > Invalidate Caches (ביטול תוקף של מטמון) ואז לוחצים על Invalidate and Restart (ביטול תוקף והפעלה מחדש).מוסיפים את הטקסט הבא אל
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; }
יוצרים ומתקינים את האפליקציה כמו בעבר.
יופיע הסמל CarUiRecyclerView
:

שימוש ב-RRO כדי להסיר את פס ההזזה
משך: 10 דקות
במטלה הזו תלמדו איך להשתמש ב-RRO כדי להסיר את פס ההזזה מ-CarUiRecyclerView
.
מוסיפים את הקבצים הבאים ל-RRO ועורכים אותם:
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>
המשאב
car_ui_scrollbar_enable
הוא משאב בוליאני מסוגcar-ui-lib
, שמחליט אם סרגל הגלילה המותאם לרכב עם הלחצנים למעלה ולמטה ב-CarUiRecyclerView
נמצא או לא. כשהערך מוגדר ל-false
, הערךCarUiRecyclerView
פועל כמוRecyclerView
של AndroidX.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>
יוצרים ומתקינים את האפליקציה כמו בעבר. סרגל הגלילה הוסר מ-CarUiRecyclerView
:

שימוש בפריסה כדי להציג שכבת-על על פס ההזזה של CarUiRecyclerView
משך: 15 דקות
במטלה הזו תשנו את הפריסה של סרגל הגלילה CarUiRecyclerView
.
מוסיפים את הקבצים הבאים לאפליקציית ה-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>
כדי להוסיף שכבת-על לקובץ פריסה, צריך להוסיף את כל המזהים ומאפייני מרחב השמות ל-
overlay.xml
של ה-RRO. הקבצים מפורטים בהמשך.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>
מומלץ לבדוק את האינטראקציה בין הקבצים האלה.
כדי לפשט את התהליך, המאפיינים והצבעים מוגדרים בקוד. עם זאת, מומלץ להצהיר על הערכים האלה ב-
dimens.xml
וב-colors.xml
, או להגדיר אותם כקובצי צבע בתיקייהres/color/
. למידע נוסף, קראו את המאמר סגנון הקוד של Java ב-AOSP למשתתפים.יוצרים ומתקינים את האפליקציה כמו בעבר. יצרתם את
CarUiRecyclerView
עם פס גלילה כחול ופסים אפורים.
מזל טוב! שתי החצים מופיעים בחלק התחתון של פס ההזזה. סימן שהצלחתם להחיל RRO על קובץ משאב של פריסה מסוג car-ui-lib
באמצעות מערכת ה-build של Gradle דרך Android Studio.

פריטים ברשימה של RRO
משך: 15 דקות
עד עכשיו, החלתם RRO על רכיבי car-ui-lib
באמצעות רכיבי מסגרת (לא AndroidX). כדי להשתמש ברכיבי AndroidX ב-RRO, צריך להוסיף את יחסי התלות של הרכיב גם לאפליקציה וגם ל-RRO build.gradle.
. צריך גם להוסיף את attrs
של הרכיב ל-overlayable.xml
באפליקציה, וגם את sample_overlay.xml
ב-RRO.
הספרייה שלנו (car-ui-lib
) משתמשת ב-ConstraintLayout
וברכיבים אחרים של AndroidX, כך ש-overlayable.xml
שלה עשוי להיראות כך:
<?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>
משנים את הפריסה של הפריטים ברשימה ב-
CarUiRecyclerView
באמצעותConstraintLayout
. מוסיפים או משנים את הקבצים הבאים ב-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
מפנה לכמה רכיבים או משאבים שלא נכללים בתלות של האפליקציה. אלה משאביcar-ui-lib
. כדי לפתור את הבעיה, צריך להוסיף אתcar-ui-lib
כיחסי תלות לאפליקציית ה-RRO ב-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' }
עכשיו הכותרת והתוכן מיושרים לימין במקום לשמאל.

החלנו RRO על car-ui-lib
באמצעות רכיבי AndroidX (ConstraintLayout
) רק כשהמאפיינים שלו היו נוכחים בקובץ car-ui-lib
בשם overlayable.xml
וגם ב-RRO sample_overlay.xml
. אפשר לעשות משהו דומה באפליקציה שלכם. פשוט מוסיפים את כל הערכים התואמים של attrs
לקובץ overlayable.xml
של האפליקציה, בדומה ל-car-ui-lib
.
עם זאת, אי אפשר לבצע RRO לאפליקציה שמשתמשת ברכיבי AndroidX כשcar-ui-lib
מופיע בתור תלות ב-build.gradle
של האפליקציה (כשהאפליקציה משתמשת ברכיבי car-ui-lib
). מאחר שמיפויי המאפיינים כבר הוגדרו ב-overlayable.xml
של הספרייה car-ui-lib
, הוספה שלהם ל-overlayable.xml
של האפליקציה עם car-ui-lib
כיחס תלות תגרום לשגיאת mergeDebugResources
כמו זו שבהמשך. הסיבה לכך היא שהמאפיינים האלה נמצאים במספר קבצים מסוג overlayable.xml
:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'