استخدِم مكتبة car-ui-lib
لتشغيل أنظمة الترفيه والمعلومات
(IVI) داخل المركبات ذاتية الاكتفاء. يعرّفك هذا الدرس التطبيقي حول الترميز على car-ui-lib
وكيفية
استخدام تراكب الموارد أثناء التشغيل (RRO) لتخصيص المكوّنات في المكتبة.
المُعطيات
كيفية إجراء ذلك:
- أدرِج
car-ui-lib
مكوّنًا في تطبيق Android. - استخدام Gradle لإنشاء تطبيقات Android وتطبيقات RRO
- استخدِم طلبات إعادة النظر في الموافقة مع
car-ui-lib
.
لا يوضّح هذا الدليل التعليمي كيفية عمل طلبات الحصول على إذن الوصول إلى مساحة التخزين المؤقت. اطّلِع على مقالتَي تغيير قيمة موارد التطبيق أثناء التشغيل وتحديد المشاكل وحلّها في تراكب موارد وقت التشغيل لمزيد من المعلومات.
قبل البدء
المتطلّبات الأساسية
قبل البدء، تأكَّد من توفّر ما يلي:
جهاز كمبيوتر مزوّد بخط الأوامر (جهاز كمبيوتر يعمل بنظام التشغيل Linux أو Mac أو Windows مزوّد بنظام التشغيل Windows Subsystem for Linux)
جهاز Android أو محاكي Android متصل بجهازك اطّلِع على مقالتَي تنزيل رمز المصدر لنظام التشغيل Android وإنشاء نظام التشغيل Android.
معرفة أساسية بعمليات إعادة التوجيه (RRO)
إنشاء تطبيق Android جديد
المدة: 15 دقيقة
في هذا القسم، يمكنك إنشاء مشروع جديد في "استوديو Android".
في "استوديو Android"، أنشئ تطبيقًا يتضمّن
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 من خلال IDE.
من المفترض أن يتم فتح التطبيق الجديد تلقائيًا على المحاكي أو جهاز 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>
لإنشاء التطبيق، اضغط على الزر الأخضر تشغيل كما في السابق.
إضافة عمليات شراء داخل التطبيق إلى تطبيقك
المدة: 30 دقيقة
إذا كنت على دراية بـ RRO، انتقِل إلى القسم التالي، وهو إضافة وحدة تحكّم في الأذونات إلى تطبيقك. وإذا لم تكن على دراية بـ 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".
لإنشاء مشروع جديد، اختَر ملف > جديد > مشروع جديد. احرص على اختيار ما مِن نشاط بدلاً من "نشاط فارغ" لأنّ حِزم 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 المستهدف، اضغط على الزر الأخضر تشغيل لإنشاء إصدار Gradle من ملف RRO على المحاكي أو جهاز Android.
للتأكّد من تثبيت RRO بشكل صحيح، يمكنك تنفيذ ما يلي:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirro
يعرض هذا الأمر معلومات مفيدة عن حالة حِزم RRO على النظام.
- يشير الرمز
[ ]
إلى أنّ التطبيق المُعدّ للطرح على الرفّ قد تم تثبيته وأصبح جاهزًا للتنشيط. - يشير الرمز
---
إلى أنّ التطبيق المزوّد برمز التشغيل القابل للإزالة مثبَّت ولكنّه يحتوي على أخطاء. - يشير الرمز
[X]
إلى أنّ التطبيق المزوّد بإذن الوصول إلى مساحة التخزين المؤقت (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، قد تحتاج إلى استخدام علامتَي Android Asset Packaging Tool (AAPT2)
--no-resource-deduping
و--no-resource-removal
الموضّحتَين في
خيارات الربط.
ليس من الضروري إضافة العلامات في هذا الدليل التعليمي حول الرموز البرمجية، ولكننا نقترح عليك استخدامها
في تطبيقاتك التي تستخدم ميزات الوصول المحدود إلى الموارد لتجنُّب إزالة الموارد (وتجنُّب المشاكل المتعلّقة بتصحيح الأخطاء). يمكنك
إضافتها إلى ملف build.gradle
الخاص بتطبيقك المتوافق مع مبادرة "متجر التطبيقات في نظام التشغيل Android" على النحو التالي:
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
. عندما يكون هذا المورد مضمّنًا في إعدادات عنصر عرض إعلانات ديناميكية على شبكة البحث، لا يتغيّر شريط الأدوات لأنّه يتم استهداف القيمة الخاطئة.في
AndroidManifest.xml
لتطبيقك المتوافق مع سياسة RRO، عدِّلtargetName
ليشير إلىcar-ui-lib
:… android:targetName="car-ui-lib" …
يجب إنشاء حزمة جديدة لإعادة الإصدار والنشر لكل حزمة مستهدَفة تريد إعادة إصدارها ونشرها. على سبيل المثال، عند إنشاء تراكب لهدفَين مختلفَين، عليك إنشاء حِزم apk تراكبَين.
أنشئ رمز 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 وثبِّتهما بالطريقة نفسها التي استخدمتها سابقًا (الزر الأخضر تشغيل ). تأكَّد من تفعيل ميزة "الوصول المحدود للتطبيقات".
يتم عرض التطبيق ورمز RRO على النحو التالي. نص RRO الخاص بتطبيق Hello World أخضر ومائل ومتوسط كما هو محدّد في ملف RRO الخاص بالتنسيق.

إضافة CarUiRecyclerView إلى تطبيقك
المدة: 15 دقيقة
توفّر واجهة CarUiRecyclerView
واجهات برمجة تطبيقات للوصول إلى RecyclerView
التي تم تخصيصها من خلال موارد car-ui-lib
. على سبيل المثال، يتحقق CarUiRecyclerView
من علامة أثناء التشغيل لتحديد ما إذا كان يجب تفعيل شريط التمرير أم لا، ويختار 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
:

استخدام طلب إعادة النظر في المراجعة لإزالة شريط التمرير
المدة: 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
باستخدام نظام Gradle لإنشاء
التطبيقات من خلال "استوديو Android".

عناصر قائمة "التداخل في الوقت الفعلي"
المدة: 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
.
ومع ذلك، لا يمكن إعادة ترخيص تطبيق يستخدم مكونات 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'