Codelab: RROها را با اجزای car-ui-lib با استفاده از سیستم ساخت Gradle ایجاد کنید

از کتابخانه car-ui-lib برای راه‌اندازی سیستم‌های سرگرمی-اطلاعاتی درون‌خودرویی (IVI) خودسازگار استفاده کنید. این آزمایشگاه کد شما را با car-ui-lib و نحوه استفاده از پوشش‌های منابع زمان اجرا (RRO) برای سفارشی‌سازی اجزای موجود در کتابخانه آشنا می‌کند.

آنچه یاد خواهید گرفت

چگونه:

  • کامپوننت‌های car-ui-lib را در برنامه اندروید خود قرار دهید.
  • از Gradle برای ساخت برنامه‌های اندروید و RRO استفاده کنید.
  • از RROها به همراه car-ui-lib استفاده کنید.

این آزمایشگاه کد، جزئیات نحوه‌ی کار RROها را شرح نمی‌دهد. برای کسب اطلاعات بیشتر، به «تغییر مقدار منابع یک برنامه در زمان اجرا» و «عیب‌یابی همپوشانی‌های منابع زمان اجرا» مراجعه کنید.

قبل از شروع

پیش‌نیازها

قبل از شروع، مطمئن شوید که موارد زیر را دارید:

یک برنامه اندروید جدید ایجاد کنید

مدت زمان: ۱۵ دقیقه

در این بخش، شما یک پروژه جدید اندروید استودیو ایجاد می‌کنید.

  1. در اندروید استودیو یک برنامه با EmptyActivity ایجاد کنید.

    ایجاد یک اکتیویتی خالی
    شکل ۱. ایجاد یک اکتیویتی خالی
  2. نام برنامه را CarUiCodelab بگذارید و سپس زبان جاوا را انتخاب کنید. در صورت تمایل می‌توانید محل ذخیره فایل را نیز انتخاب کنید. مقادیر پیش‌فرض را برای سایر تنظیمات بپذیرید.

    برنامه خود را نامگذاری کنید
    شکل ۲. نام برنامه خود را بنویسید
  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 را اضافه کنید و آن را در فایل strings.xml خود روی "Hello World!" تنظیم کنید. برای باز کردن این فایل، 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>
    
  5. برای ساخت برنامه، روی دکمه سبز Play در بالا سمت راست کلیک کنید. با انجام این کار، فایل apk به طور خودکار از طریق Gradle روی شبیه‌ساز یا دستگاه اندروید شما نصب می‌شود.

    دکمه پخش

برنامه جدید باید به طور خودکار روی شبیه‌ساز یا دستگاه اندروید شما باز شود. در غیر این صورت، برنامه CarUiCodelab را از لانچر برنامه که اکنون نصب شده است، باز کنید. چیزی شبیه به این خواهد بود:

برنامه جدید CarUiCodelab را باز کنید
شکل ۳. باز کردن برنامه جدید CarUiCodelab

افزودن car-ui-lib به برنامه اندروید شما

مدت زمان: ۱۵ دقیقه

car-ui-lib را به برنامه خود اضافه کنید:

  1. برای افزودن وابستگی 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 در برنامه اندروید خود استفاده کنید

حالا که 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 ، 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>
    
  4. برای ساخت برنامه، مانند قبل دکمه سبز Play را فشار دهید.

    ساخت اپلیکیشن

RRO ها را به برنامه خود اضافه کنید

مدت زمان: ۳۰ دقیقه

اگر با RROها آشنا هستید، به بخش بعدی، یعنی «افزودن یک کنترل‌کننده مجوز به برنامه» مراجعه کنید. در غیر این صورت، برای یادگیری اصول اولیه RROها، به بخش «تغییر مقدار منابع یک برنامه در زمان اجرا» مراجعه کنید.

یک کنترل‌کننده مجوز به برنامه خود اضافه کنید

برای کنترل اینکه یک بسته RRO کدام منابع را همپوشانی می‌کند، فایلی با نام overlayable.xml را به پوشه /res برنامه خود اضافه کنید. این فایل به عنوان یک کنترل‌کننده مجوز بین برنامه شما ( target ) و بسته RRO شما ( overlay ) عمل می‌کند.

  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. برای ایجاد یک پروژه جدید، File > New > New Project را انتخاب کنید. حتماً به جای Empty Activity، گزینه No Activity را انتخاب کنید، زیرا بسته‌های RRO فقط شامل منابع هستند.

    پیکربندی‌های شما مشابه موارد نشان داده شده در زیر هستند. محل ذخیره آنها ممکن است متفاوت باشد:

  2. پس از ایجاد پروژه جدید CarUiRRO ، با تغییر AndroidManifest.xml ، پروژه را به عنوان یک RRO اعلام کنید.

    <?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 نگاشت می‌کند. تنظیم flag hasCode روی false برای بسته‌های RRO الزامی است. علاوه بر این، بسته‌های RRO مجاز به داشتن فایل‌های DEX نیستند.

  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 خود، دکمه سبز Play را فشار دهید تا یک نسخه Gradle از RRO خود را روی شبیه‌ساز یا دستگاه اندروید خود ایجاد کنید.

  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)
شکل ۴ : سلام دنیا! RRO

تبریک می‌گویم! شما اولین RRO خود را ایجاد کردید.

هنگام استفاده از RROها، ممکن است بخواهید از فلگ‌های --no-resource-deduping و --no-resource-removal ابزار بسته‌بندی دارایی‌های اندروید (AAPT2) که در گزینه‌های Link توضیح داده شده‌اند، استفاده کنید. اضافه کردن فلگ‌ها در این آزمایشگاه کد ضروری نیست، اما پیشنهاد می‌کنیم برای جلوگیری از حذف منابع (و دردسرهای اشکال‌زدایی) از آنها در RROهای خود استفاده کنید. می‌توانید آنها را به فایل build.gradle RRO خود به این صورت اضافه کنید:

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

