درس تطبيقي حول الترميز: إنشاء قوائم تسجيل الموارد (RRO) باستخدام مكونات Car-ui-lib باستخدام نظام إصدار Gradle

استخدِم مكتبة "car-ui-lib" لتوفير تجربة المعلومات والترفيه داخل المركبة. (IVI). يقدّم لك هذا الدرس التطبيقي حول الترميز التعرّف على car-ui-lib وكيفية استخدام استخدام تراكبات موارد وقت التشغيل (RROs) لتخصيص المكونات في المكتبة.

المعلومات التي ستطّلع عليها

كيفية:

  • ضمِّن car-ui-lib عنصرًا في تطبيق Android.
  • استخدِم Gradle لإنشاء تطبيقات Android وRRO.
  • استخدِم قوائم الموارد المجمَّعة مع "car-ui-lib".

لا يوضِّح هذا الدرس التطبيقي حول الترميز بالتفصيل طريقة عمل قوائم الموارد المنتظمة (RRO). عرض تغيير قيمة موارد التطبيق في وقت التشغيل تحديد مشاكل تراكبات موارد وقت التشغيل وحلّها لمعرفة المزيد.

قبل البدء

المتطلّبات الأساسية

قبل البدء، تأكَّد من توفُّر ما يلي:

  • كمبيوتر يحتوي على سطر أوامر (جهاز Linux أو Mac أو Windows يحتوي على Windows الفرعي لنظام التشغيل Linux).

  • استوديو Android

  • تم ربط جهاز Android أو المحاكي بجهازك. عرض نزِّل مصدر Android و إنشاء Android:

  • معرفة أساسية بـ RRO.

إنشاء تطبيق Android جديد

المدة: 15 دقيقة

في هذا القسم، يمكنك إنشاء مشروع جديد على "استوديو Android".

  1. في "استوديو Android"، أنشِئ تطبيقًا باستخدام EmptyActivity.

    إنشاء نشاط فارغ
    الشكل 1.إنشاء نشاط فارغ
  2. أدخِل اسمًا للتطبيق CarUiCodelab ثم اختَر لغة Java. يمكنك أيضًا تحديد موقع الملف إذا رغبت في ذلك. اقبل القيم الافتراضية الإعدادات المتبقية.

     تسمية التطبيق
    الشكل 2. أدخِل اسمًا للتطبيق
  3. استبدِل 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 التي لم يتم تعريفها.

  4. أضِف سلسلة موارد sample_text واضبطها على "Hello World!" في ملف strings.xml. لفتح هذا الملف، اختَر تطبيق > src > الصفحة الرئيسية > الدقة > القيم > schema.xml.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiCodelab</string>
        <string name="sample_text">Hello World!</string>
    </resources>
    
  5. لإنشاء تطبيقك، انقر على الزر تشغيل الأخضر أعلى اليسار. إجراء ذلك تثبّت ملف APK تلقائيًا على المحاكي أو على جهاز Android من خلال Gradle.

    زر التشغيل

من المفترض أن يتم فتح التطبيق الجديد تلقائيًا على المحاكي أو جهاز Android. في حال حذف لا، افتح تطبيق CarUiCodelab من مشغِّل التطبيقات المثبّت الآن. يظهر على النحو التالي:

فتح تطبيق CarUiCodelab الجديد
الشكل 3. فتح تطبيق CarUiCodelab الجديد

إضافة Car-ui-lib إلى تطبيق Android

المدة: 15 دقيقة

أضِف "car-ui-lib" إلى تطبيقك:

  1. لإضافة الاعتمادية car-ui-lib إلى ملف build.gradle الخاص بمشروعك، اتّبِع الخطوات التالية: اختَر التطبيق > 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، أضف شريط أدوات إلى تطبيقك.

  1. في ملف 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);
    }
    
  2. تأكد من استيراد ToolbarController:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. لاستخدام المظهر Theme.CarUi.WithToolbar، اختَر التطبيق > src > الرئيسية > 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>
    
  4. لإنشاء التطبيق، اضغط على الزر تشغيل كما في السابق.

    إنشاء التطبيق

إضافة حسابات RRO إلى تطبيقك

المدة: 30 دقيقة

