Codelab: crie RROs com componentes car-ui-lib usando o sistema de compilação Gradle

Use a biblioteca car-ui-lib para iniciar sistemas de infoentretenimento (IVI) autoconsistentes no veículo. Este codelab apresenta car-ui-lib e como usar sobreposições de recursos de tempo de execução (RROs) para personalizar componentes na biblioteca.

O que você aprenderá

Como:

  • Inclua componentes car-ui-lib em seu aplicativo Android.
  • Use Gradle para criar aplicativos Android e RROs.
  • Use RROs com car-ui-lib .

Este codelab não detalha como funcionam os RROs. Consulte Alterar o valor dos recursos de um aplicativo em tempo de execução e Solucionar problemas de sobreposições de recursos de tempo de execução para saber mais.

Antes que você comece

Pré-requisitos

Antes de começar, certifique-se de ter:

Crie um novo aplicativo Android

Duração: 15 minutos

Nesta seção, você cria um novo projeto do Android Studio.

  1. No Android Studio, crie um aplicativo com um EmptyActivity .

    Crie uma atividade vazia
    Figura 1. Crie uma atividade vazia
  2. Nomeie o aplicativo CarUiCodelab e selecione a linguagem Java. Você também pode selecionar um local de arquivo, se desejar. Aceite os valores padrão para as configurações restantes.

    Nomeie seu aplicativo
    Figura 2. Nomeie seu aplicativo
  3. Substitua activity_main.xml pelo seguinte bloco de código:

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

    Este bloco de código exibe a string sample_text , que não está definida.

  4. Adicione a string de recurso sample_text e defina-a como "Hello World!" no seu arquivo strings.xml . Para abrir este arquivo, selecione 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. Para construir seu aplicativo, clique no botão verde Play no canto superior direito. Fazer isso instala automaticamente o apk em seu emulador ou dispositivo Android por meio do Gradle.

    Botão reproduzir

O novo aplicativo deve abrir automaticamente no seu emulador ou dispositivo Android. Caso contrário, abra o aplicativo CarUiCodelab no inicializador de aplicativos, que agora está instalado. Parece assim:

Abra o novo aplicativo CarUiCodelab
Figura 3. Abra o novo aplicativo CarUiCodelab

Adicione car-ui-lib ao seu aplicativo Android

Duração: 15 minutos

Adicione car-ui-lib ao seu aplicativo:

  1. Para adicionar a dependência car-ui-lib ao arquivo build.gradle do seu projeto, selecione app > build.gradle . Suas dependências devem aparecer assim:

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

Use componentes car-ui-lib em seu aplicativo Android

Agora que você tem car-ui-lib , adicione uma barra de ferramentas ao seu aplicativo.

  1. Em seu arquivo MainActivity.java , substitua o método 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. Certifique-se de importar ToolbarController :

    import com.android.car.ui.core.CarUi;
    import com.android.car.ui.toolbar.ToolbarController;
    
  3. Para usar o tema Theme.CarUi.WithToolbar , selecione app > src > main > AndroidManifest.xml e atualize AndroidManifest.xml para aparecer da seguinte forma:

    <?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. Para construir o aplicativo, pressione o botão verde Play como antes.

    Crie o aplicativo

Adicione RROs ao seu aplicativo

Duração: 30 minutos

Se você estiver familiarizado com RROs, vá para a próxima seção, Adicione um controlador de permissão ao seu aplicativo . Caso contrário, para aprender os conceitos básicos de RROs, consulte Alterar o valor dos recursos de um aplicativo em tempo de execução .

Adicione um controlador de permissão ao seu aplicativo

Para controlar quais recursos um pacote RRO sobrepõe, adicione um arquivo chamado overlayable.xml à pasta /res do seu aplicativo. Este arquivo serve como um controlador de permissão entre seu aplicativo (o target ) e seu pacote RRO (o overlay ).

  1. Adicione res/values/overlayable.xml ao seu aplicativo e copie o seguinte conteúdo no seu arquivo:

    <?xml version="1.0" encoding="utf-8"?>
    <resources>
        <overlayable name="CarUiCodelab">
            <policy type="public">
                <item type="string" name="sample_text"/>
            </policy>
        </overlayable>
    </resources>
    

    Como a string sample_text deve ser sobreposta por um RRO, inclua o nome do recurso no overlayable.xml do aplicativo.

    Seu arquivo overlayable.xml DEVE residir em res/values/ . Caso contrário, o OverlayManagerService não poderá localizá-lo.

    Para saber mais sobre recursos sobrepostos e como eles podem ser configurados, consulte Restringir recursos sobrepostos .

Crie um pacote RRO