برای کسب اطلاعات بیشتر در مورد این پرچم‌ها، به ساخت بسته و AAPT2 مراجعه کنید.

اصلاح کامپوننت‌های car-ui-lib با استفاده از RROها در برنامه اندروید شما

این صفحه نحوه استفاده از یک پوشش منابع زمان اجرا (RRO) را برای تغییر اجزای کتابخانه car-ui-lib در برنامه اندروید شما شرح می‌دهد.

تنظیم رنگ پس زمینه نوار ابزار

مدت زمان: ۱۵ دقیقه

برای تغییر رنگ پس زمینه نوار ابزار:

  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 را به همان روش قبلی بسازید، تأیید کنید، نصب کنید و فعال کنید.

برنامه شما به این شکل نمایش داده می‌شود:

رنگ پس زمینه نوار ابزار جدید
شکل ۵ : رنگ پس‌زمینه جدید نوار ابزار

طرح‌بندی‌ها و سبک‌های RRO

مدت زمان: ۱۵ دقیقه

در این تمرین، شما یک برنامه جدید مشابه برنامه‌ای که قبلاً ساخته‌اید، می‌سازید. این برنامه امکان همپوشانی طرح‌بندی را فراهم می‌کند. همان مراحل قبلی را دنبال کنید یا برنامه موجود خود را تغییر دهید.

  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 : سلام دنیا RRO

CarUiRecyclerView را به برنامه خود اضافه کنید

مدت زمان: ۱۵ دقیقه

رابط کاربری CarUiRecyclerView رابط‌های برنامه‌نویسی کاربردی (API) را برای دسترسی به یک RecyclerView که از طریق منابع car-ui-lib سفارشی‌سازی شده است، فراهم می‌کند. برای مثال، CarUiRecyclerView در زمان اجرا یک پرچم (flag) را بررسی می‌کند تا مشخص کند که آیا نوار اسکرول باید فعال باشد یا خیر و طرح‌بندی مربوطه را انتخاب می‌کند.

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 خود را بسازید و کامپایل کنید. برای رفع خطا، File > Invalidate Caches را انتخاب کنید و سپس روی Invalidate and Restart کلیک کنید.

    موارد زیر را به 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 : نمای بازیافت CarUi

از RRO برای حذف نوار پیمایش استفاده کنید

مدت زمان: ۱۰ دقیقه

این تمرین به شما نشان می‌دهد که چگونه از یک 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 مانند یک AndroidX RecyclerView عمل می‌کند.

    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 بدون اسکرول بار
شکل ۸. CarUiRecyclerView بدون نوار اسکرول

از یک طرح‌بندی برای پوشاندن نوار اسکرول CarUiRecyclerView استفاده کنید

مدت زمان: ۱۵ دقیقه

در این تمرین، طرح‌بندی نوار اسکرول 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 برای مشارکت‌کنندگان مراجعه کنید.

  2. برنامه خود را مانند قبل بسازید و نصب کنید. شما CarUiRecyclerView با یک اسکرول بار آبی و ریل‌های خاکستری ساخته‌اید.

تبریک! هر دو فلش در پایین نوار پیمایش ظاهر می‌شوند. شما با موفقیت یک RRO را با استفاده از سیستم ساخت Gradle از طریق اندروید استودیو به فایل منبع طرح‌بندی car-ui-lib اعمال کرده‌اید.

CarUiRecyclerView با یک اسکرول بار آبی با ریل‌های خاکستری
شکل ۹. CarUiRecyclerView با نوار پیمایش آبی با ریل‌های خاکستری

اقلام فهرست RRO

مدت زمان: ۱۵ دقیقه

تا این مرحله، شما یک RRO را با استفاده از کامپوننت‌های فریم‌ورک (نه AndroidX) به کامپوننت‌های car-ui-lib اعمال کرده‌اید. برای استفاده از کامپوننت‌های AndroidX در یک 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'
    }
    

عنوان و بدنه اکنون به جای تراز چپ، راست‌چین شده‌اند.

عنوان و متن راست‌چین
شکل ۱۰. عنوان و متن راست‌چین

ما فقط زمانی یک RRO را با استفاده از کامپوننت‌های AndroidX ( ConstraintLayout ) به car-ui-lib اعمال کردیم که ویژگی‌های آن در فایل car-ui-lib به نام overlayable.xml و همچنین RRO sample_overlay.xml وجود داشته باشند. انجام کاری مشابه در برنامه خودتان نیز امکان‌پذیر است. فقط تمام attrs مربوطه را به overlayable.xml برنامه خود اضافه کنید، مشابه car-ui-lib .

با این حال، وقتی برنامه car-ui-lib را به عنوان یک وابستگی در build.gradle خود دارد (وقتی برنامه از اجزای car-ui-lib استفاده می‌کند)، RRO کردن یک برنامه با استفاده از اجزای AndroidX امکان‌پذیر نیست . از آنجایی که نگاشت‌های ویژگی قبلاً در overlayable.xml کتابخانه car-ui-lib تعریف شده‌اند، اضافه کردن آنها به overlayable.xml برنامه شما با car-ui-lib به عنوان یک وابستگی، باعث خطای mergeDebugResources مانند زیر می‌شود. دلیل این امر این است که این ویژگی‌ها در چندین فایل overlayable.xml وجود دارند:

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