再不迁移到Material Design Components 就out啦

5,642 阅读6分钟

翻译自国外文档加自己理解 原文

声明

我们最近宣布了 Material Design Components(MDC)1.1.0 ,这是一个库更新,为您的 Android 应用程序带来了 Material Theming 、新的组件、深色主题和其他令人兴奋的功能。

MDC取代了设计支持库。本指南将向您展示如何迁移代码库,以便您可以使用新的属性,样式和小部件。

精简的主题示例

本指南使用了精简的应用程序来演示迁移过程。它使用AppCompat主题,设计支持库中的小部件(包括具有自定义背景的按钮)以及需要迁移的各种其他元素。我们将从使用传统AppCompat模板的应用程序主题开始:

<style name="Theme.App" parent="Theme.AppCompat.*">
    <item name="colorPrimary">@color/navy_700</item>
    <item name="colorPrimaryDark">@color/navy_900</item>
    <item name="colorAccent">@color/green_300</item>
</style>

使用 AppCompatDesign Support Library 的 APP

Support Library 迁移到 JetPack

在使用MDC之前,您需要从支持库迁移到Android Jetpack。Jetpack使用新的androidx.*名称空间,并将以前的支持库程序包拆分为单独维护的语义版本化的库,从而提供部分功能的新库。MDC是使用AndroidX库构建的,因此必须进行迁移。

要迁移到 AndroidX ,建议您遵循官方开发人员文档。 Android Studio中的 重构 > 迁移到 AndroidX 工具会将您的 Design Support Library 依赖重构成 MDC

更新到 MDC

首先要将build.gradle 依赖中

com.android.support:design:28.0.0 修改成 com.google.android.material:material:1.0.0

更改主题

需要将 app 的主题修改成 Material Components 主题的子类

<style name = "Theme.App" parent = "Theme.AppCompat.*" 修改成

<style name = "Theme.App" parent = "Theme.MaterialComponents.">

MDC 主题中有样式和 AppCompat 一一对应,在大多数情况下,只需要简单的将 AppCompat 替换成 MaterialComponents 就可以了

AppCompat themeMDC-Android theme
Theme.AppCompatTheme.MaterialComponents
Theme.AppCompat.NoActionBarTheme.MaterialComponents.NoActionBar
Theme.AppCompat.Dialog.*Theme.MaterialComponents.Dialog.*
Theme.AppCompat.DialogWhenLargeTheme.MaterialComponents.DialogWhenLarge
Theme.AppCompat.LightTheme.MaterialComponents.Light
Theme.AppCompat.Light.DarkActionBarTheme.MaterialComponents.Light.DarkActionBar
Theme.AppCompat.Light.NoActionBarTheme.MaterialComponents.Light.NoActionBar
Theme.AppCompat.Light.Dialog.*Theme.MaterialComponents.Light.Dialog.*
Theme.AppCompat.Light.DialogWhenLargeTheme.MaterialComponents.Light.DialogWhenLarge
Theme.AppCompat.DayNightTheme.MaterialComponents.DayNight
Theme.AppCompat.DayNight.DarkActionBarTheme.MaterialComponents.DayNight.DarkActionBar
Theme.AppCompat.DayNight.NoActionBarTheme.MaterialComponents.DayNight.NoActionBar
Theme.AppCompat.DayNight.Dialog.*Theme.MaterialComponents.DayNight.Dialog.*
Theme.AppCompat.DayNight.DialogWhenLargeTheme.MaterialComponents.DayNight.DialogWhenLarge
AppCompat theme overlayMDC-Android theme overlay
ThemeOverlay.AppCompatThemeOverlay.MaterialComponents
ThemeOverlay.AppCompat.LightThemeOverlay.MaterialComponents.Light
ThemeOverlay.AppCompat.DarkThemeOverlay.MaterialComponents.Dark
ThemeOverlay.AppCompat.*.ActionBarThemeOverlay.MaterialComponents.*.ActionBar.*
ThemeOverlay.AppCompat.Dialog.*ThemeOverlay.MaterialComponents.Dialog.*
N/AThemeOverlay.MaterialComponents.*.BottomSheetDialog
N/AThemeOverlay.MaterialComponents.MaterialAlertDialog.*
N/AThemeOverlay.MaterialComponents.MaterialCalendar.*
N/AThemeOverlay.MaterialComponents.Toolbar.*

