Usa la biblioteca car-ui-lib
para iniciar sistemas de infoentretenimiento (IVI) en el vehículo y coherentes. En este codelab, se te presenta car-ui-lib
y cómo puedes usar superposiciones de recursos de tiempo de ejecución (RRO) para personalizar componentes en la biblioteca.
Qué aprenderás
Aprenderás a hacer lo siguiente:
- Incluye componentes
car-ui-lib
en tu app para Android. - Usa Gradle para compilar apps para Android y RRO.
- Usa RRO con
car-ui-lib
.
En este codelab, no se detalla cómo funcionan los RRO. Consulta Cómo cambiar el valor de los recursos de una app en el tiempo de ejecución y Cómo solucionar problemas relacionados con las superposiciones de recursos del entorno de ejecución para obtener más información.
Antes de comenzar
Requisitos previos
Antes de comenzar, asegúrate de tener lo siguiente:
Computadora con línea de comandos (máquina Linux, Mac o Windows con el subsistema de Windows para Linux)
Dispositivo o emulador de Android conectado a tu máquina Consulta Cómo descargar el código fuente de Android y Cómo compilar Android.
Conocimientos básicos de los RRO
Crea una nueva app para Android
Duración: 15 minutos
En esta sección, crearás un proyecto nuevo de Android Studio.
En Android Studio, crea una app con un
EmptyActivity
.Figura 1: Cómo crear una actividad vacía Asigna el nombre
CarUiCodelab
a la app y, luego, selecciona el idioma Java. También puedes seleccionar una ubicación de archivo si lo deseas. Acepta los valores predeterminados para el resto de la configuración.Figura 2: Asigna un nombre a tu app Reemplaza
activity_main.xml
por el siguiente bloque 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 bloque de código muestra la cadena
sample_text
, que no está definida.Agrega la cadena de recursos
sample_text
y configúrala como “Hello World!” en tu archivostrings.xml
. Para abrir este archivo, selecciona app > src > main > res > valores > strings.xml.<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">CarUiCodelab</string> <string name="sample_text">Hello World!</string> </resources>
Para compilar la app, haz clic en el botón verde Play en la parte superior derecha. De esta manera, se instalará el APK automáticamente en tu emulador o dispositivo Android a través de Gradle.
La nueva app debería abrirse automáticamente en tu emulador o dispositivo Android. De lo contrario, abre la app de CarUiCodelab
desde el selector de aplicaciones, que ya está instalado.
Se verá de la siguiente manera:

Agrega car-ui-lib a tu app para Android
Duración: 15 minutos
Agrega car-ui-lib
a tu app:
Para agregar la dependencia de
car-ui-lib
al archivobuild.gradle
de tu proyecto, selecciona app > build.gradle. Tus dependencias deberían aparecer de la siguiente manera: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' }
Usa componentes de car-ui-lib en tu app para Android
Ahora que tienes car-ui-lib
, agrega una barra de herramientas a tu app.
En tu archivo
MainActivity.java
, reemplaza el métodoonCreate
:@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); }
Asegúrate de importar
ToolbarController
:import com.android.car.ui.core.CarUi; import com.android.car.ui.toolbar.ToolbarController;
Para usar el tema
Theme.CarUi.WithToolbar
, selecciona app > src > main > AndroidManifest.xml y, luego, actualizaAndroidManifest.xml
para que aparezca de la siguiente manera:<?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>
Para compilar la app, presiona el botón verde Play como antes.
Agrega RRO a tu app
Duración: 30 minutos
Si conoces los RRO, ve a la siguiente sección, Cómo agregar un controlador de permisos a tu app. De lo contrario, para conocer los conceptos básicos de los RRO, consulta Cómo cambiar el valor de los recursos de una app en el tiempo de ejecución.
Agrega un controlador de permisos a tu app
Para controlar qué recursos superpone un paquete de RRO, agrega un archivo llamado overlayable.xml
a la carpeta /res
de tu app. Este archivo funciona como un controlador de permisos entre tu app (el objetivo) y tu paquete de RRO (la superposición).
Agrega
res/values/overlayable.xml
a tu app y copia el siguiente contenido en tu archivo:<?xml version="1.0" encoding="utf-8"?> <resources> <overlayable name="CarUiCodelab"> <policy type="public"> <item type="string" name="sample_text"/> </policy> </overlayable> </resources>
Como la cadena
sample_text
debe poder superponerse con un RRO, incluye el nombre del recurso en overlayable.xml de la app.Tu archivo
overlayable.xml
DEBE residir enres/values/
. De lo contrario,OverlayManagerService
no podrá encontrarlo.Para obtener más información sobre los recursos superpuestos y cómo se pueden configurar, consulta Cómo restringir los recursos superpuestos.
Crea un paquete de RRO
En esta sección, crearás un paquete de RRO para cambiar la cadena que se muestra arriba de “Hello World!” a “Hello World RRO”.
Para crear un proyecto nuevo, selecciona File > New > New Project. Asegúrate de seleccionar No Activity en lugar de Empty Activity, ya que los paquetes de RRO solo contienen recursos.
Tus parámetros de configuración aparecerán de forma similar a los que se ilustran a continuación. La ubicación en la que se guardan puede diferir:
Después de crear el nuevo proyecto
CarUiRRO
, modificaAndroidManifest.xml
para declararlo como un 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>
Si lo haces, se creará un error con
@xml/sample_overlay
. El archivoresourcesMap
asigna los nombres de los recursos del paquete de destino al paquete de RRO. Es obligatorio establecer la marcahasCode
comofalse
para los paquetes de RRO. Además, los paquetes de RRO no pueden contener archivos DEX.Copia el siguiente bloque de código en
…/res/xml/sample_overlay.xml
:<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="string/sample_text" value="@string/sample_text"/> </overlay>
Agrega
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>
Para compilar tu destino de RRO, presiona el botón verde Play para crear una compilación de Gradle de tu RRO en el emulador o dispositivo Android.
Para verificar que el RRO esté instalado correctamente, ejecuta el siguiente comando:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirro
Este comando muestra información útil sobre el estado de los paquetes de RRO en el sistema.
[ ]
designa que el RRO está instalado y listo para activarse.---
indica que el RRO está instalado, pero contiene errores.[X]
significa que el RRO está instalado y activado.
Si tu RRO contiene errores, consulta Cómo solucionar problemas de superposiciones de recursos del entorno de ejecución antes de continuar.
Para habilitar el RRO y verificar que esté habilitado, haz lo siguiente:
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
Tu app muestra la cadena "Hello World RRO".

