将AppCompat主题应用于PreferenceFragment中的个人首选项

时间:2015-01-30 17:27:31

标签: java android android-theme

我一直在努力让我的PreferenceFragment拥有与我的应用程序其余部分相同的基于材质的主题和样式(通过AppCompat)。我用来管理所有应用程序设置的PreferenceFragment如下所示:

enter image description here

从上面的屏幕截图中可以看出,我可以使用PreferenceFragmentcolorAccent和其他一些属性来自定义colorPrimary。我对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主题:

enter image description here

我发现一篇2年前的帖子讨论了这个问题,虽然没有真正的解决方案:How to apply theme to <PreferenceScreen> elements of a <PreferenceCategory>

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

4 个答案:

答案 0 :(得分: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:单选按钮drawables没有变异,因此图形在被动和主动(彩色)状态之间不一致 - 所有颜色都是彩色的(不仅仅是你按下的那个)或者所有都是灰色。现在这真的很烦人

问题2&amp; 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>

通过浏览平台的源文件并经过充分测试,实验性地获得了这些值。

重点是唯一可靠的解决方案似乎是使用设备默认对话框主题。棒棒糖之前唯一的选择是浅色或深色。在棒棒糖上,这将按照预期和要求运作。

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

您可以使用提供的AlertDialog.Builder(不要与其原生版本混淆)来创建其实例。

答案 1 :(得分:3)

DialogPreference直接使用android.app.AlertDialog.Builder,因此无法将显示的对话框切换到所有API级别的材质设计(需要使用android.support.v7.widget.AlertDialog.Builder)。

我认为现在唯一的选择是在DialogPreference或其子类中扩展和覆盖对话框创建逻辑(如果需要,使用反射来解决私有访问器)。查看此reddit thread以及该主题作者提供的示例AppCompatListPreference

答案 2 :(得分:2)

从已经给出的答案中获取提示我在清单中为设置活动设置了一个自定义主题,因为有必要删除出现的对话框周围的边框背景,使用透明背景,这仅适用于API&lt; 21:

的AndroidManifest.xml

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

值/ 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>

实际上我有问题直接从Theme属性设置颜色:?android:colorAccent而不是我的固定颜色@ color / accent_light。

答案 3 :(得分:1)

您应该查看this Gist有关不同组件如何使用主题颜色属性的信息。您可能需要将以下属性添加到主题中以获得所需的效果:

<item name="colorControlNormal">@color/x_color</item>
<item name="colorControlActivated">@color/y_color</item>
<item name="colorControlHighlight">@color/z_color</item>