例子更新

Button 改变

Design 库到 MDC ,样式变成 Theme.MaterialComponents.* 后有了一些变化。拿 Button 来举例,Button失去了自定义背景。现在 Button 有了一个绿色的强调色并且字体间的间距变大了。

那么为什么会这样呢?我们先来看一下布局

<Button
    android:id="@+id/containedButton"
    // 这是自定义的某种颜色的背景
    android:background="@drawable/bg_button_gradient"
    android:textColor="@android:color/white"
    ... />
<Button
    android:id="@+id/textButton"
    style=”?attr/borderlessButtonStyle”
    ... />

之所以出现这种情况是因为,在填充布局的时候,会自动将我们布局中的普通控件替换成 MDC 控件。

和 AppCompat 一样,MDC 会在填充的时候用 MDC 等效的控件来替换某些原始控件。这样就可以发布新功能和错误修正了,而不必将所有声明都换成新的类型。这是通过 MaterialComponentsViewInflater 来完成的,它属于 AppCompatViewInflater 的子类。

映射关系:

Framework widgetAppCompat widget (replaced by AppCompatViewInflater)MDC-Android widget (replaced by MaterialComponentsViewInflater)
ButtonAppCompatButtonMaterialButton
CheckBoxAppCompatCheckBoxMaterialCheckBox
RadioButtonAppCompatRadioButtonMaterialRadioButton
TextViewAppCompatTextViewMaterialTextView
AutoCompleteTextViewAppCompatAutoCompleteTextViewMaterialAutoCompleteTextView

注意:MDC 1.0.0 中只有 Button 控件被替换了。

我们例子中如果是 Theme.AppCompat.* 的主题,那么就会把 ButtonAppCompatButton 来替换。现在把主题修改成 Theme.MaterialComponents.* ,那么就会把 Button 替换成 MaterialButton ,会有默认的 style

AppCompatButton 不同的是 MaterialButton 不支持自定义背景。到 1.2.0-alpha06 版本开始支持。使用 Shape 可以进行变通。下面章节会详细介绍。

更新到 MDC 1.1.0

从 1.0.0 到 1.1.0 有了很多新变化:

  • 完整的 Material Theming
  • Dark Theme 支持
  • Android 10 手势导航支持
  • 新组件:扩展 FAB、date picker、badges、toggle buttons
  • 无障碍功能提升、bug 修复等等

implementation ‘com.google.android.material:material:1.1.0’

一些出乎意料的改变和普通问题

MDC 1.1.0更改了一些默认的小部件样式,以更好地符合“材料设计”准则。但是,升级后,您可能会注意到某些控件颜色和其他属性的某些意外更改。

在上面的示例中,按钮发生了变化、文本和图标的颜色发生了变化。FAB 现在变成了蓝绿色,并且文本字段看起来完全不同。不用担心。我们的当前主题中可能是丢失了一些重要的 MDC 属性,同时有一些重要的 AppCompat 或者原有属性(android:xxx)不再需要。下面我们通过一些常见的迁移方案来了解一下这些问题

文字栏位改变

在 MDC 中,文字字段默认样式发生了改变。改进版本是经过用户调查研究的。

我们建议您使用这个版本,来提高可用性和可配置项性。但是我们意识到这可能并不适合您的品牌和设计系统。

要恢复为旧的文本字段可以在布局中添加样式

<com.google.android.material.textfield.TextInputLayout
    ...
+    style="@style/Widget.Design.TextInputLayout">
    ...
</com.google.android.material.textfield.TextInputLayout>

或者你也可以在主题中给所有的文本设置默认样式

<style name="Theme.App" parent="Theme.MaterialComponents.*">
    ...
