Я пытаюсь настроить диалоговые окна AppCompat, чтобы кнопки использовали тот же цвет, что и цвет акцента приложения, без повторения самого цвета. Это отлично работает с AppCompat v22 (только для Lollipop, очевидно), используя этот файл стилей в values-v21
:
<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>
Когда был выпущен AppCompat v22.1, я попытался установить это для всех версий Android, поэтому я переместил эти стили в базовую папку values
и в основном заменил все атрибуты android:
и v21 их сопоставлениями AppCompat.
<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>
Однако это не сработает - приложение аварийно завершает работу, когда пытается показать диалог предупреждения. В logcat есть некоторые предупреждения, которые, как я подозреваю, связаны с проблемой:
05-08 16:55:44.863 W/ResourceType﹕ Too many attribute references, stopped at: 0x7f01009e
И исключение:
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)
Конечно, дублирование значения цвета (или создание ресурса цвета и ссылки на него) работает... но из-за структуры проекта мне это нужно.
Подводя итог: Я предполагаю, что ссылка на ?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>
(плюс соответствующие варианты для Light and Light с Dark Bar).
После этого проект приложения должен выбрать только базовую тему из предоставленного списка, а затем иметь что-то вроде:
<!-- Application theme -->
<style name="ApplicationTheme" parent="Theme.Library.Dark">
<-- Ohter material colors -->
<item name="colorAccent">#FF9800</item>
</style>
По крайней мере, это идеальная ситуация, которая работала до этого (как указывает @Vikram в своем ответе, по-видимому, только потому, что есть два разных атрибута colorAccent
).
Преимущество этой схемы заключается в том, что я не вынужден предоставлять значения по умолчанию для colorAccent
в темах библиотеки, поскольку они наследуются от базовых модулей AppCompat.
Кроме того, если мне нужно создать цветовые ресурсы, мне понадобится два из них (для вариантов с подсветкой и темным), поскольку цвета по умолчанию не совпадают.
Итак, в идеале, я ищу аналогичное решение (при условии, что оно существует).