Nesta seção, você cria um pacote RRO para alterar a string exibida acima de "Hello World!" para "Olá Mundo RRO".

  1. Para criar um novo projeto, selecione Arquivo > Novo > Novo Projeto . Certifique-se de selecionar Nenhuma atividade em vez de Atividade vazia, pois os pacotes RRO contêm apenas recursos.

    Suas configurações aparecem de forma semelhante às ilustradas abaixo. O local onde eles são salvos pode ser diferente:

  2. Depois de criar o novo projeto CarUiRRO , declare o projeto como um RRO modificando 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>
    

    Fazer isso cria um erro com @xml/sample_overlay . O arquivo resourcesMap mapeia nomes de recursos do pacote de destino para o pacote RRO.

  3. Copie o seguinte bloco de código em …/res/xml/sample_overlay.xml :

    <?xml version="1.0" encoding="utf-8"?>
    <overlay>
        <item target="string/sample_text" value="@string/sample_text"/>
    </overlay>
    
  4. Adicione sample_text a …/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>
    
    Criou a versão Gradle do RRO
  5. Para construir seu alvo RRO, pressione o botão verde Play para criar uma versão Gradle de seu RRO em seu emulador ou dispositivo Android.

  6. Para verificar se seu RRO está instalado corretamente, execute:

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

    Este comando exibe informações úteis sobre o estado dos pacotes RRO no sistema.

    • [ ] designa que o RRO está instalado e pronto para ser ativado.
    • --- indica que o RRO está instalado, mas contém erros.
    • [X] significa que o RRO está instalado e ativado.

    Se o seu RRO contiver erros, consulte Solucionar problemas de sobreposições de recursos de tempo de execução antes de continuar.

  7. Para ativar o RRO e verificar se ele está ativado:

    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
    

Seu aplicativo exibe a string “Hello World RRO”.

Olá mundo RRO!
Figura 4 : Olá, mundo RRO!

Parabéns! Você criou seu primeiro RRO.

Ao usar RROs, você pode usar os sinalizadores --no-resource-deduping e --no-resource-removal do Android Asset Packaging Tool (AAPT2) descritos em Opções de link . Não é necessário adicionar sinalizações neste codelab, mas sugerimos que você as use em seus RROs para evitar a remoção de recursos (e dores de cabeça de depuração). Você pode adicioná-los ao arquivo build.gradle do seu RRO assim:

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

Para saber mais sobre esses sinalizadores, consulte Construir o pacote e AAPT2 .

Modifique componentes car-ui-lib usando RROs em seu aplicativo Android

Esta página descreve como você pode usar uma sobreposição de recursos de tempo de execução (RRO) para modificar componentes da biblioteca car-ui-lib em seu aplicativo Android.

Defina a cor de fundo da barra de ferramentas

Duração: 15 minutos