+    <item name=”textInputStyle”>@style/Widget.App.TextInputLayout</item>
</style>

+<style name=”Widget.App.TextInputLayout” parent=”Widget.Design.TextInputLayout”>
+    <!-- Custom attrs -->
+</style>

更喜爱 MDC 样式和控件

如上所述,先前支持库的风格已经变成了 MDC 的一部分。在大多数的情况下,我们都可以通过 Widget.MaterialComponents.* 来替换 Widget.Design.* 样式。并且还启用了新的属性,虽然可以不使用,但是我们建议还是采用新的 MDC 样式!

建议使用 MDC 组件来替换AppCompat 或者 MaterialButton (如果有的话)这些组件默认情况下使用更新后的材料设计指南。并且支持启用 Material Theming 和其他功能。

下面这几种情况应该考虑

  • 在布局中写的控件如果有对应的 MDC 控件的话,直接使用 MDC 控件
  • 任何的风格,默认风格和默认风格属性应该改变成 MDC 版本
  • 在编程中或者自定义类的父级类使用的任何控件都应该为 MDC 版本。

完整 控件和样式映射表

MDC-Android widget (moved from Design Support Library)Design Support Library default styleMDC-Android default styleDefault style attr
AppBarLayoutWidget.Design.AppBarLayoutWidget.MaterialComponents.AppBarLayout.*appBarLayoutStyle
BottomNavigationViewWidget.Design.BottomNavigationViewWidget.MaterialComponents.BottomNavigationViewbottomNavigationStyle
BottomSheetBehaviorWidget.Design.BottomSheet.ModalWidget.MaterialComponents.BottomSheet.*bottomSheetStyle
BottomSheetDialog BottomSheetDialogFragmentTheme.Design.Light.BottomSheetDialogTheme.MaterialComponents.*.BottomSheetDialog ThemeOverlay.MaterialComponents.*.BottomSheetDialogbottomSheetDialogTheme
CollapsingToolbarLayoutWidget.Design.CollapsingToolbarN/AN/A
FloatingActionButtonWidget.Design.FloatingActionButtonWidget.MaterialComponents.FloatingActionButtonfloatingActionButtonStyle
NavigationViewWidget.Design.NavigationViewWidget.MaterialComponents.NavigationViewnavigationViewStyle
SnackbarWidget.Design.SnackbarWidget.MaterialComponents.SnackbarsnackbarStyle
TabLayout TabItemWidget.Design.TabLayoutWidget.MaterialComponents.TabLayouttabStyle
TextInputLayout TextInputEditTextWidget.Design.TextInputLayoutWidget.MaterialComponents.TextInputLayout.*textInputStyle
AppCompat widgetAppCompat default styleAppCompat default style attrMDC-Android widgetMDC-Android default styleMDC-Android default style attr
AlertDialog.BuilderAlertDialog.AppCompat ThemeOverlay.AppCompat.Dialog.AlertalertDialogStyle alertDialogThemeMaterialAlertDialogBuilderMaterialAlertDialog.MaterialComponents ThemeOverlay.MaterialComponents.MaterialAlertDialogalertDialogStyle materialAlertDialogTheme
AppCompatAutoCompleteTextViewWidget.AppCompat.AutoCompleteTextViewautoCompleteTextViewStyleMaterialAutoCompleteTextViewWidget.MaterialComponents.AutoCompleteTextView.* ThemeOverlay.MaterialComponents.AutoCompleteTextView.*autoCompleteTextViewStyle
AppCompatButtonWidget.AppCompat.ButtonbuttonStyleMaterialButtonWidget.MaterialComponents.ButtonmaterialButtonStyle
AppCompatCheckBoxWidget.AppCompat.CompoundButton.CheckBoxcheckboxStyleMaterialCheckboxWidget.MaterialComponents.CompoundButton.CheckBoxcheckboxStyle
AppCompatImageViewN/AN/AShapeableImageViewWidget.MaterialComponents.ShapeableImageViewN/A
AppCompatRadioButtonWidget.AppCompat.CompoundButton.RadioButtonradioButtonStyleMaterialRadioButtonWidget.MaterialComponents.CompoundButton.RadioButtonradioButtonStyle
AppCompatTextViewWidget.AppCompat.TextViewN/AMaterialTextViewWidget.MaterialComponents.TextViewN/A
CardViewCardViewcardViewStyleMaterialCardViewWidget.MaterialComponents.CardViewmaterialCardViewStyle
PopupMenuWidget.AppCompat.PopupMenu.*popupMenuStyleN/AWidget.MaterialComponents.PopupMenu.*popupMenuStyle
SwitchCompatWidget.AppCompat.CompoundButton.SwitchswitchStyleSwitchMaterialWidget.MaterialComponents.CompoundButton.SwitchswitchStyle
ToolbarWidget.AppCompat.ToolbartoolbarStyleMaterialToolbarWidget.MaterialComponents.ToolbartoolbarStyle

