Codelab: Gradle derleme sistemini kullanarak car-ui-lib bileşenleriyle RRO'lar oluşturma

Tutarlı, araç içi bilgi-eğlence (IVI) sistemleri başlatmak için car-ui-lib kitaplığını kullanın. Bu codelab'de car-ui-lib ve kitaplıktaki bileşenleri özelleştirmek için çalışma zamanı kaynak katmanlarını (RRO'lar) nasıl kullanabileceğiniz açıklanmaktadır.

Neler öğreneceksiniz?

Nasıl yapılır?

  • Android uygulamanıza car-ui-lib bileşenlerini ekleyin.
  • Android uygulamaları ve RRO'lar oluşturmak için Gradle'ı kullanın.
  • car-ui-lib ile RRO'ları kullanma

Bu codelab'de RRO'ların nasıl çalıştığı ayrıntılı olarak açıklanmamaktadır. Daha fazla bilgi için Çalışma zamanında bir uygulamanın kaynaklarının değerini değiştirme ve Çalışma zamanı kaynak yer paylaşımlarıyla ilgili sorunları giderme başlıklı makaleleri inceleyin.

Başlamadan önce

Ön koşullar

Başlamadan önce aşağıdakilere sahip olduğunuzdan emin olun:

  • Komut satırı olan bir bilgisayar (Linux makine, Mac veya Windows Subsystem for Linux'un yüklü olduğu Windows makine).

  • Android Studio.

  • Makinenize bağlı Android cihaz veya emülatör. Android kaynağını indirme ve Android'i derleme başlıklı makaleleri inceleyin.

  • RRO'lar hakkında temel bilgi

Yeni bir Android uygulaması oluşturma

Süre: 15 dakika

Bu bölümde yeni bir Android Studio projesi oluşturacaksınız.

  1. Android Studio'da EmptyActivity içeren bir uygulama oluşturun.

    Boş etkinlik oluşturma
    Şekil 1.Boş Etkinlik Oluşturma
  2. Uygulamaya ad verin CarUiCodelab ve Java dilini seçin. İsterseniz dosya konumu da seçebilirsiniz. Kalan ayarlar için varsayılan değerleri kabul edin.

     Uygulamanızı adlandırma
    Şekil 2. Uygulamanıza ad verme
  3. activity_main.xml yerine aşağıdaki kod bloğunu ekleyin:

    <?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>
    

    Bu kod bloğunda, tanımlanmamış olan sample_text dizesi gösteriliyor.

  4. sample_text kaynak dizesini ekleyin ve strings.xml dosyanızda "Hello World!" olarak ayarlayın. Bu dosyayı açmak için app > src > main > res > values > strings.xml'i seçin.

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiCodelab</string>
        <string name="sample_text">Hello World!</string>
    </resources>
    
  5. Uygulamanızı oluşturmak için sağ üstteki yeşil Play (Oynat) düğmesini tıklayın. Bu işlem, Gradle aracılığıyla APK'yı emülatörünüze veya Android cihazınıza otomatik olarak yükler.

    Oynat düğmesi

Yeni uygulama, emülatörünüzde veya Android cihazınızda otomatik olarak açılır. Aksi takdirde, uygulama başlatıcıdan CarUiCodelab uygulamasını açın. Şöyle görünür:

Yeni CarUiCodelab uygulamasını açın.
Şekil 3. Yeni CarUiCodelab uygulamasını açın

Android uygulamanıza car-ui-lib ekleme

Süre: 15 dakika

Uygulamanıza car-ui-lib ekleme:

  1. car-ui-lib bağımlılığını projenizin build.gradle dosyasına eklemek için app > build.gradle'ı seçin. Bağımlılıklarınız aşağıdaki gibi görünmelidir:

    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'
    }
    

Android uygulamanızda car-ui-lib bileşenlerini kullanma

