Usa la biblioteca car-ui-lib para iniciar sistemas de infoentretenimiento (IVI) en el vehículo y coherentes. En este codelab, se presenta car-ui-lib y cómo puedes usar superposiciones de recursos del entorno de ejecución (RRO) para personalizar componentes en la biblioteca.
Qué aprenderás
Instructivo:
- Incluye componentes
car-ui-liben 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 las RRO. Consulta Cómo cambiar el valor de los recursos de una app en el entorno de ejecución y Soluciona problemas de 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:
Una computadora con línea de comandos (máquina Linux, Mac o Windows con el Subsistema de Windows para Linux)
Un dispositivo o emulador de Android conectado a tu máquina (consulta Cómo descargar la fuente de Android y Cómo compilar Android)
Conocimientos básicos de RRO
Crea una app para Android nueva
Duración: 15 minutos
En esta sección, crearás un nuevo proyecto de Android Studio.
En Android Studio, crea una app con una
EmptyActivity.
Figura 1.Crea una actividad vacía Nombra la app
CarUiCodelaby, luego, selecciona el lenguaje Java. También puedes seleccionar una ubicación de archivo si lo deseas. Acepta los valores predeterminados para la configuración restante.
Figura 2. Nombra tu app Reemplaza
activity_main.xmlpor 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_texty configúrala como "Hello World!" en tu archivostrings.xml. Para abrir este archivo, selecciona 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>Para compilar tu app, haz clic en el botón verde Play en la esquina superior derecha. Si lo haces, se instalará automáticamente el APK en tu emulador o dispositivo Android a través de Gradle.
La app nueva debería abrirse automáticamente en tu emulador o dispositivo Android. Si no es así, abre la app CarUiCodelab desde el selector de aplicaciones, que ahora está instalado.
Se ve 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
car-ui-libal archivobuild.gradlede tu proyecto, selecciona app > build.gradle. Tus dependencias deberían verse 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, anula 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.xmlpara 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 estás familiarizado con las RRO, ve a la siguiente sección, Agrega un controlador de permisos a tu app. De lo contrario, para aprender los conceptos básicos de las RRO, consulta Cómo cambiar el valor de los recursos de una app en el entorno 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 sirve como un controlador de permisos entre tu app (el destino) y tu paquete de RRO (la superposición).
Agrega
res/values/overlayable.xmla 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>Dado que la cadena
sample_textdebe superponerse con una RRO, incluye el nombre del recurso en el archivo overlayable.xml de la app.El archivo
overlayable.xmlDEBE residir enres/values/. De lo contrario,OverlayManagerServiceno podrá ubicarlo.Para obtener más información sobre los recursos superponibles y cómo se pueden configurar, consulta Restringe los recursos superponibles.
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 configuraciones se verán de manera similar a las que se muestran a continuación. La ubicación en la que se guardan puede diferir:
Después de crear el nuevo proyecto
CarUiRRO, decláralo como una RRO modificandoAndroidManifest.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>Si lo haces, se generará un error con
@xml/sample_overlay. El archivoresourcesMapasigna nombres de recursos del paquete de destino al paquete de RRO. Configurar la marcahasCodeenfalsees obligatorio 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_texta…/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 la RRO esté instalada correctamente, ejecuta lo siguiente:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirroEste comando muestra información útil sobre el estado de los paquetes de RRO en el sistema.
[ ]indica que la RRO está instalada y lista para activarse.---indica que la RRO está instalada, pero contiene errores.[X]significa que la RRO está instalada y activada.
Si tu RRO contiene errores, consulta Soluciona problemas de superposiciones de recursos del entorno de ejecución antes de continuar.
Para habilitar la RRO y verificar que esté habilitada, 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 primera RRO.
Cuando uses RRO, es posible que quieras usar las marcas de Android Asset Packaging Tool (AAPT2)
--no-resource-deduping y --no-resource-removal 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 agregarlas 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 Compila el paquete y AAPT2.
Modifica componentes de 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 del entorno de ejecución (RRO) para modificar componentes de la biblioteca car-ui-lib en tu app para Android.
Establece 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 configura 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-libcontiene un recurso llamadocar_ui_toolbar_background. Cuando este recurso se incluye en la configuración de una RRO, la barra de herramientas no cambia porque se apunta al valor incorrecto.En el
AndroidManifest.xmlde tu RRO, actualizatargetNamepara que apunte acar-ui-lib:… android:targetName="car-ui-lib" …DEBES crear un nuevo paquete de RRO para cada paquete de destino que quieras RRO. Por ejemplo, cuando creas superposiciones para dos destinos diferentes, debes crear dos APK de superposición.
Compila, verifica, instala y habilita la RRO de la misma manera que antes.
Tu app se ve 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 que se superponga 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.xmlaparezca 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.xmly 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.xmlpara agregar nuestro estilo a la 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
targetNameenAndroidManifest.xmlpara que apunte al nombre de tu app nueva:… android:targetName="CarUiCodelab" …Agrega los recursos al archivo
sample_overlay.xmlen 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 la RRO de la misma manera que antes (botón verde Play). Asegúrate de habilitar tu RRO.
La app y la RRO se renderizan de la siguiente manera. El texto Hello World RRO es verde y está centrado como se especifica en la RRO de diseño.
Agrega CarUiRecyclerView a tu app
Duración: 15 minutos
La interfaz CarUiRecyclerView proporciona APIs para acceder a una RecyclerView
que se personaliza a través de recursos car-ui-lib. Por ejemplo, CarUiRecyclerView verifica una marca en el tiempo de ejecución para determinar si se debe habilitar o no la barra de desplazamiento y selecciona el diseño correspondiente.
Para agregar un
CarUiRecyclerView, agrégalo a tus archivosactivity_main.xmlyMainActivity.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"/>Puede aparecer el siguiente error, que puedes ignorar:
Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerViewSiempre que tu clase esté escrita correctamente y hayas agregado
car-ui-libcomo 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.javapackage 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 una RRO para quitar la barra de desplazamiento
Duración: 10 minutos
En este ejercicio, se muestra cómo usar una 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_enablees un recurso booleanocar-ui-lib, que controla si la barra de desplazamiento optimizada para el vehículo con los botones Arriba y Abajo enCarUiRecyclerViewestá presente o no. Cuando se establece enfalse,CarUiRecyclerViewactúa como un AndroidXRecyclerView.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. Ahora 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.xmlde tu RRO. Consulta los archivos 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 sugiere 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.xmlycolors.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
CarUiRecyclerViewcon una barra de desplazamiento azul y rieles grises.
¡Felicitaciones! Ambas flechas aparecen en la parte inferior de la barra de desplazamiento. Aplicaste correctamente una 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 una RRO a los componentes car-ui-lib con componentes de framework (no AndroidX). Para usar componentes de AndroidX en una RRO, debes agregar las dependencias de ese componente a la app y a la RRO build.gradle. 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
CarUiRecyclerViewconConstraintLayout. 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.xmlhace 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-libcomo 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 una 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 la 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 RRO una app con componentes de AndroidX cuando la app 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'