【问题标题】:Applying AppCompat theme to individual preferences in a PreferenceFragment将 AppCompat 主题应用于 PreferenceFragment 中的个人首选项
【发布时间】:2015-01-30 17:27:31
【问题描述】:

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

从上面的屏幕截图中可以看出,我可以通过使用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 主题:

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

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

【问题讨论】:

    标签: java android android-theme


    【解决方案1】:

    更新:我创建了一个库来解决这个问题(使用 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: 单选按钮 drawable 没有发生变化,因此图形在被动和主动(彩色)状态之间不一致 - 全部都是彩色的(不仅仅是你正在按下的那个)或者全部都是彩色的灰色的。现在这真的很烦人

    问题 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(不要与它的本地对应物混淆)来创建它的实例。

    【讨论】:

    • 谢谢。这正是我所需要的。
    • 在 AppCompat v22.1 上,您可以使用 android.support.v7.app.AlertDialog
    • 是的,希望我在 6 个月前拥有它:D
    • 不会改变普通的AlertDialog 硬连线到ListPreference 的事实,所以我预计会出现一些问题。
    【解决方案2】:

    DialogPreference 直接使用android.app.AlertDialog.Builder,因此对于所有 API 级别(需要使用 android.support.v7.widget.AlertDialog.Builder),不可能将显示的对话框切换到材料设计之一。

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

    【讨论】:

      【解决方案3】:

      从已经给出的答案中获取线索,我在清单中为设置活动设置了一个自定义主题,因为有必要删除出现的对话框周围的边框背景,使用仅用于 API

      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。

      【讨论】:

        【解决方案4】:

        您应该查看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
        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2016-10-01
        • 2014-10-17
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多