从App主inheritanceAppCompat 22.1.1对话框colorAccent不起作用

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

  #FF9800 @style/AlertDialogTheme   ?attr/colorAccent  

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

  #FF9800 @style/AlertDialogTheme   ?attr/colorAccent  

但是,它不起作用 – 应用程序在尝试显示警报对话框时崩溃 。 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.(TextView.java:991) at android.widget.Button.(Button.java:111) at android.widget.Button.(Button.java:107) at android.support.v7.widget.AppCompatButton.(AppCompatButton.java:60) at android.support.v7.widget.AppCompatButton.(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

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

   @style/Theme.Library.Dark.AlertDialog    ?attr/colorAccent   

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

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

    #FF9800  

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

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

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

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

 ?attr/colorAccent 

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

 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; } 

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

 ?attr/colorY 

接着:

 ?attr/colorX 

…. ….

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

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

为什么之前有效呢?

   

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

?attr/colorAccent在创建AlertDialog时传递的ContextAlertDialog 。 出于这个原因,它是针对#FF9800

一种可能的解决方法是在res/values/attrs.xml定义自定义attr

  

现在,我们可以在AppTheme下初始化这个属性:

  

并在AlertDialogTheme使用它:

  

但是,这仍然无效。 它仍然会创建一个循环 – colorAccentalertDialogColorAccentalertDialogColorAccentcolorAccent 。 沿链的某处,需要设置实际颜色值:

  

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

  

基于@Vikram的优秀答案,我最终得到了这个(我将其用于将来参考,以防有人对实际解决方案感兴趣)。

对于基本样式文件,在values注意:属性,颜色和c的不同XML文件是优选的 – 它们在这里一起用于紧凑 ):

     #FF9800     

新的dialogColorAccent属性是必需的,以便可以从对话框样式中引用它。 不幸的是,它不能引用colorAccent本身(并且两者都不可能相反),因此两者必须具有相同的值(在这种情况下,是对颜色资源的引用)。

这可以确保使用android.support.v7.app.AlertDialog.Builder构建的AlertDialog使用所有Android版本的正/负按钮的强调颜色。

但是,对于某些对话框(例如DatePickerDialogTimePickerDialogProgressDialog ),需要一个额外的文件,这些对话框在Lollipop中具有材质版本,但到目前为止还没有AppCompat等效。 因此,以下样式文件的values-v21

     

这将使这些新的对话框也具有强调色(但显然只在Lollipop中)。


该解决方案可能看起来有点复杂(从AlertDialogTheme样式引用@myAccentColor更简单:) :)但这是必要的,因为在库中定义了多个主题,并且想法是这些主题可以inheritance并使用最少的更改。

我相信?attr/colorAccent在这里指的是你想要设置的那个:

 ?attr/colorAccent 

您可以将重音颜色提取到@color属性,然后将其用于应用主题和对话框主题。

colors.xml

 #FF9800 

styles.xml

   

我在对话框主题中将android:textColor设置为@null ,这有帮助。

styles.xml

  

这个trick帮我修复了其他按钮的android:textColor问题。

  

some_layout.xml

  

现在按钮文本颜色是在colorAccent定义的AppTheme