إذا كنت على دراية بـ RROs، انتقِل إلى ، أضِف وحدة تحكُّم بالأذونات إلى تطبيقك. بخلاف ذلك، لمعرفة أساسيات RROs، راجع تغيير قيمة موارد التطبيق في وقت التشغيل

إضافة وحدة تحكّم بالأذونات إلى تطبيقك

للتحكم في الموارد التي تراكبها حزمة RRO، أضف ملفًا باسم overlayable.xml إلى مجلد التطبيق /res. يتم استخدام هذا الملف كإذن. وحدة التحكّم بين تطبيقك (target) وحزمة RRO (التراكب).

  1. أضِف "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".

  1. لإنشاء مشروع جديد، اختَر ملف > جديد > مشروع جديد: تأكد من حدِّد بلا نشاط بدلاً من إفراغ النشاط حيث تحتوي حِزم RRO على الموارد فقط.

    تظهر الإعدادات بشكل مشابه لتلك الموضّحة أدناه. تشير رسالة الأشكال البيانية وقد يختلف الموقع الجغرافي الذي يتم حفظها فيه:

  2. بعد إنشاء مشروع 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.

  3. انسخ مجموعة الرموز التالية إلى …/res/xml/sample_overlay.xml:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
    </overlay>
    
  4. إضافة 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 من RRO
    .
  5. لإنشاء هدف RRO، اضغط على الزر الأخضر تشغيل لإنشاء قاعدة Gradle من RRO على المحاكي أو على جهاز Android.

  6. للتحقّق من تثبيت RRO الخاص بك بشكل صحيح، قم بتشغيل:

    shell:~$ adb shell cmd overlay list --user current | grep -i com.example
    com.example.caruicodelab
    [ ] com.example.caruirro
    

    يعرض هذا الأمر معلومات مفيدة عن حالة حزم RRO على النظام.

    • يشير [ ] إلى أنّ RRO مثبّت وجاهزة للتفعيل.
    • --- يشير إلى أنه تم تثبيت RRO ولكنه يحتوي على أخطاء.
    • تعني القيمة [X] أنّه تم تثبيت RRO وتفعيله.

    إذا احتوت RRO على أخطاء، راجِع تحديد مشاكل تراكبات موارد وقت التشغيل وحلّها قبل المتابعة.

  7. لتمكين 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!
الشكل 4: مرحبًا بالعالم RRO

تهانينا! لقد أنشأت أول RRO لك.

عند استخدام RROs، ننصحك باستخدام أداة Android Asset Packaging Tool (AAPT2). تم وصف العلامتين --no-resource-deduping و--no-resource-removal في خيارات الربط ليس من الضروري إضافة العلامات في هذا الدرس التطبيقي حول الترميز، ولكننا نقترح عليك استخدامها. في قوائم الموارد المنتظمة (RRO) لتجنب إزالة الموارد (وتصحيح المشكلات). إِنْتَ يمكنك إضافتها إلى ملف build.gradle في RRO على النحو التالي:

android {
    …
    aaptOptions {
        additionalParameters "--no-resource-deduping", "--no-resource-removal"
    }
}

لمزيد من المعلومات عن هذه العلامات، راجع إنشاء الحزمة AAPT2

تعديل مكوّنَين (car-ui-lib) باستخدام قوائم RRO في تطبيق Android

توضّح هذه الصفحة كيفية استخدام ميزة "تراكب موارد وقت التشغيل" (RRO) بهدف تعديل المكونات من مكتبة car-ui-lib في تطبيق Android.

ضبط لون خلفية شريط الأدوات

المدة: 15 دقيقة