Artık car-ui-lib'niz olduğuna göre uygulamanıza bir araç çubuğu ekleyin.

  1. MainActivity.java dosyanızda onCreate yönteminin üzerine yazın:

    @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 dosyasını içe aktardığınızdan emin olun:

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Theme.CarUi.WithToolbar temasını kullanmak için app > src > main > AndroidManifest.xml'i seçin ve ardından AndroidManifest.xml öğesini aşağıdaki gibi görünecek şekilde güncelleyin:

    <?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. Uygulamayı oluşturmak için daha önce olduğu gibi yeşil Oynat düğmesine basın.

    Uygulamayı oluşturma

Uygulamanıza RRO'lar ekleme

Süre: 30 dakika

RRO'lar hakkında bilginiz varsa sonraki bölüme, Uygulamanıza izin denetleyicisi ekleme bölümüne gidin. Aksi takdirde, RRO'ların temellerini öğrenmek için Uygulama kaynaklarının değerini çalışma zamanında değiştirme başlıklı makaleyi inceleyin.

Uygulamanıza izin denetleyicisi ekleme

Bir RRO paketinin hangi kaynakları kaplayacağını kontrol etmek için uygulamanızın /res klasörüne overlayable.xml adlı bir dosya ekleyin. Bu dosya, uygulamanız (hedef) ve RRO paketiniz (kaplama) arasında izin denetleyicisi olarak işlev görür.

  1. Uygulamanıza res/values/overlayable.xml ekleyin ve aşağıdaki içeriği dosyanıza kopyalayın:

    <?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 dizesi bir RRO tarafından yerleştirilebildiğinden kaynak adını uygulamanın overlayable.xml dosyasına ekleyin.

    overlayable.xml dosyanız KESİNLİKLE res/values/ içinde bulunmalıdır. Aksi takdirde OverlayManagerService bu öğeyi bulamaz.

    Yerleştirilebilir kaynaklar ve bunların nasıl yapılandırılacağı hakkında daha fazla bilgi edinmek için Yerleştirilebilir kaynakları kısıtlama başlıklı makaleyi inceleyin.

RRO paketi oluşturma

Bu bölümde, yukarıda gösterilen dizeyi "Hello World!" yerine "Hello World RRO" olarak değiştirmek için bir RRO paketi oluşturacaksınız.

  1. Yeni bir proje oluşturmak için Dosya > Yeni > Yeni Proje'yi seçin. RRO paketleri yalnızca kaynak içerdiğinden, Boş Etkinlik yerine Etkinlik Yok'u seçtiğinizden emin olun.

    Yapılandırmalarınız, aşağıda gösterilenlere benzer şekilde görünür. Kaydedildikleri konum farklı olabilir:

  2. Yeni CarUiRRO projesini oluşturduktan sonra AndroidManifest.xml öğesini değiştirerek projeyi RRO olarak bildirin.

    <?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>
    

    Bu işlem, @xml/sample_overlay ile ilgili bir hataya neden olur. resourcesMap dosyası, hedef paketteki kaynak adlarını RRO paketine eşler. hasCode işaretinin false olarak ayarlanması, RRO paketleri için zorunludur. Ayrıca, RRO paketlerinin DEX dosyaları içermesine izin verilmez.

  3. Aşağıdaki kod bloğunu …/res/xml/sample_overlay.xml içine kopyalayın:

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
    </overlay>
    
  4. sample_text öğesini …/res/values/strings.xml öğesine ekleme:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <string name="app_name">CarUiRRO</string>
        <string name="sample_text">Hello World RRO</string>
    </resources>
    
    RRO'nun Gradle derlemesi oluşturuldu
  5. RRO hedefinizi oluşturmak için yeşil Play düğmesine basarak emülatörünüzde veya Android cihazınızda RRO'nuzun Gradle derlemesini oluşturun.

  6. RRO'nuzun düzgün şekilde yüklendiğini doğrulamak için şu komutu çalıştırın:

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

    Bu komut, sistemdeki RRO paketlerinin durumu hakkında faydalı bilgiler gösterir.

    • [ ], RRO'nun yüklendiğini ve etkinleştirilmeye hazır olduğunu gösterir.
    • ---, RRO'nun yüklendiğini ancak hatalar içerdiğini gösterir.
    • [X], RRO'nun yüklendiği ve etkinleştirildiği anlamına gelir.

    Çalışma zamanı kaynak yer paylaşımınızda hatalar varsa devam etmeden önce Çalışma zamanı kaynak yer paylaşımlarıyla ilgili sorunları giderme başlıklı makaleyi inceleyin.

  7. RRO'yu etkinleştirmek ve etkinleştirildiğini doğrulamak için:

    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
    

