从App主继承AppCompat 22.1.1对话框colorAccent不起作用

mat*_*ash 16 android android-appcompat android-support-library android-styles

我正在尝试设置AppCompat的对话框,以便按钮使用与应用程序的强调颜色相同的颜色,而不重复颜色本身.通过在values-v21以下位置使用此样式文件,这与AppCompat v22(仅适用于Lollipop)完美配合:

<style name="AppTheme" parent="@style/Theme.AppCompat">
    <item name="colorAccent">#FF9800</item>
    <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
</style>

<style name="AlertDialogTheme" parent="android:Theme.Material.Dialog.Alert">
    <item name="android:colorAccent">?attr/colorAccent</item>
</style>
Run Code Online (Sandbox Code Playgroud)

AppCompat v22.1发布时,我试图为所有Android版本设置它,所以我将这些样式移动到基本values文件夹,并基本上用android:它们的AppCompat对应物替换了所有和v21特定的属性.

<style name="AppTheme" parent="Theme.AppCompat">
    <item name="colorAccent">#FF9800</item>
    <item name="alertDialogTheme">@style/AlertDialogTheme</item>
</style>

<style name="AlertDialogTheme" parent="Theme.AppCompat.Dialog.Alert">
    <item name="colorAccent">?attr/colorAccent</item>
</style>
Run Code Online (Sandbox Code Playgroud)

但是,它不起作用 - 应用程序在尝试显示警报对话框时崩溃.在logcat中有一些警告,我强烈怀疑它与问题有关:

05-08 16:55:44.863  W/ResourceType? Too many attribute references, stopped at: 0x7f01009e
Run Code Online (Sandbox Code Playgroud)

例外是:

