استخدِم مكتبة car-ui-lib لتشغيل أنظمة ترفيه ومعلومات (IVI) متّسقة ذاتيًا داخل السيارة. يعرّفك هذا الدرس التطبيقي حول الترميز على car-ui-lib وكيفية استخدام تراكبات الموارد في وقت التشغيل (RRO) لتخصيص المكوّنات في المكتبة.
أهداف الدورة التعليمية
كيفية:
- تضمين مكوّنات
car-ui-libفي تطبيق Android - استخدام Gradle لإنشاء تطبيقات Android وتراكبات الموارد في وقت التشغيل
- استخدام تراكبات الموارد في وقت التشغيل مع
car-ui-lib
لا يوضّح هذا الدرس التطبيقي حول الترميز كيفية عمل تراكبات الموارد في وقت التشغيل. لمزيد من المعلومات، يُرجى الاطّلاع على مقالتَي تغيير قيمة موارد تطبيق في وقت التشغيل و تحديد مشاكل تراكبات الموارد في وقت التشغيل وحلّها.
قبل البدء
المتطلبات الأساسية
قبل البدء، تأكَّد مما يلي:
كمبيوتر مزوّد بواجهة سطر الأوامر (جهاز Linux أو Mac أو Windows مع "نظام Windows الفرعي لنظام Linux")
جهاز Android أو محاكي متصل بجهاز الكمبيوتر يُرجى الاطّلاع على مقالة تنزيل مصدر Android و مقالة إنشاء Android.
معرفة أساسية بتراكبات الموارد في وقت التشغيل
إنشاء تطبيق 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 من خلال 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>لإنشاء التطبيق، انقر على الزر الأخضر تشغيل كما فعلت سابقًا.
إضافة تراكبات الموارد في وقت التشغيل إلى تطبيقك
المدة: 30 دقيقة
إذا كنت على دراية بتراكبات الموارد في وقت التشغيل، انتقِل إلى القسم التالي، إضافة وحدة تحكّم في الأذونات إلى تطبيقك. بخلاف ذلك، للاطّلاع على أساسيات تراكبات الموارد في وقت التشغيل، يُرجى الاطّلاع على مقالة تغيير قيمة موارد تطبيق في وقت التشغيل.
إضافة وحدة تحكّم في الأذونات إلى تطبيقك
للتحكّم في الموارد التي يغطيها حزمة تراكبات الموارد في وقت التشغيل، أضِف ملفًا باسم overlayable.xml إلى مجلد /res في تطبيقك. يعمل هذا الملف كوحدة تحكّم في الأذونات بين تطبيقك (الهدف) وحزمة تراكبات الموارد في وقت التشغيل (التراكب).
أضِف
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قابلة للتراكب من خلال تراكبات الموارد في وقت التشغيل، أدرِج اسم المورد في ملف overlayable.xml الخاص بالتطبيق.يجب أن يكون ملف
overlayable.xmlفيres/values/. إذا لم يكن كذلك، لا يمكن لـOverlayManagerServiceالعثور عليه.لمزيد من المعلومات حول الموارد القابلة للتراكب وكيفية ضبطها، يُرجى الاطّلاع على مقالة تقييد الموارد القابلة للتراكب.
إنشاء حزمة تراكبات الموارد في وقت التشغيل
في هذا القسم، ستنشئ حزمة تراكبات الموارد في وقت التشغيل لتغيير السلسلة المعروضة أعلاه من "Hello World!" إلى "Hello World RRO".
لإنشاء مشروع جديد، انقر على ملف > جديد > مشروع جديد. احرص على اختيار بدون نشاط بدلاً من "نشاط فارغ" لأنّ حزم تراكبات الموارد في وقت التشغيل لا تحتوي إلا على موارد.
ستظهر الإعدادات بشكل مشابه لتلك الموضّحة أدناه. قد يختلف الموقع الذي يتم حفظها فيه:
بعد إنشاء مشروع
CarUiRROالجديد، عليك الإعلان عن المشروع على أنّه تراكب موارد في وقت التشغيل من خلال تعديل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أسماء الموارد من الحزمة المستهدَفة بحزمة تراكبات الموارد في وقت التشغيل. يجب ضبط العلامةhasCodeعلىfalseلحزم تراكبات الموارد في وقت التشغيل. بالإضافة إلى ذلك، لا يُسمح لحزم تراكبات الموارد في وقت التشغيل باحتواء ملفات 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>
لإنشاء هدف تراكب الموارد في وقت التشغيل، انقر على الزر الأخضر تشغيل لإنشاء إصدار Gradle من تراكب الموارد في وقت التشغيل على المحاكي أو جهاز Android.
للتحقّق من تثبيت تراكب الموارد في وقت التشغيل بشكل صحيح، شغِّل ما يلي:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirroيعرض هذا الأمر معلومات مفيدة حول حالة حزم تراكبات الموارد في وقت التشغيل على النظام.
[ ]يشير إلى أنّ تراكب الموارد في وقت التشغيل مثبَّت وجاهز للتفعيل.---يشير إلى أنّ تراكب الموارد في وقت التشغيل مثبَّت ولكنّه يحتوي على أخطاء.[X]يعني أنّ تراكب الموارد في وقت التشغيل مثبَّت ومفعَّل.
إذا كان تراكب الموارد في وقت التشغيل يحتوي على أخطاء، يُرجى الاطّلاع على مقالة تحديد مشاكل تراكبات الموارد في وقت التشغيل وحلّها قبل المتابعة.
لتفعيل تراكب الموارد في وقت التشغيل والتحقّق من أنّه مفعَّل:
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”.
تهانينا! لقد أنشأت أول تراكب موارد في وقت التشغيل.
عند استخدام تراكبات الموارد في وقت التشغيل، قد تحتاج إلى استخدام علامتَي Android Asset Packaging Tool (AAPT2)
flags --no-resource-deduping و--no-resource-removal الموضّحتَين في
خيارات الربط.
ليس من الضروري إضافة العلامات في هذا الدرس التطبيقي حول الترميز، ولكن ننصحك باستخدامها في تراكبات الموارد في وقت التشغيل لتجنُّب إزالة الموارد (وتجنُّب مشاكل تصحيح الأخطاء). يمكنك إضافتها إلى ملف build.gradle الخاص بتراكب الموارد في وقت التشغيل على النحو التالي:
android {
…
aaptOptions {
additionalParameters "--no-resource-deduping", "--no-resource-removal"
}
}
لمزيد من المعلومات حول هاتَين العلامتَين، يُرجى الاطّلاع على مقالتَي إنشاء الحزمة و AAPT2.
تعديل مكوّنات car-ui-lib باستخدام تراكبات الموارد في وقت التشغيل في تطبيق Android
توضّح هذه الصفحة كيفية استخدام تراكب موارد في وقت التشغيل لتعديل المكوّنات من مكتبة car-ui-lib في تطبيق Android.
ضبط لون خلفية شريط الأدوات
المدة: 15 دقيقة
لتغيير لون خلفية شريط الأدوات:
أضِف القيمة التالية إلى تطبيق تراكب الموارد في وقت التشغيل، واضبط المورد على اللون الأخضر الفاتح (
#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لتراكب الموارد في وقت التشغيل، عدِّلtargetNameللإشارة إلىcar-ui-lib:… android:targetName="car-ui-lib" …**يجب** إنشاء حزمة تراكبات موارد في وقت التشغيل جديدة لكل حزمة مستهدَفة تريد استخدام تراكب الموارد في وقت التشغيل لها. على سبيل المثال، عند إنشاء تراكبات لهدفَين مختلفَين، يجب إنشاء ملفَي APK للتراكب.
أنشئ تراكب الموارد في وقت التشغيل وتحقَّق منه وثبِّته وفعِّله بالطريقة نفسها كما فعلت سابقًا.
يظهر تطبيقك على النحو التالي:
تنسيقات وأنماط تراكبات الموارد في وقت التشغيل
المدة: 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>في تطبيق تراكب الموارد في وقت التشغيل، أنشئ
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لإضافة النمط إلى تراكب الموارد في وقت التشغيل:<?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في تراكب الموارد في وقت التشغيل:<?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>أنشئ التطبيق وتراكب الموارد في وقت التشغيل وثبِّتهما بالطريقة نفسها كما فعلت سابقًا (الزر الأخضر تشغيل). احرص على تفعيل تراكب الموارد في وقت التشغيل.
يتم عرض التطبيق وتراكب الموارد في وقت التشغيل على النحو التالي. يكون النص "Hello World RRO" باللون الأخضر ويتم توسيطه كما هو محدّد في تراكب الموارد في وقت التشغيل الخاص بالتنسيق.
إضافة CarUiRecyclerView إلى تطبيقك
المدة: 15 دقيقة
توفر واجهة CarUiRecyclerView واجهات برمجة تطبيقات للوصول إلى 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.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 دقائق
يوضّح لك هذا التمرين كيفية استخدام تراكب موارد في وقت التشغيل لإزالة شريط التمرير من CarUiRecyclerView.
في تراكب الموارد في وقت التشغيل، أضِف الملفات التالية وعدِّلها:
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.
أضِف الملفات التالية وعدِّلها في تطبيق تراكب الموارد في وقت التشغيل.
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في تراكب الموارد في وقت التشغيل. يُرجى الاطّلاع على الملفات أدناه.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مع شريط تمرير أزرق وقضبان رمادية.
تهانينا! يظهر كلا السهمَين على طول أسفل شريط التمرير، وقد نجحت في تطبيق تراكب موارد في وقت التشغيل على ملف مورد تنسيق car-ui-lib باستخدام نظام إنشاء Gradle من خلال "استوديو Android".
عناصر قائمة تراكبات الموارد في وقت التشغيل
المدة: 15 دقيقة
حتى الآن، طبّقت تراكب موارد في وقت التشغيل على مكوّنات car-ui-lib باستخدام مكوّنات إطار العمل (وليس AndroidX). لاستخدام مكوّنات AndroidX في تراكب موارد في وقت التشغيل، يجب إضافة
تبعيات هذا المكوّن إلى كل من التطبيق وملف تراكب الموارد في وقت التشغيل build.gradle. يجب
أيضًا إضافة attrs لهذا المكوّن إلى overlayable.xml في تطبيقك، بالإضافة
إلى sample_overlay.xml في تراكب الموارد في وقت التشغيل.
تستخدم مكتبتنا (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. أضِف الملفات التالية أو عدِّلها في تراكب الموارد في وقت التشغيل: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كملحق لتطبيق تراكب الموارد في وقت التشغيل في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' }
يتم الآن محاذاة العنوان والنص إلى اليمين بدلاً من المحاذاة إلى اليسار.
لم نطبّق تراكب موارد في وقت التشغيل على car-ui-lib إلا باستخدام مكوّنات AndroidX (ConstraintLayout) عندما كانت سماته متوفرة في ملف car-ui-lib باسم overlayable.xml بالإضافة إلى 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'