Uygulamanız "Hello World RRO" dizesini gösteriyor.

Hello World RRO!
Şekil 4: Hello World RRO!

Tebrikler! İlk RRO'nuzu oluşturdunuz.

RRO'ları kullanırken Bağlantı seçenekleri bölümünde açıklanan Android Asset Packaging Tool (AAPT2) --no-resource-deduping ve --no-resource-removal işaretlerini kullanmak isteyebilirsiniz. Bu codelab'de işaretleri eklemeniz gerekmez ancak kaynakların kaldırılmasını (ve hata ayıklama sorunlarını) önlemek için RRO'larınızda kullanmanızı öneririz. Bunları RRO'nuzun build.gradle dosyasına şu şekilde ekleyebilirsiniz:

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

Bu işaretler hakkında daha fazla bilgi edinmek için Paketi oluşturma ve AAPT2 başlıklı makalelere bakın.

Android uygulamanızda RRO'ları kullanarak car-ui-lib bileşenlerini değiştirme

Bu sayfada, Android uygulamanızdaki car-ui-lib kitaplığındaki bileşenleri değiştirmek için nasıl çalışma zamanı kaynak yerleşimi (RRO) kullanabileceğiniz açıklanmaktadır.

Araç çubuğunun arka plan rengini ayarlama

Süre: 15 dakika

