אפשר להשתמש בספרייה car-ui-lib כדי להפעיל מערכות מידע ובידור (IVI) ברכב, שהן עקביות בפני עצמן. ב-Codelab הזה נסביר על car-ui-lib ואיך אפשר להשתמש בשכבות-על של משאבי זמן ריצה (RRO) כדי להתאים אישית רכיבים בספרייה.
מה תלמדו
איך עושים את זה:
- כוללים רכיבי
car-ui-libבאפליקציית Android. - אפשר להשתמש ב-Gradle כדי ליצור אפליקציות ל-Android ו-RRO.
- שימוש ב-RRO עם
car-ui-lib.
בשיעור Codelab הזה לא נפרט איך פועלים RRO. מידע נוסף זמין במאמרים שינוי הערך של משאבי אפליקציה בזמן ריצה ופתרון בעיות בשכבות-על של משאבים בזמן ריצה.
לפני שמתחילים
דרישות מוקדמות
לפני שמתחילים, חשוב לוודא שיש לכם:
מחשב עם שורת פקודה (מחשב Linux, Mac או Windows עם Windows Subsystem for Linux).
מכשיר Android או אמולטור שמחוברים למחשב. אפשר לעיין במאמרים בנושא הורדת המקור של Android ויצירת Android.
ידע בסיסי ב-RRO.
יצירת אפליקציה חדשה ל-Android
משך: 15 דקות
בקטע הזה יוצרים פרויקט חדש ב-Android Studio.
ב-Android Studio, יוצרים אפליקציה עם
EmptyActivity.
איור 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>כדי ליצור את האפליקציה, לוחצים על הלחצן הירוק הפעלה בפינה השמאלית העליונה. פעולה כזו תגרום להתקנת קובץ ה-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>כדי ליצור את האפליקציה, לוחצים על לחצן ההפעלה הירוק כמו קודם.
הוספת RRO לאפליקציה
משך: 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החדש, צריך להצהיר על הפרויקט כ-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="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, לוחצים על לחצן ההפעלה הירוק כדי ליצור גרסת build של Gradle של ה-RRO באמולטור או במכשיר Android.
כדי לוודא שה-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, כדאי להשתמש בדגלים --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 רכיבים באמצעות RRO באפליקציית 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>כדי להוסיף את הסגנון שלנו ל-RRO, צריך לעדכן את
res/values/styles.xml:<?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. כדי להסיר את השגיאה, בוחרים באפשרות קובץ > ביטול תוקף של מטמונים ואז לוחצים על ביטול תוקף והפעלה מחדש.מוסיפים את הטקסט הבא לקובץ
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 באמצעות רכיבי framework (לא 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.xmlreferences several references several components/ resources that are not included as dependencies of the app. These arecar-ui-libresources. כדי לפתור את הבעיה, צריך להוסיף את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). מיפויי המאפיינים כבר הוגדרו בספרייה car-ui-lib של overlayable.xml, ולכן הוספה שלהם ל-overlayable.xml של האפליקציה עם car-ui-lib כתלות תגרום לשגיאה mergeDebugResources כמו זו שמופיעה בהמשך. הסיבה לכך היא שהמאפיינים האלה מופיעים בכמה קבצים של overlayable.xml:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'