Android Material 设计问题从 1.0.0 更新到 1.1.0

Android Material Design issues updated from 1.0.0 to 1.1.0

我将 'com.google.android.material:material:1.0.0' 库从 gradle 更新为 'com.google.android.material:material:1.1.0',但现在我的应用程序以返回 InflateException 结束。

此处完全例外:

E/AndroidRuntime: FATAL EXCEPTION: main
Process: com.concas.diffapp, PID: 3893
java.lang.RuntimeException: Unable to start activity ComponentInfo{com.concas.diffapp/com.concas.diffapp.activities.Login}: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class com.google.android.material.textfield.TextInputLayout
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3114)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7050)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
 Caused by: android.view.InflateException: Binary XML file line #19: Binary XML file line #19: Error inflating class com.google.android.material.textfield.TextInputLayout
 Caused by: android.view.InflateException: Binary XML file line #19: Error inflating class com.google.android.material.textfield.TextInputLayout
 Caused by: java.lang.reflect.InvocationTargetException
    at java.lang.reflect.Constructor.newInstance0(Native Method)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:343)
    at android.view.LayoutInflater.createView(LayoutInflater.java:647)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:790)
    at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:730)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:863)
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
    at android.view.LayoutInflater.rInflate(LayoutInflater.java:866)
    at android.view.LayoutInflater.rInflateChildren(LayoutInflater.java:824)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:515)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:423)
    at android.view.LayoutInflater.inflate(LayoutInflater.java:374)
    at androidx.appcompat.app.AppCompatDelegateImpl.setContentView(AppCompatDelegateImpl.java:555)
    at androidx.appcompat.app.AppCompatActivity.setContentView(AppCompatActivity.java:161)
    at com.concas.diffapp.activities.Login.onCreate(Login.java:82)
    at android.app.Activity.performCreate(Activity.java:7327)
    at android.app.Activity.performCreate(Activity.java:7318)
    at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1271)
    at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:3094)
    at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:3257)
    at android.app.servertransaction.LaunchActivityItem.execute(LaunchActivityItem.java:78)
    at android.app.servertransaction.TransactionExecutor.executeCallbacks(TransactionExecutor.java:108)
    at android.app.servertransaction.TransactionExecutor.execute(TransactionExecutor.java:68)
    at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1948)
    at android.os.Handler.dispatchMessage(Handler.java:106)
    at android.os.Looper.loop(Looper.java:214)
    at android.app.ActivityThread.main(ActivityThread.java:7050)
    at java.lang.reflect.Method.invoke(Native Method)
    at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:494)
    at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:965)
Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).
    at com.google.android.material.internal.ThemeEnforcement.checkTheme(ThemeEnforcement.java:248)
    at com.google.android.material.internal.ThemeEnforcement.checkMaterialTheme(ThemeEnforcement.java:222)
    at com.google.android.material.internal.ThemeEnforcement.checkCompatibleTheme(ThemeEnforcement.java:150)
    at com.google.android.material.internal.ThemeEnforcement.obtainTintedStyledAttributes(ThemeEnforcement.java:120)
    at com.google.android.material.textfield.TextInputLayout.<init>(TextInputLayout.java:424)
    at com.google.android.material.textfield.TextInputLayout.<init>(TextInputLayout.java:396)
        ... 32 more

我的风格:

<resources>
<style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar" >
    <item name="colorPrimary">@color/colorPrimary</item>
    <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
    <item name="colorAccent">@color/colorAccent</item>
</style>

<style name="AppTheme.NoActionBar">
    <item name="windowActionBar">false</item>
    <item name="windowNoTitle">true</item>
</style>

<style name="AppTheme.AppBarOverlay" parent="ThemeOverlay.AppCompat.Dark.ActionBar" />
<style name="AppTheme.PopupOverlay" parent="ThemeOverlay.AppCompat.Light" />

我的布局:

<?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=".activities.Login">
    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="match_parent"
        android:orientation="vertical"
        android:weightSum="2">
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
            <com.google.android.material.textfield.TextInputLayout
                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="30dp"
                android:layout_marginEnd="30dp"
                android:layout_marginBottom="15dp">
                <com.google.android.material.textfield.TextInputEditText
                    android:id="@+id/input_username"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/username"
                    android:inputType="text"
                    android:maxLength="30"
                    android:maxLines="1"
                    android:textSize="16sp" />
            </com.google.android.material.textfield.TextInputLayout>
            <com.google.android.material.textfield.TextInputLayout
                style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="30dp"
                android:layout_marginEnd="30dp"
                app:passwordToggleEnabled="true">
                <com.google.android.material.textfield.TextInputEditText
                    android:id="@+id/input_password"
                    android:layout_width="match_parent"
                    android:layout_height="wrap_content"
                    android:hint="@string/password"
                    android:inputType="textPassword"
                    android:maxLength="30"
                    android:maxLines="1"
                    android:textSize="16sp" />
            </com.google.android.material.textfield.TextInputLayout>
        </LinearLayout>
        <LinearLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_weight="1"
            android:gravity="center"
            android:orientation="vertical">
            <Button
                android:id="@+id/button_login"
                style="@style/Widget.AppCompat.Button.Borderless"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:layout_marginStart="30dp"
                android:layout_marginEnd="30dp"
                android:text="@string/login"
                android:textColor="#2B579A"
                android:textSize="15sp" />
        </LinearLayout>
    </LinearLayout>
</androidx.constraintlayout.widget.ConstraintLayout>

我可以通过使用 Theme.MaterialComponents.+++.+++ 更改父样式或在 AppTheme 部分中实现项目来解决,但这样做我改变了图形和颜色,我不想编辑它们再次。还有其他解决方案吗?