Araç çubuğunun arka plan rengini değiştirmek için:

  1. RRO uygulamanıza aşağıdaki değeri ekleyin ve kaynağı parlak yeşil (#0F0) olarak ayarlayın:

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

    car-ui-lib kitaplığında car_ui_toolbar_background adlı bir kaynak var. Bu kaynak bir RRO'nun yapılandırmasında yer aldığında, yanlış değer hedeflendiği için araç çubuğu değişmez.

  2. RRO'nuz için AndroidManifest.xml içinde targetName öğesini car-ui-lib'ı gösterecek şekilde güncelleyin:

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

    RRO uygulamak istediğiniz her hedef paket için YENİ bir RRO paketi oluşturmanız GEREKİR. Örneğin, iki farklı hedef için yer paylaşımları oluştururken iki yer paylaşımı APK'sı oluşturmanız gerekir.

  3. RRO'yu daha önce olduğu gibi oluşturun, doğrulayın, yükleyin ve etkinleştirin.

Uygulamanız şu şekilde görünür:

Yeni araç çubuğu arka plan rengi
Şekil 5: Yeni araç çubuğu arka plan rengi

RRO düzenleri ve stilleri

Süre: 15 dakika

Bu alıştırmada, daha önce oluşturduğunuz uygulamaya benzer yeni bir uygulama oluşturacaksınız. Bu uygulama, düzenin yerleştirilmesine olanak tanır. Önceki adımları uygulayın veya mevcut uygulamanızı değiştirin.

  1. overlayable.xml dosyasına aşağıdaki satırları eklediğinizden emin olun:

    <?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 simgesinin aşağıdaki gibi göründüğünden emin olun:

    <?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 uygulamanızda bir res/layout/activity_main.xml oluşturun ve aşağıdakileri ekleyin:

    <?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. Stilimizi RRO'ya eklemek için res/values/styles.xml öğesini güncelleyin:

    <?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. AndroidManifest.xml içindeki targetName öğesini yeni uygulamanızın adına yönlendirecek şekilde değiştirin:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Kaynakları RRO'nuzdaki sample_overlay.xml dosyasına ekleyin:

    <?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. Uygulamayı ve RRO'yu daha önce yaptığınız gibi oluşturup yükleyin (yeşil Play düğmesi). RRO'nuzu etkinleştirdiğinizden emin olun.

Uygulama ve RRO aşağıdaki gibi oluşturulur. Hello World RRO metni yeşildir ve düzen RRO'sunda belirtildiği gibi ortalanmıştır.

Hello World RRO
Şekil 6: Hello World RRO

Uygulamanıza CarUiRecyclerView ekleme

Süre: 15 dakika

CarUiRecyclerView arayüzü, car-ui-lib kaynakları aracılığıyla özelleştirilmiş bir RecyclerView'ye erişmek için API'ler sağlar. Örneğin, CarUiRecyclerView kaydırma çubuğunun etkinleştirilip etkinleştirilmeyeceğini belirlemek için çalışma zamanında bir işareti kontrol eder ve ilgili düzeni seçer.

CarUiRecyclerViewContainer
Şekil 7. CarUiRecyclerViewContainer
  1. CarUiRecyclerView eklemek için onu activity_main.xml ve MainActivity.java dosyalarınıza ekleyin. Sıfırdan yeni bir uygulama oluşturabilir veya mevcut uygulamayı değiştirebilirsiniz. Mevcut uygulamayı değiştirirseniz overlayable.xml içindeki beyan edilmemiş kaynakları kaldırdığınızdan emin olun.

    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"/>
    

    Aşağıdaki hata mesajı gösterilebilir. Bu mesajı görmezden gelebilirsiniz:

    Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerView

    Sınıfınız doğru yazıldığı ve car-ui-lib bağımlılık olarak eklendiği sürece APK'nızı oluşturup derleyebilirsiniz. Hatayı kaldırmak için Dosya > Önbellekleri Geçersiz Kıl'ı seçin, ardından Geçersiz Kıl ve Yeniden Başlat'ı tıklayın.

    Aşağıdakiler MainActivity.java alanına eklensin mi?

    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. Uygulamanızı eskisi gibi oluşturup yükleyin.

Artık CarUiRecyclerView simgesini görürsünüz:

CarUiRecyclerView
Şekil 7 : CarUiRecyclerView

Kaydırma çubuğunu kaldırmak için RRO kullanma

Süre: 10 dakika

Bu alıştırmada, CarUiRecyclerView öğesinden kaydırma çubuğunu kaldırmak için RRO'nun nasıl kullanılacağı gösterilmektedir.

  1. RRO'nuzda aşağıdaki dosyaları ekleyin ve değiştirin:

    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 kaynağı, car-ui-lib boole kaynağıdır. Bu kaynak, CarUiRecyclerView içinde yukarı ve aşağı düğmelerine sahip, otomobil için optimize edilmiş kaydırma çubuğunun bulunup bulunmadığını kontrol eder. false olarak ayarlandığında, CarUiRecyclerView, AndroidX RecyclerView gibi davranır.

    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>
    

Uygulamanızı eskisi gibi oluşturup yükleyin. Kaydırma çubuğu artık CarUiRecyclerView uygulamasından kaldırıldı:

Kaydırma çubuğu olmayan CarUiRecyclerView
Şekil 8. Kaydırma çubuğu olmayan CarUiRecyclerView

CarUiRecyclerView kaydırma çubuğunu yerleştirmek için bir düzen kullanın.

Süre: 15 dakika

Bu alıştırmada, CarUiRecyclerView kaydırma çubuğu düzenini değiştireceksiniz.

  1. RRO uygulamanıza aşağıdaki dosyaları ekleyin ve bu dosyalarda değişiklik yapın.

    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>
    

    Bir düzen dosyasını yerleştirmek için RRO'nuzun overlay.xml bölümüne tüm kimlikleri ve ad alanı özelliklerini eklemeniz gerekir. Aşağıdaki dosyalara bakın.

    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>
    

    Bu dosyaların nasıl etkileşim kurduğunu incelemeniz önerilir.

    Kolaylık sağlamak için boyutlar ve renkler sabit kodlanmıştır. Ancak bu değerleri dimens.xml ve colors.xml içinde bildirmek veya res/color/ klasöründe renk dosyaları olarak belirtmek en iyi uygulamadır. Daha fazla bilgi edinmek için AOSP Java code style for contributors (Katkıda bulunanlar için AOSP Java kod stili) başlıklı makaleyi inceleyin.

  2. Uygulamanızı eskisi gibi oluşturup yükleyin. Mavi kaydırma çubuğu ve gri raylarla CarUiRecyclerView oluşturmuş olabilirsiniz.

Tebrikler! Her iki ok da kaydırma çubuğunun en altında görünür. Android Studio üzerinden Gradle derleme sistemini kullanarak car-ui-lib düzen kaynak dosyasına başarıyla RRO uyguladınız.

Gri raylı mavi kaydırma çubuğu içeren CarUiRecyclerView
Şekil 9. Gri raylı mavi kaydırma çubuğu olan CarUiRecyclerView

RRO Liste öğeleri

Süre: 15 dakika

Bu noktaya kadar, framework bileşenlerini (AndroidX değil) kullanarak car-ui-lib bileşenlerine bir RRO uyguladınız. Bir RRO'da AndroidX bileşenlerini kullanmak için bu bileşenin bağımlılıklarını hem uygulamaya hem de RRO'ya eklemeniz gerekir. build.gradle. Ayrıca, bu bileşenin attrs öğesini uygulamanızdaki overlayable.xml öğesine ve RRO'nuzdaki sample_overlay.xml öğesine de eklemeniz gerekir.

Kitaplığımız (car-ui-lib), ConstraintLayout'nin yanı sıra diğer AndroidX bileşenlerini de kullandığı için overlayable.xml şu şekilde görünebilir:

<?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 içindeki liste öğelerinin düzenini ConstraintLayout kullanarak değiştirin. RRO'nuzda aşağıdaki dosyaları ekleyin veya değiştirin:

    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, uygulamanın bağımlılıkları olarak dahil edilmeyen çeşitli bileşenlere/kaynaklara referans veriyor. Bunlar car-ui-lib kaynaklarıdır. Bu sorunu düzeltmek için car-ui-lib öğesini app/build.gradle bölümünde RRO uygulamanıza bağımlılık olarak ekleyebilirsiniz:

    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'
    }
    

