通过overlay切换多主题遇到layout里这个组件inflate异常 <com.google.android.material.appbar.AppBarLayout
Caused by: java.lang.IllegalArgumentException: The style on this component requires your app theme to be Theme.AppCompat (or a descendant).
做了几次尝试:
1.将activity主题换为Theme.AppCompat // 失败
2.将application主题也换位Theme.AppCompat // 失败
3.将<com.google.android.material.appbar.AppBarLayout去掉 // OK,但功能需要不能去掉
4.研究源码,找到异常点
com.google.android.material.internal.ThemeEnforcement#checkAppCompatTheme
public static void checkAppCompatTheme(@NonNull Context context) { checkTheme(context, APPCOMPAT_CHECK_ATTRS, APPCOMPAT_THEME_NAME); }
这个组件会检测主题,通过代码看到
private static final int[] APPCOMPAT_CHECK_ATTRS = {R.attr.colorPrimary};
也就是要检测主题colorPrimary属性
private static void checkTheme( @NonNull Context context, @NonNull int[] themeAttributes, String themeName) { if (!isTheme(context, themeAttributes)) { throw new IllegalArgumentException( "The style on this component requires your app theme to be " + themeName + " (or a descendant)."); } }
这里可以看到异常信息,关键点在于com.google.android.material.internal.ThemeEnforcement#isTheme
private static boolean isTheme(@NonNull Context context, @NonNull int[] themeAttributes) { TypedArray a = context.obtainStyledAttributes(themeAttributes); for (int i = 0; i < themeAttributes.length; i++) { if (!a.hasValue(i)) { a.recycle(); return false; } } a.recycle(); return true; }
从方法名可以看出是判断是否主题,这里有点不是太明白为啥是这个名字,不过无关紧要,这个方法就是检测传进来的主题属性是否在当前主题里都存在,如果有一个不存在则认为不是主题,从上面可以看出其实就是检测R.attr.colorPrimary属性是否存在,不存在就让你异常,所以解决办法自然有了,那就是在主题里添加这个属性,不过一般加三个,单独加colorPrimary也可以解决问题
<item name="colorAccent">@color/color_cursor</item> <item name="colorPrimaryDark">@color/primary_dark_material_dark</item> <item name="colorPrimary">@color/primary_material_dark</item>