¡Felicitaciones! Creaste tu primer RRO.
Cuando uses RRO, te recomendamos que uses las marcas --no-resource-deduping
y --no-resource-removal
de Android Asset Packaging Tool (AAPT2) que se describen en Opciones de vinculación.
No es necesario agregar las marcas en este codelab, pero te sugerimos que las uses en tus RRO para evitar la eliminación de recursos (y los dolores de cabeza de depuración). Puedes agregarlos al archivo build.gradle
de tu RRO de la siguiente manera:
android {
…
aaptOptions {
additionalParameters "--no-resource-deduping", "--no-resource-removal"
}
}
Para obtener más información sobre estas marcas, consulta Cómo compilar el paquete y AAPT2.
Modifica los componentes car-ui-lib
con RRO en tu app para Android
En esta página, se describe cómo puedes usar una superposición de recursos de tiempo de ejecución (RRO) para modificar componentes de la biblioteca car-ui-lib
en tu app para Android.
Cómo establecer el color de fondo de la barra de herramientas
Duración: 15 minutos
Para cambiar el color de fondo de la barra de herramientas, haz lo siguiente:
Agrega el siguiente valor a tu app de RRO y establece el recurso en verde brillante (
#0F0
):<?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="car_ui_toolbar_background">#0F0</drawable> </resources>
La biblioteca
car-ui-lib
contiene un recurso llamadocar_ui_toolbar_background
. Cuando este recurso se incluye en la configuración de un RRO, la barra de herramientas no cambia porque se segmenta el valor incorrecto.En el
AndroidManifest.xml
de tu RRO, actualizatargetName
para que apunte acar-ui-lib
:… android:targetName="car-ui-lib" …
DEBES crear un paquete de RRO nuevo para cada paquete de destino que quieras que tenga este tipo de lanzamiento. Por ejemplo, cuando creas superposiciones para dos objetivos diferentes, debes crear dos APK de superposición.
Compila, verifica, instala y habilita el RRO de la misma manera que antes.
Tu app aparecerá de la siguiente manera:

Diseños y estilos de RRO
Duración: 15 minutos
En este ejercicio, compilarás una app nueva similar a la que compilaste antes. Esta app permite superponer el diseño. Sigue los mismos pasos que antes o modifica tu app existente.
Asegúrate de agregar las siguientes líneas a
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>
Asegúrate de que
activity_main.xml
aparezca de la siguiente manera:<?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>
En tu app de RRO, crea un
res/layout/activity_main.xml
y agrega lo siguiente:<?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>
Actualiza
res/values/styles.xml
para agregar nuestro estilo al 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>
Cambia el
targetName
enAndroidManifest.xml
para que apunte al nombre de tu app nueva:… android:targetName="CarUiCodelab" …
Agrega los recursos al archivo
sample_overlay.xml
en tu 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>
Compila e instala la app y el RRO de la misma manera que antes (botón verde Play). Asegúrate de habilitar tu RRO.
La app y el RRO se renderizan de la siguiente manera. El texto de RRO de Hello World es verde y está centrado como se especifica en el RRO de diseño.

Agrega CarUiRecyclerView a tu app
Duración: 15 minutos
La interfaz CarUiRecyclerView
proporciona APIs para acceder a un RecyclerView
personalizado a través de recursos car-ui-lib
. Por ejemplo, CarUiRecyclerView
verifica una marca en el tiempo de ejecución para determinar si la barra de desplazamiento debe estar habilitada o no y selecciona el diseño correspondiente.