05-08 16:55:44.900  21301-21301/com.example.test.testaccentcolor E/AndroidRuntime? FATAL EXCEPTION: main
    Process: com.example.test.testaccentcolor, PID: 21301
    android.view.InflateException: Binary XML file line #124: Error inflating class Button
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:763)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatDialog.setContentView(AppCompatDialog.java:75)
            at android.support.v7.app.AlertController.installContent(AlertController.java:216)
            at android.support.v7.app.AlertDialog.onCreate(AlertDialog.java:240)
            at android.app.Dialog.dispatchOnCreate(Dialog.java:373)
            at android.app.Dialog.show(Dialog.java:274)
            at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:902)
            at com.example.test.testaccentcolor.MainActivity.onOptionsItemSelected(MainActivity.java:37)
            at android.app.Activity.onMenuItemSelected(Activity.java:2885)
            at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:353)
            at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:144)
            at android.support.v7.internal.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:99)
            at android.support.v7.app.AppCompatDelegateImplV7.onMenuItemSelected(AppCompatDelegateImplV7.java:538)
            at android.support.v7.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:802)
            at android.support.v7.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:153)
            at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:949)
            at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:939)
            at android.support.v7.internal.view.menu.MenuPopupHelper.onItemClick(MenuPopupHelper.java:187)
            at android.widget.AdapterView.performItemClick(AdapterView.java:305)
            at android.widget.AbsListView.performItemClick(AbsListView.java:1146)
            at android.widget.AbsListView$PerformClick.run(AbsListView.java:3053)
            at android.widget.AbsListView$3.run(AbsListView.java:3860)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
     Caused by: java.lang.RuntimeException: Failed to resolve attribute at index 5
            at android.content.res.TypedArray.getColorStateList(TypedArray.java:425)
            at android.widget.TextView.<init>(TextView.java:991)
            at android.widget.Button.<init>(Button.java:111)
            at android.widget.Button.<init>(Button.java:107)
            at android.support.v7.widget.AppCompatButton.<init>(AppCompatButton.java:60)
            at android.support.v7.widget.AppCompatButton.<init>(AppCompatButton.java:56)
            at android.support.v7.internal.app.AppCompatViewInflater.createView(AppCompatViewInflater.java:97)
            at android.support.v7.app.AppCompatDelegateImplV7.createView(AppCompatDelegateImplV7.java:782)
            at android.support.v7.app.AppCompatDelegateImplV7.onCreateView(AppCompatDelegateImplV7.java:810)
            at android.support.v4.view.LayoutInflaterCompatHC$FactoryWrapperHC.onCreateView(LayoutInflaterCompatHC.java:44)
            at android.view.LayoutInflater.createViewFromTag(LayoutInflater.java:725)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:806)
            at android.view.LayoutInflater.rInflate(LayoutInflater.java:809)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:504)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:414)
            at android.view.LayoutInflater.inflate(LayoutInflater.java:365)
            at android.support.v7.app.AppCompatDelegateImplV7.setContentView(AppCompatDelegateImplV7.java:249)
            at android.support.v7.app.AppCompatDialog.setContentView(AppCompatDialog.java:75)
            at android.support.v7.app.AlertController.installContent(AlertController.java:216)
            at android.support.v7.app.AlertDialog.onCreate(AlertDialog.java:240)
            at android.app.Dialog.dispatchOnCreate(Dialog.java:373)
            at android.app.Dialog.show(Dialog.java:274)
            at android.support.v7.app.AlertDialog$Builder.show(AlertDialog.java:902)
            at com.example.test.testaccentcolor.MainActivity.onOptionsItemSelected(MainActivity.java:37)
            at android.app.Activity.onMenuItemSelected(Activity.java:2885)
            at android.support.v4.app.FragmentActivity.onMenuItemSelected(FragmentActivity.java:353)
            at android.support.v7.app.AppCompatActivity.onMenuItemSelected(AppCompatActivity.java:144)
            at android.support.v7.internal.view.WindowCallbackWrapper.onMenuItemSelected(WindowCallbackWrapper.java:99)
            at android.support.v7.app.AppCompatDelegateImplV7.onMenuItemSelected(AppCompatDelegateImplV7.java:538)
            at android.support.v7.internal.view.menu.MenuBuilder.dispatchMenuItemSelected(MenuBuilder.java:802)
            at android.support.v7.internal.view.menu.MenuItemImpl.invoke(MenuItemImpl.java:153)
            at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:949)
            at android.support.v7.internal.view.menu.MenuBuilder.performItemAction(MenuBuilder.java:939)
            at android.support.v7.internal.view.menu.MenuPopupHelper.onItemClick(MenuPopupHelper.java:187)
            at android.widget.AdapterView.performItemClick(AdapterView.java:305)
            at android.widget.AbsListView.performItemClick(AbsListView.java:1146)
            at android.widget.AbsListView$PerformClick.run(AbsListView.java:3053)
            at android.widget.AbsListView$3.run(AbsListView.java:3860)
            at android.os.Handler.handleCallback(Handler.java:739)
            at android.os.Handler.dispatchMessage(Handler.java:95)
            at android.os.Looper.loop(Looper.java:135)
            at android.app.ActivityThread.main(ActivityThread.java:5254)
            at java.lang.reflect.Method.invoke(Native Method)
            at java.lang.reflect.Method.invoke(Method.java:372)
            at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:903)
            at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:698)
Run Code Online (Sandbox Code Playgroud)

当然,复制颜色值(或创建颜色资源并引用它)是有效的......但由于项目结构,我需要这样做.

总结一下:我假设引用?attr/colorAccent是以某种方式创建一个循环...但我无法弄清楚为什么或如何解决它.

有任何想法吗?


更新:为什么我需要/只想accentColor在主题中设置?

我们有一个许多应用程序共有的库,它定义了必须从中派生实际应用程序主题的"基本"主题.所以上面简化的例子实际上更类似于这样的事情:

<!-- Styles that are inherited by application-generated styles. -->
<style name="Theme.Library.Dark" parent="@style/Theme.AppCompat">
    <item name="alertDialogTheme">@style/Theme.Library.Dark.AlertDialog</item>
    <!-- more properties -->
</style>

<style name="Theme.Library.Dark.AlertDialog" parent="@style/Theme.AppCompat.Dialog.Alert">
    <item name="colorAccent">?attr/colorAccent</item>
    <!-- more properties -->
</style>
Run Code Online (Sandbox Code Playgroud)

(加上Light and Light with Dark Action Bar的相应变体).

在此之后,应用程序项目应该只从提供的列表中选择一个基本主题,然后具有如下内容:

<!-- Application theme -->
<style name="ApplicationTheme" parent="Theme.Library.Dark">
    <-- Ohter material colors -->
    <item name="colorAccent">#FF9800</item>