Başlık ve gövde artık sola değil sağa hizalanıyor.

Sağa hizalanmış başlık ve gövde
Şekil 10. Sağa hizalanmış başlık ve gövde

Yalnızca car-ui-lib adlı dosyada ve RRO sample_overlay.xml'da özellikleri bulunduğunda car-ui-lib için AndroidX bileşenleri kullanılarak RRO uyguladık (ConstraintLayout).overlayable.xml Benzer bir işlemi kendi uygulamanızda da yapabilirsiniz. attrs'ya benzer şekilde, uygulamanızın overlayable.xml bölümüne ilgili tüm attrs öğelerini eklemeniz yeterlidir.car-ui-lib

Ancak, uygulama build.gradle içinde bağımlılık olarak car-ui-lib içerdiğinde (uygulama car-ui-lib bileşenlerini kullandığında) AndroidX bileşenlerini kullanan bir uygulamaya RRO uygulamak mümkün değildir. Özellik eşlemeleri car-ui-lib kitaplığının overlayable.xml içinde zaten tanımlandığından, bunları car-ui-lib bağımlılığıyla uygulamanızın overlayable.xml dosyasına eklemek aşağıdaki gibi bir mergeDebugResources hatasına neden olur. Bunun nedeni, bu özelliklerin birden fazla overlayable.xml dosyasında bulunmasıdır:

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