لتغيير لون خلفية شريط الأدوات:

  1. إضافة القيمة التالية إلى تطبيق RRO وضبط المورد على درجة سطوع أخضر (#0F0):

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <drawable name="car_ui_toolbar_background">#0F0</drawable>
    </resources>
    

    تحتوي مكتبة car-ui-lib على مورد باسم car_ui_toolbar_background عندما يتم تضمين هذا المورد في RRO، لا يتغير شريط الأدوات لأن القيمة الخاطئة استهداف العملاء.

  2. في AndroidManifest.xml لـ RRO، يجب تعديل targetName للإشارة إلى car-ui-lib:

    …
    android:targetName="car-ui-lib"
    …
    

    يجب عليك إنشاء حزمة RRO جديدة لكل حزمة مستهدفة تريد RRO. على سبيل المثال، عند إنشاء تراكبات لاستهدافين مختلفين، يجب إنشاء اثنين من حزم APK المتراكبة.

  3. يمكنك إنشاء RRO وإثبات صحتها وتثبيتها وتفعيلها بالطريقة نفسها المُتّبعة في السابق.

يظهر تطبيقك على النحو التالي:

لون خلفية شريط الأدوات الجديد
الشكل 5: لون خلفية شريط الأدوات الجديد

تخطيطات وأنماط RRO

المدة: 15 دقيقة

في هذا التمرين، تقوم بإنشاء تطبيق جديد مشابه للتطبيق الذي أنشأته سابقًا. هذا النمط تطبيق يتيح تركيب التخطيط. اتبع الخطوات نفسها كما كانت من قبل أو عدّل لتطبيقك الحالي.

  1. تأكد من إضافة الأسطر التالية إلى 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>
    
  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>
    
  3. في تطبيق 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>
    
  4. يجب تعديل "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>
    
  5. تغيير targetName في AndroidManifest.xml للإشارة إلى اسم تطبيقك الجديد:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. أضِف الموارد إلى ملف 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>
    
  7. إنشاء وتثبيت التطبيق وRRO بالطريقة نفسها (أخضر Play) ). تأكد من تمكين RRO.

يتم عرض التطبيق وRRO على النحو التالي. يظهر نص Hello World RRO باللون الأخضر كما هو محدد في تخطيط RRO.

مرحبًا بالعالم RRO
الشكل 6: Hello World RRO

إضافة CarUiRecyclerView إلى تطبيقك

المدة: 15 دقيقة

توفّر واجهة CarUiRecyclerView واجهات برمجة تطبيقات للوصول إلى RecyclerView التي يتم تخصيصها من خلال car-ui-lib مورد. على سبيل المثال: CarUiRecyclerView تتحقّق من علامة في وقت التشغيل لتحديد ما إذا كان يجب تفعيل شريط التمرير وتحدد التخطيط المتجاوب.

CarUiRecyclerViewContainer
الشكل 7. CarUiRecyclerViewContainer
  1. لإضافة "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;
    }
    
  2. أنشئ تطبيقك وثبِّته على النحو السابق.

يظهر لك الآن CarUiRecyclerView:

عرض CarUiRecyclerView
الشكل 7 : CarUiRecyclerView

استخدام RRO لإزالة شريط التمرير

المدة: 10 دقائق

يوضح لك هذا التمرين كيفية استخدام RRO لإزالة شريط التمرير من CarUiRecyclerView

  1. في 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" مثل RecyclerViewAndroidX.

    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 بدون شريط تمرير
الشكل 8. CarUiRecyclerView بدون شريط تمرير

استخدام تنسيق لتراكب شريط التمرير CarUiRecyclerView

المدة: 15 دقيقة

في هذا التمرين، يمكنك تعديل تنسيق شريط التمرير CarUiRecyclerView.

  1. أضف الملفات التالية وعدِّلها في تطبيق 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/. للمزيد من المعلومات الرؤية نمط رمز AOSP Java للمساهمين

  2. أنشئ تطبيقك وثبِّته على النحو السابق. لقد أنشأت CarUiRecyclerView باستخدام شريط تمرير أزرق وأشرطة رمادية

تهانينا! يظهر كلا السهمين أسفل شريط التمرير، تم تطبيق RRO بنجاح على ملف مورد تنسيق car-ui-lib باستخدام إصدار Gradle من خلال "استوديو Android".

CarUiRecyclerView بشريط تمرير أزرق يتضمّن أشرطة رمادية
الشكل 9. CarUiRecyclerView بشريط تمرير أزرق فيه أشرطة رمادية

عناصر قائمة RRO

المدة: 15 دقيقة

لقد طبّقت RRO حتى الآن على مكوّنات car-ui-lib باستخدام إطار العمل. (وليس AndroidX). لاستخدام مكونات AndroidX في RRO، يجب إضافة اعتماديات هذا المكون لكل من التطبيق وRRO build.gradle. أنت يجب أيضًا إضافة attrs لهذا المكوِّن إلى overlayable.xml في تطبيقك أيضًا. باعتباره sample_overlay.xml في RRO الخاص بك.

