使用 car-ui-lib
库启动自相一致的车载信息娱乐 (IVI)。此 Codelab 将向您介绍 car-ui-lib
,以及如何使用运行时资源叠加层 (RRO) 自定义库中的组件。
学习内容
如何执行以下操作:
- 在您的 Android 应用中添加
car-ui-lib
组件。 - 使用 Gradle 构建 Android 应用和 RRO。
- 将 RRO 与
car-ui-lib
搭配使用。
此 Codelab 不会详细介绍 RRO 的工作原理。如需了解详情,请参阅在运行时更改应用资源的值和排查运行时资源叠加层问题。
开始前须知
前提条件
开始前,请先确保您拥有以下设备及知识:
带命令行的计算机(Linux 计算机、Mac 或带有适用于 Linux 的 Windows 子系统的 Windows 计算机)。
连接到计算机的 Android 设备或模拟器。请参阅下载 Android 源代码和构建 Android。
RRO 基础知识。
创建新的 Android 应用
时长:15 分钟
在本部分中,您将创建一个新的 Android Studio 项目。
在 Android Studio 中,创建具有
EmptyActivity
的应用。图 1. 创建 Empty Activity 将应用命名为
CarUiCodelab
,然后选择 Java 语言。如果需要,您还可以选择文件位置。其余设置保持默认值。图 2. 为应用命名 将
activity_main.xml
替换为以下代码块:<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sample_text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
此代码块会显示未定义的字符串
sample_text
。添加
sample_text
资源字符串,并在strings.xml
文件中将其设置为“Hello World!”。如需打开此文件,请依次选择 app > src > main > res > values > strings.xml。<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">CarUiCodelab</string> <string name="sample_text">Hello World!</string> </resources>
如需构建应用,请点击右上角的绿色 Play 按钮。这样做会自动通过 Gradle 将 APK 安装到模拟器或 Android 设备上。
新应用应该会在模拟器或 Android 设备上自动打开。如果没有,请从应用启动器(现已安装)打开 CarUiCodelab
应用。
如下所示:
![打开新的 CarUiCodelab 应用](https://source.android.com/static/docs/automotive/images/codelab_04.png?hl=zh-cn)
将 car-ui-lib 添加到您的 Android 应用
时长:15 分钟
将 car-ui-lib
添加到您的应用:
如需将
car-ui-lib
依赖项添加到项目的build.gradle
文件中,请依次选择 app > build.gradle。您的依赖项应如下所示:dependencies { implementation 'com.android.car.ui:car-ui-lib:2.0.0' implementation 'androidx.appcompat:appcompat:1.4.1' implementation 'com.google.android.material:material:1.4.0' implementation 'androidx.constraintlayout:constraintlayout:2.1.4' }
在 Android 应用中使用 car-ui-lib 组件
现在,您已经有了 car-ui-lib
,请将工具栏添加到您的应用。
在
MainActivity.java
文件中,替换onCreate
方法:@Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); // Get the toolbar controller instance. ToolbarController toolbar = CarUi.getToolbar(this); // Set the title on toolbar. toolbar.setTitle(getTitle()); // Set the logo to be shown with the title. toolbar.setLogo(R.mipmap.ic_launcher_round); }
请务必导入
ToolbarController
:import com.android.car.ui.core.CarUi; import com.android.car.ui.toolbar.ToolbarController;
如需使用
Theme.CarUi.WithToolbar
主题,请依次选择 app > src > main > AndroidManifest.xml,然后更新AndroidManifest.xml
,使其如下所示:<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" package="com.example.caruicodelab"> <application android:allowBackup="true" android:dataExtractionRules="@xml/data_extraction_rules" android:fullBackupContent="@xml/backup_rules" android:icon="@mipmap/ic_launcher" android:label="@string/app_name" android:roundIcon="@mipmap/ic_launcher_round" android:supportsRtl="true" android:theme="@style/Theme.CarUi.WithToolbar" tools:targetApi="31"> <activity android:name=".MainActivity" android:exported="true"> <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>
如需构建应用,请像之前一样按绿色的 Play 按钮。
向应用添加 RRO
时长: 30 分钟
如果您熟悉 RRO,请转到下一部分,即向应用添加权限控制器。否则,如需了解 RRO 基础知识,请参阅在运行时更改应用资源的值。
向应用添加权限控制器
如需控制 RRO 软件包叠加的资源,请将名为 overlayable.xml
的文件添加到应用的 /res
文件夹中。该文件充当应用(目标)和 RRO 软件包(叠加层)之间的权限控制器。
将
res/values/overlayable.xml
添加到您的应用,并将以下内容复制到您的文件中:<?xml version="1.0" encoding="utf-8"?> <resources> <overlayable name="CarUiCodelab"> <policy type="public"> <item type="string" name="sample_text"/> </policy> </overlayable> </resources>
由于字符串
sample_text
必须可由 RRO 叠加,因此请将资源名称添加到应用的 overlayable.xml 中。overlayable.xml
文件必须位于res/values/
中。否则,OverlayManagerService
将无法找到它。如需详细了解可叠加资源以及如何配置这些资源,请参阅限制可叠加资源。
创建 RRO 软件包
在本部分中,您将创建一个 RRO 软件包,以将上面显示的字符串从“Hello World!”更改为“Hello World RRO”。
如需创建新项目,请依次选择 File > New > New Project。请务必选择 No Activity 而不是 Empty Activity,因为 RRO 软件包仅包含资源。
您的配置看起来与下图所示类似。它们的保存位置可能会有所不同:
创建新的
CarUiRRO
项目后,修改AndroidManifest.xml
以将该项目声明为 RRO。<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.caruirro"> <application android:hasCode="false" /> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <overlay android:targetPackage="com.example.caruicodelab" android:targetName="CarUiCodelab" android:isStatic="false" android:resourcesMap="@xml/sample_overlay" /> </manifest>
这样做会导致
@xml/sample_overlay
错误。resourcesMap
文件会将资源名称从目标软件包映射到 RRO 软件包。将以下代码块复制到
…/res/xml/sample_overlay.xml
:<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="string/sample_text" value="@string/sample_text"/> </overlay>
将
sample_text
添加到…/res/values/strings.xml
中:<?xml version="1.0" encoding="utf-8"?> <resources> <string name="app_name">CarUiRRO</string> <string name="sample_text">Hello World RRO</string> </resources>
如需构建 RRO 目标,请按绿色的 Play 按钮,以在模拟器或 Android 设备上创建 RRO 的 Gradle build。
如需验证 RRO 是否已正确安装,请运行以下命令:
shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [ ] com.example.caruirro
此命令会显示有关系统上 RRO 软件包状态的实用信息。
[ ]
表示 RRO 已安装,可以激活。---
表示 RRO 已安装,但包含错误。[X]
表示 RRO 已安装并激活。
如果 RRO 包含错误,请参阅排查运行时资源叠加层问题,然后再继续。
如需启用 RRO 并验证其已启用,请执行以下操作:
shell:~$ adb shell cmd overlay enable --user current com.example.caruirro shell:~$ adb shell cmd overlay list --user current | grep -i com.example com.example.caruicodelab [x] com.example.caruirro
您的应用会显示字符串“Hello World RRO”。
![Hello World RRO!](https://source.android.com/static/docs/automotive/images/codelab_09.png?hl=zh-cn)
恭喜!您已创建第一个 RRO。
使用 RRO 时,您可能需要使用 Android 资源打包工具 (AAPT2) 标志 --no-resource-deduping
和 --no-resource-removal
,如链接选项中所述。在此 Codelab 中无需添加上述标志,但我们建议您在 RRO 中使用这些标志,以免移除资源(以及解决调试问题)。您可以如下所示地将它们添加到 RRO 的 build.gradle
文件中:
android {
…
aaptOptions {
additionalParameters "--no-resource-deduping", "--no-resource-removal"
}
}
在 Android 应用中使用 RRO 修改 car-ui-lib
组件
本页介绍了如何使用运行时资源叠加层 (RRO) 来修改 Android 应用 car-ui-lib
库中的组件。
设置工具栏背景颜色
时长:15 分钟
若要更改工具栏的背景颜色,请执行以下操作:
将以下值添加到您的 RRO 应用,并将资源设置为亮绿色 (
#0F0
):<?xml version="1.0" encoding="utf-8"?> <resources> <drawable name="car_ui_toolbar_background">#0F0</drawable> </resources>
car-ui-lib
库包含一个名为car_ui_toolbar_background
的资源。当该资源包含在 RRO 的配置中时,工具栏不会更改,因为定位的值不正确。在 RRO 的
AndroidManifest.xml
中,将targetName
更新为指向car-ui-lib
:… android:targetName="car-ui-lib" …
您必须为要设为 RRO 的每个目标软件包创建一个新的 RRO 软件包。例如,在为两个不同的目标创建叠加层时,必须创建两个叠加层 APK。
按照与之前相同的方式构建、验证、安装和启用 RRO。
您的应用如下所示:
![新的工具栏背景颜色](https://source.android.com/static/docs/automotive/images/codelab_10.png?hl=zh-cn)
RRO 布局和样式
时长:15 分钟
在本练习中,您将构建一个与之前构建的应用类似的新应用。此应用允许叠加布局。按照与之前相同的步骤操作,或修改现有应用。
请务必将以下几行代码添加到
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>
确保
activity_main.xml
如下所示:<?xml version="1.0" encoding="utf-8"?> <androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sample_text" app:layout_constraintBottom_toBottomOf="parent" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toTopOf="parent" /> </androidx.constraintlayout.widget.ConstraintLayout>
在 RRO 应用中,创建一个
res/layout/activity_main.xml
并添加以下代码:<?xml version="1.0" encoding="utf-8"?> <FrameLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent"> <TextView android:id="@+id/textView" android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="@string/sample_text" android:textAppearance="@style/TextAppearance.CarUi" android:layout_gravity="center_vertical|center_horizontal"/> </FrameLayout>
更新
res/values/styles.xml
以将样式添加到 RRO:<?xml version="1.0" encoding="utf-8"?> <resources> <style name="TextAppearance.CarUi" parent="android:TextAppearance.DeviceDefault"> <item name="android:textColor">#0f0</item> <item name="android:textSize">100sp</item> </style> </resources>
将
AndroidManifest.xml
中的targetName
更改为指向新应用的名称:… android:targetName="CarUiCodelab" …
将资源添加到 RRO 中的
sample_overlay.xml
文件:<?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>
采用与之前相同的方式构建和安装应用及 RRO(绿色的 Play 按钮)。请务必启用 RRO。
应用和 RRO 的渲染效果如下所示。Hello World RRO 文本为绿色,并按照布局 RRO 中指定的方式居中显示。
![Hello World RRO](https://source.android.com/static/docs/automotive/images/codelab_11.png?hl=zh-cn)
将 CarUiRecyclerView 添加到您的应用
时长:15 分钟
CarUiRecyclerView
接口提供了用于访问通过 car-ui-lib
资源自定义的 RecyclerView
的 API。例如,CarUiRecyclerView
会在运行时检查标志以确定是否应启用滚动条,并选择对应的布局。
![CarUiRecyclerViewContainer](https://source.android.com/static/docs/automotive/images/codelab_12.png?hl=zh-cn)
如需添加
CarUiRecyclerView
,请将其添加到activity_main.xml
和MainActivity.java
文件中。您可以从头开始创建新应用,也可以修改现有应用。如果您修改现有应用,请务必从overlayable.xml
中移除未声明的资源。activity_main.xml
<?xml version="1.0" encoding="utf-8"?> <com.android.car.ui.recyclerview.CarUiRecyclerView android:id="@+id/list" android:layout_width="match_parent" android:layout_height="match_parent"/>
系统可能会显示以下错误,您可以忽略:
Cannot resolve class com.android.car.ui.recyclerview.CarUiRecyclerView
只要您的类拼写正确,并且您已将
car-ui-lib
添加为依赖项,您就可以构建和编译 APK。如需消除此错误,请依次选择 File > Invalidate Caches,然后点击 Invalidate and Restart。将以下内容添加到
MainActivity.java
package com.example.caruicodelab; import android.app.Activity; import android.os.Bundle; import com.android.car.ui.core.CarUi; import com.android.car.ui.recyclerview.CarUiContentListItem; import com.android.car.ui.recyclerview.CarUiListItem; import com.android.car.ui.recyclerview.CarUiListItemAdapter; import com.android.car.ui.recyclerview.CarUiRecyclerView; import com.android.car.ui.toolbar.ToolbarController; import java.util.ArrayList; /** Activity with a simple car-ui layout. */ public class MainActivity extends Activity { private final ArrayList<CarUiListItem> mData = new ArrayList<>(); private CarUiListItemAdapter mAdapter; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); ToolbarController toolbar = CarUi.getToolbar(this); toolbar.setTitle(getTitle()); toolbar.setLogo(R.mipmap.ic_launcher_round); CarUiRecyclerView recyclerView = findViewById(R.id.list); mAdapter = new CarUiListItemAdapter(generateSampleData()); recyclerView.setAdapter(mAdapter); } private ArrayList<CarUiListItem> generateSampleData() { for (int i = 0; i < 20; i++) { CarUiContentListItem item = new CarUiContentListItem(CarUiContentListItem.Action.ICON); item.setTitle("Title " + i); item.setPrimaryIconType(CarUiContentListItem.IconType.CONTENT); item.setIcon(getDrawable(R.drawable.ic_launcher_foreground)); item.setBody("body " + i); mData.add(item); } return mData; }
像以前一样构建和安装应用。
您现在会看到 CarUiRecyclerView
:
![CarUiRecyclerView](https://source.android.com/static/docs/automotive/images/codelab_13.png?hl=zh-cn)
使用 RRO 移除滚动条
时长: 10 分钟
本练习介绍了如何使用 RRO 从 CarUiRecyclerView
中移除滚动条。
在您的 RRO 中,添加和修改以下文件:
AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.example.caruirro"> <application android:hasCode="false" /> <uses-sdk android:minSdkVersion="29" android:targetSdkVersion="29"/> <overlay android:targetPackage="com.example.caruicodelab" android:targetName="car-ui-lib" android:isStatic="false" android:resourcesMap="@xml/sample_overlay" /> </manifest>
res/values/bools.xml
<?xml version="1.0" encoding="utf-8"?> <resources> <bool name="car_ui_scrollbar_enable">false</bool> </resources>
资源
car_ui_scrollbar_enable
是car-ui-lib
布尔值资源,用于控制CarUiRecyclerView
中是否存在带有向上和向下按钮且经过优化的汽车滚动条。设置为false
时,CarUiRecyclerView
的作用相当于 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>
像以前一样构建和安装应用。滚动条现已从 CarUiRecyclerView
中移除:
![不带滚动条的 CarUiRecyclerView](https://source.android.com/static/docs/automotive/images/codelab_14.png?hl=zh-cn)
使用布局叠加 CarUiRecyclerView 滚动条
时长:15 分钟
在本练习中,您将修改 CarUiRecyclerView
滚动条布局。
在您的 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>
如需叠加布局文件,您必须将所有 ID 和命名空间属性添加到 RRO 的
overlay.xml
中。请参阅以下文件。res/xml/sample_overlay.xml
<?xml version="1.0" encoding="utf-8"?> <overlay> <item target="drawable/car_ui_recyclerview_ic_down" value="@drawable/car_ui_recyclerview_ic_down"/> <item target="drawable/car_ui_recyclerview_ic_up" value="@drawable/car_ui_recyclerview_ic_up"/> <item target="drawable/car_ui_recyclerview_scrollbar_thumb" value="@drawable/car_ui_recyclerview_scrollbar_thumb"/> <item target="id/car_ui_scroll_bar" value="@id/car_ui_scroll_bar"/> <item target="id/car_ui_scrollbar_thumb" value="@id/car_ui_scrollbar_thumb"/> <item target="id/car_ui_scrollbar_track" value="@id/car_ui_scrollbar_track"/> <item target="id/car_ui_scrollbar_page_up" value="@id/car_ui_scrollbar_page_up"/> <item target="id/car_ui_scrollbar_page_down" value="@id/car_ui_scrollbar_page_down"/> <item target="layout/car_ui_recyclerview_scrollbar" value="@layout/car_ui_recyclerview_scrollbar"/> </overlay>
res/drawable/car_ui_recyclerview_ic_up.xml
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="48.0" android:viewportHeight="48.0"> <path android:pathData="M14.83,30.83L24,21.66l9.17,9.17L36,28 24,16 12,28z" android:fillColor="#0000FF"/> </vector>
res/drawable/car_ui_recyclerview_ic_down.xml
<?xml version="1.0" encoding="utf-8"?> <vector xmlns:android="http://schemas.android.com/apk/res/android" android:width="48dp" android:height="48dp" android:viewportWidth="48.0" android:viewportHeight="48.0"> <path android:pathData="M14.83,16.42L24,25.59l9.17,-9.17L36,19.25l-12,12 -12,-12z" android:fillColor="#0000FF"/> </vector>
res/drawable/car_ui_recyclerview_scrollbar_thumb.xml
<?xml version="1.0" encoding="utf-8"?> <shape xmlns:android="http://schemas.android.com/apk/res/android" android:shape="rectangle"> <solid android:color="#0000FF" /> <corners android:radius="100dp"/> </shape>
建议您检查这些文件的互动方式。
为简单起见,尺寸和颜色已硬编码。但最佳做法是在
dimens.xml
和colors.xml
中声明这些值,甚至在res/color/
文件夹中将其指定为颜色文件。如需了解详情,请参阅面向贡献者的 AOSP Java 代码样式。像以前一样构建和安装应用。您已使用蓝色滚动条和灰色侧边栏构建了
CarUiRecyclerView
。
恭喜!两个箭头都显示在滚动条的底部,您已成功通过 Android Studio 使用 Gradle 构建系统将 RRO 应用于 car-ui-lib
布局资源文件。
![带有蓝色滚动条和灰色侧边栏的 CarUiRecyclerView](https://source.android.com/static/docs/automotive/images/codelab_15.png?hl=zh-cn)
RRO 列表项
时长:15 分钟
至此,您已使用框架组件(而非 AndroidX)将 RRO 应用到 car-ui-lib
组件。如需在 RRO 中使用 AndroidX 组件,您必须将该组件的依赖项同时添加到应用和 RRO build.gradle.
中。您还必须将该组件的 attrs
添加到应用中的 overlayable.xml
以及 RRO 中的 sample_overlay.xml
。
我们的库 (car-ui-lib
) 使用 ConstraintLayout
以及其他 AndroidX 组件,因此其 overlayable.xml
可能如下所示:
<?xml version='1.0' encoding='UTF-8'?>
<resources>
<overlayable name="car-ui-lib">
…
<item type="attr" name="layout_constraintBottom_toBottomOf"/>
<item type="attr" name="layout_constraintBottom_toTopOf"/>
<item type="attr" name="layout_constraintCircle"/>
<item type="attr" name="layout_constraintCircleAngle"/>
<item type="attr" name="layout_constraintCircleRadius"/>
<item type="attr" name="layout_constraintDimensionRatio"/>
<item type="attr" name="layout_constraintEnd_toEndOf"/>
<item type="attr" name="layout_constraintEnd_toStartOf"/>
<item type="attr" name="layout_constraintGuide_begin"/>
<item type="attr" name="layout_constraintGuide_end"/>
<item type="attr" name="layout_constraintGuide_percent"/>
<item type="attr" name="layout_constraintHeight_default"/>
<item type="attr" name="layout_constraintHeight_max"/>
<item type="attr" name="layout_constraintHeight_min"/>
<item type="attr" name="layout_constraintHeight_percent"/>
<item type="attr" name="layout_constraintHorizontal_bias"/>
<item type="attr" name="layout_constraintHorizontal_chainStyle"/>
<item type="attr" name="layout_constraintHorizontal_weight"/>
<item type="attr" name="layout_constraintLeft_creator"/>
<item type="attr" name="layout_constraintLeft_toLeftOf"/>
<item type="attr" name="layout_constraintLeft_toRightOf"/>
<item type="attr" name="layout_constraintRight_creator"/>
<item type="attr" name="layout_constraintRight_toLeftOf"/>
<item type="attr" name="layout_constraintRight_toRightOf"/>
<item type="attr" name="layout_constraintStart_toEndOf"/>
<item type="attr" name="layout_constraintStart_toStartOf"/>
<item type="attr" name="layout_constraintTag"/>
<item type="attr" name="layout_constraintTop_creator"/>
<item type="attr" name="layout_constraintTop_toBottomOf"/>
<item type="attr" name="layout_constraintTop_toTopOf"/>
<item type="attr" name="layout_constraintVertical_bias"/>
<item type="attr" name="layout_constraintVertical_chainStyle"/>
…
</overlayable>
</resources>
使用
ConstraintLayout
更改CarUiRecyclerView
中列表项的布局。在 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
引用了若干个组件/资源,这些组件/资源未作为应用的依赖项包含在内,它们是car-ui-lib
资源。如需解决此问题,您可以在app/build.gradle
中将car-ui-lib
作为依赖项添加到 RRO 应用中: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' }
Title 和 Body 现在已右对齐,而不是左对齐。
![右对齐的 Title 和 Body](https://source.android.com/static/docs/automotive/images/codelab_16.png?hl=zh-cn)
只有当属性在名为 overlayable.xml
及 RRO sample_overlay.xml
的 car-ui-lib
文件中时,我们才使用 AndroidX 组件 (ConstraintLayout
) 对 car-ui-lib
应用了 RRO。您可以在自己的应用中执行类似的操作。只需将所有对应的 attrs
添加到应用的 overlayable.xml
中,类似于 car-ui-lib
即可。
不过,如果应用在其 build.gradle
中有 car-ui-lib
作为依赖(当应用使用 car-ui-lib
组件时),则无法使用 AndroidX 组件对应用设置 RRO。由于属性映射已在 car-ui-lib
库的 overlayable.xml
中定义,将它们添加到应用的 overlayable.xml
并将 car-ui-lib
设为依赖项会导致 mergeDebugResources
错误,如下所示。这是因为这些属性出现在多个 overlayable.xml
文件中:
org.gradle.api.tasks.TaskExecutionException: Execution failed for task ':app:mergeDebugResources'