将AppCompat主题应用于PreferenceFragment中的个人偏好设置

18

我一直在尝试让我的PreferenceFragment与应用程序的其他部分使用相同的基于Material且通过AppCompat实现的主题和样式。下面是我用来管理所有应用设置的PreferenceFragment

enter image description here

从上面的截图可以看出,我能够通过使用colorAccentcolorPrimary和其他一些属性来自定义PreferenceFragment。 我的PreferenceFragment主题如下:

<style
    name="settingsTheme"
    parent="Theme.AppCompat.Light.DarkActionBar">
    <item name="colorPrimary">@color/blue_grey_500</item>
    <item name="colorAccent">@color/blue_grey_500</item>
    <item name="android:textColor">@color/black_text_alt</item>
    <item name="android:textColorSecondary">@color/black_secondary_text</item>
</style>

然而,尽管我尽力了,我仍然无法将主题应用于PreferenceFragment中的各个元素(例如ListPreferenceEditTextPreference),所有首选项仍然保留标准的AppCompat主题:

图片描述

我找到了一篇两年前的帖子讨论了这个问题,但没有真正的解决方案:如何将主题应用于<PreferenceCategory><PreferenceScreen>元素

我想知道自从发布了AppComat V21以来,是否有人成功地将主题应用于偏好设置。如果没有,是否有任何可行的解决方法可用于将自定义主题应用于单个首选项?

4个回答

9

更新:我制作了一个库来解决这个问题(使用了AppCompat r22):https://github.com/consp1racy/android-support-preference


ListPreference扩展了DialogPreference,后者使用以下代码创建对话框:

mBuilder = new AlertDialog.Builder(context)
    .setTitle(mDialogTitle)
    .setIcon(mDialogIcon)
    .setPositiveButton(mPositiveButtonText, this)
    .setNegativeButton(mNegativeButtonText, this);

正如您所看到的,AlertDialog.Builder 构造函数没有提供第二个可选的 int theme 参数。这意味着对话框的主题将受到您的活动主题在其 android:alertDialogTheme 属性中设置的影响。

现在,您需要创建一个从 Theme.AppCompat.Dialog 派生的自定义主题用于您的对话框,如下所示:

<style name="Theme.YourApp.Dialog.Alert" parent="Theme.AppCompat.Light.Dialog">
  <item name="android:windowBackground">@android:color/transparent</item>
  <item name="android:windowContentOverlay">@null</item>
  <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
  <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
  <item name="colorAccent">@color/accent_yourapp</item>
  <item name="colorPrimary">@color/primary_yourapp</item>
  <item name="colorPrimaryDark">@color/primary_dark_yourapp</item>
</style>

问题1:上述解决方案对于RingtonePreference无效,因为它没有扩展ListPreference,而是调用了铃声选择器意图,因此它始终根据系统主题进行。查看这个答案:RingtonePreference Theme。所以我们可以将其标记为已解决。

问题2:AppCompat对话框缺少标题。到目前为止,我还没有找到解决方法。确实,我没有努力寻找。让我们把标题缺失视为一个小问题。

问题3:单选按钮可绘制对象未被改变,因此图形在被动和活动(有颜色)状态之间不一致 - 所有都是彩色的(不仅仅是你按下的那一个),或者全部都是灰色的。现在这真的很烦人。

问题2和3迫使我采取另一种方法 - 我的对话框主题在API 14+上看起来像这样

<style name="Theme.MyApp.Dialog.Alert" parent="android:Theme.DeviceDefault.Light.Dialog.MinWidth">
  <item name="android:windowBackground">@android:color/transparent</item>
  <item name="android:windowContentOverlay">@null</item>
</style>

并且在API 21+上也是这样的

<style name="Theme.YourApp.Dialog.Alert" parent="android:Theme.DeviceDefault.Light.Dialog.MinWidth">
  <item name="android:colorPrimary">@color/primary_yourapp</item>
  <item name="android:colorPrimaryDark">@color/primary_dark_yourapp</item>
  <item name="android:colorAccent">@color/accent_yourapp</item>
</style>