تستخدم مكتبتنا (car-ui-lib) ConstraintLayout بالإضافة إلى تطبيقات AndroidX الأخرى. لذلك، قد يبدو overlayable.xml على النحو التالي:

<?xml version='1.0' encoding='UTF-8'?>
<resources>
    <overlayable name="car-ui-lib">
        …
        <item type="attr" name="layout_constraintBottom_toBottomOf"/>
        <item type="attr" name="layout_constraintBottom_toTopOf"/>
        <item type="attr" name="layout_constraintCircle"/>
        <item type="attr" name="layout_constraintCircleAngle"/>
        <item type="attr" name="layout_constraintCircleRadius"/>
        <item type="attr" name="layout_constraintDimensionRatio"/>
        <item type="attr" name="layout_constraintEnd_toEndOf"/>
        <item type="attr" name="layout_constraintEnd_toStartOf"/>
        <item type="attr" name="layout_constraintGuide_begin"/>
        <item type="attr" name="layout_constraintGuide_end"/>
        <item type="attr" name="layout_constraintGuide_percent"/>
        <item type="attr" name="layout_constraintHeight_default"/>
        <item type="attr" name="layout_constraintHeight_max"/>
        <item type="attr" name="layout_constraintHeight_min"/>
        <item type="attr" name="layout_constraintHeight_percent"/>
        <item type="attr" name="layout_constraintHorizontal_bias"/>
        <item type="attr" name="layout_constraintHorizontal_chainStyle"/>
        <item type="attr" name="layout_constraintHorizontal_weight"/>
        <item type="attr" name="layout_constraintLeft_creator"/>
        <item type="attr" name="layout_constraintLeft_toLeftOf"/>
        <item type="attr" name="layout_constraintLeft_toRightOf"/>
        <item type="attr" name="layout_constraintRight_creator"/>
        <item type="attr" name="layout_constraintRight_toLeftOf"/>
        <item type="attr" name="layout_constraintRight_toRightOf"/>
        <item type="attr" name="layout_constraintStart_toEndOf"/>
        <item type="attr" name="layout_constraintStart_toStartOf"/>
        <item type="attr" name="layout_constraintTag"/>
        <item type="attr" name="layout_constraintTop_creator"/>
        <item type="attr" name="layout_constraintTop_toBottomOf"/>
        <item type="attr" name="layout_constraintTop_toTopOf"/>
        <item type="attr" name="layout_constraintVertical_bias"/>
        <item type="attr" name="layout_constraintVertical_chainStyle"/>
        …
    </overlayable>
</resources>
  1. تغيير تنسيق عناصر القائمة في 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>
    
  2. تشير السمة 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'
    }
    

تتم الآن محاذاة العنوان والنص الأساسي إلى اليمين بدلاً من المحاذاة إلى اليسار.

عنوان ونص محاذاة إلى اليمين
الشكل 10 عنوان ونص تمت محاذاته إلى اليمين

لم يتم تطبيق RRO على car-ui-lib إلا باستخدام مكونات AndroidX. (ConstraintLayout) عندما كانت سماته متوفّرة في car-ui-lib. باسم overlayable.xml بالإضافة إلى RRO sample_overlay.xml. من المهم ممكن أن تفعل شيئًا مشابهًا في تطبيقك. ما عليك سوى إضافة جميع attrs مقارنةً بـ overlayable.xml في تطبيقك، على غرار car-ui-lib

ومع ذلك، ليس من الممكن تشغيل تطبيق RRO باستخدام مكونات AndroidX عندما يتضمّن التطبيق car-ui-lib كتبعية في build.gradle (عندما يستخدم التطبيق car-ui-lib). ونظرًا لأن تعيينات السمات قد تم تحديدها بالفعل في overlayable.xml في مكتبة car-ui-lib، وستتم إضافته إلى سيؤدي استخدام overlayable.xml في التطبيق مع car-ui-lib كتبعية إلى خطأ واحد (mergeDebugResources) مثل ذلك أدناه. وذلك لأن هذه السمات متوفّرة في عدة ملفات overlayable.xml:

org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'