您不能将 AppCompat 主题与 MaterialComponents 视图一起使用。 com.google.android.material.textfield.TextInputLayoutTextInputEditText 是 Material 设计组件。他们俩不在一起。

这样做解决了:

在清单中我将主题设置为:

<activity
        android:name=".activities.Login"
        android:theme="@style/Theme.MaterialComponents.Light.NoActionBar.Bridge" />

在布局中,我将 TextInput 设置为:

<com.google.android.material.textfield.TextInputLayout
            style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox.Dense"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_marginStart="30dp"
            android:layout_marginEnd="30dp"
            android:layout_marginBottom="15dp"
            app:endIconMode="clear_text"
            app:boxStrokeColor="@color/colorPrimary"
            app:hintTextColor="@color/colorPrimary">

            <com.google.android.material.textfield.TextInputEditText
                android:id="@+id/input_username"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Username"
                android:inputType="text"
                android:maxLength="30"
                android:maxLines="1"
                android:textSize="16sp" />
</com.google.android.material.textfield.TextInputLayout>

添加以下属性:

app:boxStrokeColor="@color/colorPrimary"
app:hintTextColor="@color/colorPrimary">

此错误消息中描述了问题

Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.MaterialComponents (or a descendant).

使用 Material 小部件需要使用从 1.1.0 开始的 Theme.MaterialComponents 系列的主题。

Getting started with Material Components for Android 指南解释了该怎么做:

4. Change your app theme to inherit from a Material Components theme

Doing an app-wide migration by changing your app theme to inherit from a Material Components theme is the recommended approach. However, be sure to test thoroughly afterwards, as components in existing layouts may change their looks and behavior.

Note: If you can't change your theme, you can do one of the following:

  • Inherit from one of our Material Components Bridge themes. See the Bridge Themes section for more details.
  • Continue to inherit from an AppCompat theme and add some new theme attributes to your theme. See the App Compat Themes section for more details.

[...]

Bridge Themes

If you cannot change your theme to inherit from a Material Components theme, you can inherit from a Material Components Bridge theme.

<style name="Theme.MyApp" parent="Theme.MaterialComponents.Light.Bridge">
    <!-- ... -->
</style>

Both Theme.MaterialComponents and Theme.MaterialComponents.Light have .Bridge themes:

  • Theme.MaterialComponents.Bridge
  • Theme.MaterialComponents.Light.Bridge
  • Theme.MaterialComponents.NoActionBar.Bridge
  • Theme.MaterialComponents.Light.NoActionBar.Bridge
  • Theme.MaterialComponents.Light.DarkActionBar.Bridge

Bridge themes inherit from AppCompat themes, but also define the new Material Components theme attributes for you. If you use a bridge theme, you can start using Material Design components without changing your app theme.

AppCompat Themes

You can also incrementally test new Material components without changing your app theme. This allows you to keep your existing layouts looking and behaving the same, while introducing new components to your layout one at a time.

However, you must add the following new theme attributes to your existing app theme, or you will encounter ThemeEnforcement errors:

<style name="Theme.MyApp" parent="Theme.AppCompat">

  <!-- Original AppCompat attributes. -->
  <item name="colorPrimary">@color/my_app_primary_color</item>
  <item name="colorSecondary">@color/my_app_secondary_color</item>
  <item name="android:colorBackground">@color/my_app_background_color</item>
  <item name="colorError">@color/my_app_error_color</item>

  <!-- New MaterialComponents attributes. -->
  <item name="colorPrimaryVariant">@color/my_app_primary_variant_color</item>
  <item name="colorSecondaryVariant">@color/my_app_secondary_variant_color</item>
  <item name="colorSurface">@color/my_app_surface_color</item>
  <item name="colorOnPrimary">@color/my_app_color_on_primary</item>
  <item name="colorOnSecondary">@color/my_app_color_on_secondary</item>
  <item name="colorOnBackground">@color/my_app_color_on_background</item>
  <item name="colorOnError">@color/my_app_color_on_error</item>
  <item name="colorOnSurface">@color/my_app_color_on_surface</item>
  <item name="scrimBackground">@color/mtrl_scrim_color</item>
  <item name="textAppearanceHeadline1">@style/TextAppearance.MaterialComponents.Headline1</item>
  <item name="textAppearanceHeadline2">@style/TextAppearance.MaterialComponents.Headline2</item>
  <item name="textAppearanceHeadline3">@style/TextAppearance.MaterialComponents.Headline3</item>
  <item name="textAppearanceHeadline4">@style/TextAppearance.MaterialComponents.Headline4</item>
  <item name="textAppearanceHeadline5">@style/TextAppearance.MaterialComponents.Headline5</item>
  <item name="textAppearanceHeadline6">@style/TextAppearance.MaterialComponents.Headline6</item>
  <item name="textAppearanceSubtitle1">@style/TextAppearance.MaterialComponents.Subtitle1</item>
  <item name="textAppearanceSubtitle2">@style/TextAppearance.MaterialComponents.Subtitle2</item>
  <item name="textAppearanceBody1">@style/TextAppearance.MaterialComponents.Body1</item>
  <item name="textAppearanceBody2">@style/TextAppearance.MaterialComponents.Body2</item>
  <item name="textAppearanceCaption">@style/TextAppearance.MaterialComponents.Caption</item>
  <item name="textAppearanceButton">@style/TextAppearance.MaterialComponents.Button</item>
  <item name="textAppearanceOverline">@style/TextAppearance.MaterialComponents.Overline</item>

</style>

该指南包含一些 useful links at the end, among others Theming Guide