这些数值是通过对平台源文件进行爬取并经过充分测试获得的实验数据。

关键在于唯一可靠的解决方案似乎是使用设备默认的对话框主题。在Lollipop之前,唯一的选择是浅色或深色变体。在Lollipop上,这将按照预期和要求工作。

编辑:自从appcompat-v7-r21.1.0以后,您可以使用AppCompatDialog,它是原生AlertDialog的材料主题变体。

您可以使用提供的AlertDialog.Builder(不要与其本地对应项混淆)来创建其实例。


谢谢。这正是我所需要的。 - Willis
在AppCompat v22.1上,您可以使用android.support.v7.app.AlertDialog。 - Joaquin Iurchuk
2
是的,希望我6个月前有那个 :D - Eugen Pechanec
1
不改变事实的是,普通的 AlertDialog 被硬编码到了 ListPreference 中,因此我预计会出现一些问题。 - Eugen Pechanec

3

DialogPreference 直接使用 android.app.AlertDialog.Builder,所以无法将显示的对话框切换到适用于所有 API 级别的 Material Design 对话框(需要使用 android.support.v7.widget.AlertDialog.Builder)。

我认为现在唯一的选择是扩展和覆盖 DialogPreference 或其子类中的对话框创建逻辑(如果需要,可以使用反射来解决私有访问器)。可以查看这个Reddit帖子和示例AppCompatListPreference,它由该帖子的作者制作。


2

参考已给出的答案,我在清单文件中为设置活动设置了自定义主题,因为需要删除出现的对话框周围的边框背景,仅针对API<21使用透明背景:

AndroidManifest.xml

<application
    android:name=".MyApplication"
    ...
    android:theme="@style/AppTheme">
    ...
    <activity
        android:name=".ui.SettingsActivity"
        ...
        android:theme="@style/AppTheme.Settings">
    </activity>
</application>

values/style.xml

<!-- Application theme -->
<style name="AppTheme" parent="AppTheme.Base">
    <!-- All customizations that are NOT specific to a particular API-level can go here. -->

</style>

<style name="AppTheme.Base" parent="Theme.AppCompat.Light.NoActionBar">
    ...
    <item name="android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>

<!-- Must be different because of transparent background -->
<style name="AppTheme.Settings" parent="AppTheme.Base">
    <item name="android:alertDialogTheme">@style/AppTheme.SettingsAlertDialog</item>
</style>

<style name="AppTheme.AlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
    <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="colorAccent">@color/accent_light</item>
    <item name="colorControlActivated">@color/accent_light</item>
    <item name="colorControlHighlight">@color/primary_highlight</item>
</style>

<style name="AppTheme.SettingsAlertDialog" parent="Theme.AppCompat.Light.Dialog.Alert">
    <item name="android:windowMinWidthMajor">@android:dimen/dialog_min_width_major</item>
    <item name="android:windowMinWidthMinor">@android:dimen/dialog_min_width_minor</item>
    <item name="android:windowBackground">@android:color/transparent</item>
    <item name="android:windowContentOverlay">@null</item>
    <item name="colorAccent">@color/accent_light</item>
    <item name="colorControlActivated">@color/accent_light</item>
    <item name="colorControlHighlight">@color/primary_highlight</item>
</style>

最后针对values-v21/style.xml文件,如果您不在v21中放置此文件,则会使普通对话框变得透明。

<style name="AppTheme.Settings" parent="AppTheme.Base">
    <item name="android:alertDialogTheme">@style/AppTheme.AlertDialog</item>
</style>

实际上,我有一个问题是如何直接从主题属性中设置颜色:使用?android:colorAccent而不是我的固定颜色@color/accent_light。


1
你应该查看this Gist,了解不同组件如何使用主题颜色属性。你可能需要将以下属性添加到你的主题中以获得所需的效果:
<item name="colorControlNormal">@color/x_color</item>
<item name="colorControlActivated">@color/y_color</item>
<item name="colorControlHighlight">@color/z_color</item>

这是很好知道的。不幸的是,这些属性似乎不影响各种偏好设置(EditTextPreferenceListPreference等),只影响根PreferenceScreen - Willis

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接