Para alterar a cor de fundo da barra de ferramentas:

  1. Adicione o seguinte valor ao seu aplicativo RRO e defina o recurso como verde brilhante ( #0F0 ):

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

    A biblioteca car-ui-lib contém um recurso chamado car_ui_toolbar_background . Quando este recurso está contido na configuração de um RRO, a barra de ferramentas não muda porque o valor errado é direcionado.

  2. No AndroidManifest.xml do seu RRO, atualize targetName para apontar para car-ui-lib :

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

    Você DEVE criar um novo pacote RRO para cada pacote de destino que deseja RRO. Por exemplo, ao criar sobreposições para dois destinos diferentes, você deve criar dois apks de sobreposição.

  3. Crie, verifique, instale e ative o RRO da mesma forma que antes.

Seu aplicativo aparece assim:

Nova cor de fundo da barra de ferramentas
Figura 5 : Nova cor de fundo da barra de ferramentas

Layouts e estilos RRO

Duração: 15 minutos

Neste exercício, você criará um novo aplicativo semelhante ao aplicativo criado anteriormente. Este aplicativo permite que o layout seja sobreposto. Siga as mesmas etapas anteriores ou modifique seu aplicativo existente.

  1. Certifique-se de adicionar as seguintes linhas ao 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. Certifique-se de que activity_main.xml apareça da seguinte forma:

    <?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. Em seu aplicativo RRO, crie um res/layout/activity_main.xml e adicione o seguinte:

    <?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. Atualize res/values/styles.xml para adicionar nosso estilo ao 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. Altere targetName em AndroidManifest.xml para apontar para o nome do seu novo aplicativo:

    …
    android:targetName="CarUiCodelab"
    …
    
  6. Adicione os recursos ao arquivo sample_overlay.xml em seu 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. Crie e instale o aplicativo e o RRO da mesma forma que antes (botão verde Play ). Certifique-se de habilitar seu RRO.

O aplicativo e o RRO são renderizados da seguinte maneira. O texto Hello World RRO é verde e centralizado conforme especificado no layout RRO.

Olá mundo RRO
Figura 6 : Olá Mundo RRO

Adicione CarUiRecyclerView ao seu aplicativo

Duração: 15 minutos

A interface CarUiRecyclerView fornece APIs para acessar um RecyclerView personalizado por meio de recursos car-ui-lib . Por exemplo, CarUiRecyclerView verifica um sinalizador em tempo de execução para determinar se a barra de rolagem deve ser habilitada ou não e seleciona o layout correspondente.

CarUiRecyclerViewContainer
Figura 7. CarUiRecyclerViewContainer
  1. Para adicionar um CarUiRecyclerView , adicione-o aos seus arquivos activity_main.xml e MainActivity.java . Você pode criar um novo aplicativo do zero ou modificar o aplicativo existente. Se você modificar o aplicativo existente, remova os recursos não declarados de 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"/>
    

    O seguinte erro pode aparecer, que você pode ignorar:

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

    Contanto que sua classe esteja escrita corretamente e você tenha adicionado car-ui-lib como uma dependência, você pode construir e compilar seu apk. Para remover o erro, selecione Arquivo > Invalidar Caches e clique em Invalidar e Reiniciar.

    Adicione o seguinte ao 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. Crie e instale seu aplicativo como antes.

Agora você vê um CarUiRecyclerView :

CarUiRecyclerView
Figura 7 : CarUiRecyclerView

Use um RRO para remover a barra de rolagem

Duração: 10 minutos

Este exercício mostra como usar um RRO para remover a barra de rolagem de CarUiRecyclerView .

  1. No seu RRO, adicione e modifique os seguintes arquivos:

    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>
    

    O recurso car_ui_scrollbar_enable é um recurso booleano car-ui-lib , que controla se a barra de rolagem otimizada para carro com botões para cima e para baixo em CarUiRecyclerView está presente ou não. Quando definido como false , CarUiRecyclerView atua como um 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>
    

Crie e instale seu aplicativo como antes. A barra de rolagem agora foi removida de CarUiRecyclerView :

CarUiRecyclerView sem barra de rolagem
Figura 8. CarUiRecyclerView sem barra de rolagem

Use um layout para sobrepor a barra de rolagem CarUiRecyclerView

Duração: 15 minutos

Neste exercício, você modifica o layout da barra de rolagem CarUiRecyclerView .

  1. Adicione e modifique os seguintes arquivos em seu aplicativo 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>
    

    Para sobrepor um arquivo de layout, você deve adicionar todos os IDs e atributos de namespace ao overlay.xml do seu RRO. Veja os arquivos abaixo.

    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>
    

    Sugere-se examinar como esses arquivos interagem.

    Para simplificar, as dimensões e cores são codificadas. No entanto, uma prática recomendada é declarar esses valores em dimens.xml e colors.xml ou mesmo designá-los como arquivos de cores na pasta res/color/ . Para saber mais, consulte Estilo de código Java AOSP para colaboradores .

  2. Crie e instale seu aplicativo como antes. Você construiu CarUiRecyclerView com uma barra de rolagem azul e trilhos cinza.

Parabéns! Ambas as setas aparecem na parte inferior da barra de rolagem. Você aplicou com êxito um RRO a um arquivo de recurso de layout car-ui-lib usando o sistema de compilação Gradle por meio do Android Studio.

CarUiRecyclerView com uma barra de rolagem azul com trilhos cinza
Figura 9. CarUiRecyclerView com uma barra de rolagem azul com trilhos cinza

Itens da lista RRO

Duração: 15 minutos

Até este ponto, você aplicou um RRO aos componentes car-ui-lib usando componentes de estrutura (não AndroidX). Para usar componentes AndroidX em um RRO, você deve adicionar as dependências desse componente ao aplicativo e ao RRO build.gradle. Você também deve adicionar attrs desse componente ao overlayable.xml no seu aplicativo, bem como ao sample_overlay.xml no seu RRO.

Nossa biblioteca ( car-ui-lib ) usa ConstraintLayout , bem como outros componentes do AndroidX, então seu overlayable.xml pode ficar assim:

<?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. Altere o layout dos itens da lista no CarUiRecyclerView usando ConstraintLayout . Adicione ou modifique os seguintes arquivos em seu 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 faz referência a vários componentes/recursos que não estão incluídos como dependências do aplicativo. Estes são recursos car-ui-lib . Você pode corrigir isso adicionando car-ui-lib como uma dependência ao seu aplicativo RRO em 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'
    }
    

O título e o corpo agora estão alinhados à direita em vez de alinhados à esquerda.

Título e corpo alinhados à direita
Figura 10. Título e corpo alinhados à direita

Aplicamos um RRO a car-ui-lib usando componentes AndroidX ( ConstraintLayout ) apenas quando seus atributos estavam presentes no arquivo car-ui-lib chamado overlayable.xml , bem como no RRO sample_overlay.xml . É possível fazer algo semelhante em seu próprio aplicativo. Basta adicionar todos os attrs correspondentes ao overlayable.xml do seu aplicativo, semelhante a car-ui-lib .

No entanto, não é possível fazer RRO de um aplicativo usando componentes AndroidX quando o aplicativo tem car-ui-lib como dependência em seu build.gradle (quando o aplicativo usa componentes car-ui-lib ). Como os mapeamentos de atributos já foram definidos no overlayable.xml da biblioteca car-ui-lib , adicioná-los ao overlayable.xml do seu aplicativo com car-ui-lib como uma dependência causaria um erro mergeDebugResources como o abaixo. Isso ocorre porque esses atributos estão presentes em vários arquivos overlayable.xml :

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