Para agregar un
CarUiRecyclerView
, agrégalo a tus archivosactivity_main.xml
yMainActivity.java
. Puedes crear una app nueva desde cero o modificar la app existente. Si modificas la app existente, asegúrate de quitar los recursos no declarados deoverlayable.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"/>
Es posible que aparezca el siguiente error, que puedes ignorar:
Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerView
Siempre que la clase esté escrita correctamente y hayas agregado
car-ui-lib
como dependencia, puedes compilar tu APK. Para quitar el error, selecciona File > Invalidate Caches y, luego, haz clic en Invalidate and Restart.Agrega lo siguiente a
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; }
Compila e instala tu app como antes.
Ahora verás un CarUiRecyclerView
:

Usa un RRO para quitar la barra de desplazamiento
Duración: 10 minutos
En este ejercicio, se muestra cómo usar un RRO para quitar la barra de desplazamiento de CarUiRecyclerView
.
En tu RRO, agrega y modifica los siguientes archivos:
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>
El recurso
car_ui_scrollbar_enable
es un recurso booleanocar-ui-lib
, que controla si está presente o no la barra de desplazamiento optimizada para automóviles con botones Arriba y Abajo enCarUiRecyclerView
. Cuando se establece enfalse
,CarUiRecyclerView
actúa como unRecyclerView
de AndroidX.res/xml/sample_overlay.xml
<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="bool/car_ui_scrollbar_enable" value="@bool/car_ui_scrollbar_enable"/> </overlay>
Compila e instala tu app como antes. Se quitó la barra de desplazamiento de CarUiRecyclerView
:

Usa un diseño para superponer la barra de desplazamiento de CarUiRecyclerView
Duración: 15 minutos
En este ejercicio, modificarás el diseño de la barra de desplazamiento CarUiRecyclerView
.
Agrega y modifica los siguientes archivos en tu app de 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 superponer un archivo de diseño, debes agregar todos los IDs y atributos de espacio de nombres al
overlay.xml
de tu RRO. Consulta los archivos que aparecen a continuació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>
Se recomienda examinar cómo interactúan estos archivos.
Para simplificar, las dimensiones y los colores están codificados. Sin embargo, una práctica recomendada es declarar estos valores en
dimens.xml
ycolors.xml
, o incluso designarlos como archivos de color en la carpetares/color/
. Para obtener más información, consulta Estilo de código Java del AOSP para colaboradores.Compila e instala tu app como antes. Compilaste
CarUiRecyclerView
con una barra de desplazamiento azul y rieles grises.
¡Felicitaciones! Ambas flechas aparecen en la parte inferior de la barra de desplazamiento. Aplicaste correctamente un RRO a un archivo de recursos de diseño car-ui-lib
con el sistema de compilación de Gradle a través de Android Studio.

Elementos de lista de RRO
Duración: 15 minutos
Hasta este punto, aplicaste un RRO a los componentes car-ui-lib
con componentes del framework (no AndroidX). Para usar componentes de AndroidX en un RRO, debes agregar
las dependencias de ese componente a la app y al build.gradle.
de RRO. También
debes agregar el attrs
de ese componente a overlayable.xml
en tu app, así como
el sample_overlay.xml
en tu RRO.
Nuestra biblioteca (car-ui-lib
) usa ConstraintLayout
, así como otros componentes de AndroidX, por lo que su overlayable.xml
podría verse de la siguiente manera:
<?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>
Cambia el diseño de los elementos de la lista en
CarUiRecyclerView
conConstraintLayout
. Agrega o modifica los siguientes archivos en tu 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>
car_ui_list_item.xml
hace referencia a varios componentes o recursos que no se incluyen como dependencias de la app. Estos son recursoscar-ui-lib
. Para solucionar este problema, agregacar-ui-lib
como una dependencia a tu app de RRO enapp/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' }
El título y el cuerpo ahora están alineados a la derecha en lugar de a la izquierda.

Solo aplicamos un RRO a car-ui-lib
con componentes de AndroidX (ConstraintLayout
) cuando sus atributos estaban presentes en el archivo car-ui-lib
llamado overlayable.xml
, así como en el RRO sample_overlay.xml
. Es posible hacer algo similar en tu propia app. Solo agrega todos los attrs
correspondientes al overlayable.xml
de tu app, de manera similar a car-ui-lib
.
Sin embargo, no es posible realizar la RRO de una app que usa componentes de AndroidX cuando esta tiene car-ui-lib
como dependencia en su build.gradle
(cuando la app usa componentes car-ui-lib
). Dado que las asignaciones de atributos ya se definieron en el overlayable.xml
de la biblioteca car-ui-lib
, agregarlas al overlayable.xml
de tu app con car-ui-lib
como dependencia provocaría un error mergeDebugResources
como el que se muestra a continuación. Esto se debe a que estos atributos están presentes en varios archivos overlayable.xml
:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'