استخدِم مكتبة 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.javapackage 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'