</style>
Run Code Online (Sandbox Code Playgroud)

至少这是理想的情况,之前有效(正如@Vikram在他的回答中指出的那样,显然只是因为有两个不同的colorAccent属性).

这种方案的优点是我不必colorAccent在库主题中提供默认值,因为它们是从AppCompat基础继承的.

此外,如果我需要创建颜色资源,我需要其中两个(对于浅色和深色变体),因为默认颜色不同.

所以,理想情况下,我正在寻找类似的解决方案(前提是存在).

Vik*_*ram 14

<item name="colorAccent">?attr/colorAccent</item>
Run Code Online (Sandbox Code Playgroud)

你已经知道这不起作用.原因如下:

ssize_t ResTable::Theme::getAttribute(uint32_t resID, Res_value* outValue,
    uint32_t* outTypeSpecFlags) const 
{
    int cnt = 20;

    if (outTypeSpecFlags != NULL) *outTypeSpecFlags = 0;

    do {
        ....
        ....        
        if (type == Res_value::TYPE_ATTRIBUTE) {
            if (cnt > 0) {
                cnt--;
                resID = te.value.data;
                continue;
            }
            ALOGW("Too many attribute references, stopped at: 0x%08x\n", resID);
            return BAD_INDEX;
        } 
        ....
        ....
    } while (true);

    return BAD_INDEX;
}
Run Code Online (Sandbox Code Playgroud)

该片段不言自明.你可以有:

<item name="colorZ" >?attr/colorY</item> 
Run Code Online (Sandbox Code Playgroud)

然后:

<item name="colorY" >?attr/colorX</item> 
Run Code Online (Sandbox Code Playgroud)

.... ....

但是像这样的链接属性不能超过20级.Android因为而放弃了Too many attribute references....

在您的情况下,您通过尝试读取其当前值来设置属性的值.Android看起来,但找到另一个参考 - 无尽的追求.

为什么之前有效?

<style name="AppTheme" parent="@style/Theme.AppCompat">
    <item name="colorAccent">#FF9800</item>
    <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
</style>

<style name="AlertDialogTheme" parent="android:Theme.Material.Dialog.Alert">
    <item name="android:colorAccent">?attr/colorAccent</item>
</style>
Run Code Online (Sandbox Code Playgroud)

AppTheme,您正在设置支持库的colorAccent属性(没有android:名称空间).在AlertDialogTheme,你设置android:colorAccent支持库colorAccent.这就是无限循环不成形的原因.

?attr/colorAccentContext在创建时通过解析AlertDialog.出于这个原因,它被解决了<item name="colorAccent">#FF9800</item>.

一个可能的解决方法是定义一个自定义attrres/values/attrs.xml:

<attr name="alertDialogColorAccent" format="reference|color"/>
Run Code Online (Sandbox Code Playgroud)

现在,我们可以在AppTheme以下位置初始化此属性:

<style name="AppTheme" parent="@style/Theme.AppCompat">
    <item name="colorAccent">#FF9800</item>
    <item name="alertDialogColorAccent" >?attr/colorAccent</item>
    <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
</style>
Run Code Online (Sandbox Code Playgroud)

并用于AlertDialogTheme:

<style name="AlertDialogTheme" parent="android:Theme.Material.Dialog.Alert">
    <item name="colorAccent">?attr/alertDialogColorAccent</item>
</style>
Run Code Online (Sandbox Code Playgroud)

但是,这仍然无效.它仍然创建了一个循环- colorAccentalertDialogColorAccent- alertDialogColorAccentcolorAccent.沿链的某处,需要设置实际颜色值:

<style name="AppTheme" parent="@style/Theme.AppCompat">
    <item name="colorAccent">#FF9800</item>
    <item name="alertDialogColorAccent" >#FF9800</item>
    <item name="android:alertDialogTheme">@style/AlertDialogTheme</item>
</style>
Run Code Online (Sandbox Code Playgroud)

现在,您可以初始化colorAccent,alertDialogColorAccent因为它引用了实际的颜色值:

<style name="AlertDialogTheme" parent="android:Theme.Material.Dialog.Alert">
    <item name="colorAccent">?attr/alertDialogColorAccent</item>
</style>
Run Code Online (Sandbox Code Playgroud)