最新的组件完整列表以及使用文档:material.io/develop/and…

示例更新

用 MDC 版本的组件来替换

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->
-<androidx.cardview.widget.CardView
+<com.google.android.material.card.MaterialCardView
    android:id="@+id/card"
    ...>
    ...
-</androidx.cardview.widget.CardView>
+</com.google.android.material.card.MaterialCardView>

-<androidx.appcompat.widget.SwitchCompat
+<com.google.android.material.switch.SwitchMaterial
    android:id="@+id/switch"
    ... />

颜色

MDC的颜色调色板直接从 Material Design color system 中绘制。

由于MDC-Android,AppCompat和框架之间共享历史记录,因此,颜色属性集包括以下内容:

  • 框架中已适当命名的现有属性(例如android:colorBackground
  • AppCompat中已适当命名的现有属性(例如colorPrimarycolorError
  • 新的属性由MDC介绍(如colorSurfacecolorOnPrimary等)

MDC窗口小部件使用这些属性来为其背景,文本,图标等着色。要了解哪些小部件使用哪种颜色,需要检查源代码中的默认小部件样式。

AppCompat和框架中还存在一些颜色,但不再适用于此新系统。该Theme.MaterialComponents.*主题尽最大努力向后兼容他们,例如小部件,这些旧属性。

<item name="colorAccent">?attr/colorSecondary</item>

但是,您应该考虑不推荐使用这些属性。使用更合适的MDC属性或逐步淘汰它们。

请参阅下面的颜色属性映射表:

注意 AppCompat 中的颜色属性就不要再使用了

AppCompat /框架颜色属性MDC-Android颜色属性
colorPrimarycolorPrimary
colorPrimaryDarkcolorPrimaryVariantandroid:statusBarColor明确指定)
不适用colorOnPrimary
colorAccentcolorSecondary
不适用colorSecondaryVariant
不适用colorOnSecondary
不适用colorSurface
不适用colorOnSurface
android:colorBackgroundandroid:colorBackground
不适用colorOnBackground
colorErrorcolorError
不适用colorOnError
android:textColorPrimaryandroid:textColorSecondary等等。N / A (建议将MDC设置为“ on”属性或使用默认值)
colorControlNormalcolorControlHighlightcolorControlActivatedN / A (“接通”或ATTRS使用默认偏好MDC) ***注意:*这些仍然被用来着色MaterialCheckBoxMaterialRadioButtonSwitchMaterialMaterialToolbar图标

例子

<style name="Theme.App" parent="Theme.MaterialComponents.*">
    ...
    <item name="colorPrimary">@color/navy_700</item>
-    <item name="colorPrimaryDark">@color/navy_900</item>
+    <item name="colorPrimaryVariant">@color/navy_900</item>
-    <item name="colorAccent">@color/green_300</item>
+    <item name="colorSecondary">@color/green_300</item>
+    <item name=”colorSecondaryVariant”>@color/green_500</item>
+    <item name="android:statusBarColor">@color/navy_900</item>
</style>

@color对于包含的按钮文本颜色,我们还应该使用新的“ on”颜色属性

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->
<Button
-    android:textColor="@android:color/white"
+    android:textColor="?attr/colorOnPrimary"
    ... />

字体板式

新的 TextAppearance 样式/属性

MDC字体板式直接从Material Design类型系统中提取。表达的意思就是紧贴 Material Design 风格

引入了一组新的TextAppearance.MaterialComponents.*样式和相应的textAppearance*主题属性,它们替代了现有的AppCompat /框架样式。

MDC小部件使用这些属性来设置文本样式。要知道哪些窗口小部件使用哪种类型板式,需要检查源代码中的默认窗口小部件样式。

请参阅下面的完整类型样式和属性映射表: 13 种类型

AppCompat文字样式MDC-Android文字样式MDC-Android文字属性
TextAppearance.AppCompat.Display4TextAppearance.MaterialComponents.Headline1textAppearanceHeadline1
TextAppearance.AppCompat.Display3TextAppearance.MaterialComponents.Headline2textAppearanceHeadline2
TextAppearance.AppCompat.Display2TextAppearance.MaterialComponents.Headline3textAppearanceHeadline3
TextAppearance.AppCompat.Display1TextAppearance.MaterialComponents.Headline4textAppearanceHeadline4
TextAppearance.AppCompat.HeadlineTextAppearance.MaterialComponents.Headline5textAppearanceHeadline5
TextAppearance.AppCompat.Title TextAppearance.AppCompat.LargeTextAppearance.MaterialComponents.Headline6textAppearanceHeadline6
TextAppearance.AppCompat.Subhead TextAppearance.AppCompat.MenuTextAppearance.MaterialComponents.Subtitle1textAppearanceSubtitle1
TextAppearance.AppCompat.SmallTextAppearance.MaterialComponents.Subtitle2textAppearanceSubtitle2
TextAppearance.AppCompat.Body1TextAppearance.MaterialComponents.Body1textAppearanceBody1
TextAppearance.AppCompat.Body2TextAppearance.MaterialComponents.Body2textAppearanceBody2
TextAppearance.AppCompat.ButtonTextAppearance.MaterialComponents.ButtontextAppearanceButton
TextAppearance.AppCompat.CaptionTextAppearance.MaterialComponents.CaptiontextAppearanceCaption
不适用TextAppearance.MaterialComponents.OverlinetextAppearanceOverline

例子

<com.google.android.material.card.MaterialCardView
    ...>
    ...
    <TextView
        android:id=”@+id/headerText”
-        android:textAppearance="@style/TextAppearance.AppCompat.Title"
+        android:textAppearance="?attr/textAppearanceHeadline6"
        ... />
    <TextView
        android:id=”@+id/subheadText”
        android:textColor="?android:attr/textColorSecondary"
-        android:textAppearance="@style/TextAppearance.AppCompat.Body2"
+        android:textAppearance="?attr/textAppearanceBody2"
        ... />
    <TextView
        android:id=”@+id/supportingText”
        android:textColor="?android:attr/textColorSecondary"
-        android:textAppearance="@style/TextAppearance.AppCompat.Body2"
+        android:textAppearance="?attr/textAppearanceBody2"
        ... />
</com.google.android.material.card.MaterialCardView>

自定义

我们还可以选择在应用程序主题中覆盖类型比例,以使用自定义字体系列,XML或通过Android Studio 下载字体:

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->
<style name="Theme.App" parent="Theme.MaterialComponents.*">
    ...
+    <item name="textAppearanceHeadline6">@style/TextAppearance.App.Headline6</item>
+    <item name="textAppearanceBody2">@style/TextAppearance.App.Body2</item>
</style>

+<style name="TextAppearance.App.Headline6"
+    parent="TextAppearance.MaterialComponents.Headline6">
+    <item name="fontFamily">@font/roboto_mono_medium</item>
+</style>
+<style name="TextAppearance.App.Body2"
+    parent="TextAppearance.MaterialComponents.Body2">
+    <item name="fontFamily">@font/roboto_mono_regular</item>
+</style>

上面我们只是重写了 13 种类型中的一种。如果你想要改变字体的话,建议也把剩余的 12 修改了,以保持APP中字体的一致性。

Shape

ShapeAppearance styles/attributes

Shape( Material Design shape system) 是用来处理 MDC 控件的边角的一种方式,分成了小,中,大

这些合适的样式属性来自 ShapeAppearance.* styles。包括:cornerFamily (两种值:rounded cut) 。用 cornerSize 来表示尺寸

MDC小部件使用这些属性来设置其背景样式。要了解哪些窗口小部件适用于哪些形状类别,需要检查源代码中的默认窗口小部件样式。

控件背景

实现此功能的类为 MaterialShapeDrawable. 默认情况下,所有的 MDC 控件都将此可绘制对象当做背景,我们也可以考虑将它用作自定义 View 的背景。它可以处理形状主题、阴影、黑色主题等等。

因此。我们不建议使用 android:background 作为 MDC 控件的背景。因为它会覆盖 MaterialShapeDrawable。大多数的 MDC 控件的默认 style 都指定了 <item name="android:background">@null</item>

为了避免这种情况,应该使用 shapeApperance/shapeAppearanceOverlaybackgroundTint 属性来调整背景形状和颜色。

以下情况需要单独注意:

  • MaterialButton1.2.0-alpha06 版本前忽略了 android:background 如果你确实需要用这个属性,考虑使用 AppCompatButton 在你的布局中。
  • MaterialShapeDrawable 是不支持 gradients 的。如果确实需要的话,最好用 android:background

例子

在我们的示例中我们可以删除一些由 shape theming 来处理的属性。

<com.google.android.material.bottomnavigation.BottomNavigationView
-    android:background="@android:color/white"
    ... />

<com.google.android.material.card.MaterialCardView
-    app:cardCornerRadius="2dp"
    ...>
    ...
</com.google.android.material.card.MaterialCardView>

使用 corner familysize 来自定义 shape

我们可以选择在应用主题中覆盖形状样式来表达我们自己的品牌。

<style name="Theme.App" parent="Theme.MaterialComponents.*">
    ...
+    <item name="shapeAppearanceSmallComponent">@style/ShapeAppearance.App.SmallComponent</item>
+    <item name="shapeAppearanceMediumComponent">@style/ShapeAppearance.App.MediumComponent</item>
+    <item name="shapeAppearanceLargeComponent">@style/ShapeAppearance.App.LargeComponent</item>
</style>

+<style name="ShapeAppearance.App.SmallComponent"
+   parent="ShapeAppearance.MaterialComponents.SmallComponent">
+    <item name="cornerFamily">rounded</item>
+    <item name="cornerSize">8dp</item>
+</style>
+<style name="ShapeAppearance.App.MediumComponent"
+    parent="ShapeAppearance.MaterialComponents.MediumComponent">
+    <item name="cornerFamily">rounded</item>
+    <item name="cornerSize">12dp</item>
+</style>
+<style name="ShapeAppearance.App.LargeComponent"
+    parent="ShapeAppearance.MaterialComponents.LargeComponent">
+    <item name="cornerFamily">rounded</item>
+    <item name="cornerSize">16dp</item>
+</style>

使用 shape theming 的例子

恢复 Button 的自定义渐变背景

-<Button
+<androidx.appcompat.widget.AppCompatButton
    android:background="@drawable/bg_button_gradient"
+    android:textAppearance="?attr/textAppearanceButton"
    ... />

如果使用的是 MDC 1.2.0-alpha-06 或者更新的版本,可以直接使用 MaterialButtonandroid:background。需要注意的是要清空 backgroundTint,因为在默认的 style 中,backgroundTintcolorPrimary

<!-- Copyright 2020 Google LLC.
   SPDX-License-Identifier: Apache-2.0 -->
<Button
    android:background="@drawable/bg_button_gradient"
+    app:backgroundTint="@null"
    ... />