如何使用support.v7.preference与AppCompat和潜在的缺点

时间:2016-01-25 01:49:47

标签: android android-appcompat android-preferences preferencescreen preference-v7

我正在尝试使用support.v7.preference实现AppCompat应用的首选项。我花了几天时间来完成它,因为support.v7.preference与原生偏好有一些显着差异......一旦你知道,这并不是太糟糕,但遗憾的是那里的文档很少。我以为我会分享我的发现,所以其他人不必经历同样的痛苦。

所以......问题:

如何最好地实现AppCompat应用程序的首选项(PreferenceFragment和AppCompatAcitivity不兼容)?

以下是几个相关问题:

官方文件:

2 个答案:

答案 0 :(得分:52)

解决方案1:具有PreferenceFragment

的原生AppCompatActivity

在AndroidStudio中,选择文件>新项目> ...> SettingsActivity 。此模板使用一种变通方法来改进原生PreferenceFragment以使用AppCompatActivity,类似于support.v4.Fragmentsupport.v7.PreferenceFragmentCompat

  • Pro:您现在可以在其中使用本机首选项功能 AppCompat个应用使用AS模板时,这是一种快速的方法,您可以坚持使用现有的首选项文档和工作流程。
  • Con:改装不是很直观或干净。此外,由于通常建议在可用的情况下使用支持库,我不确定这种方法的前瞻性。

解决方案2:support.v7.preference.PreferenceFragmentCompat AppCompatActivity

  • Pro:最大化兼容性
  • Con:要弥合很多差距。此外,这可能不适用于任何现有的preference-extensions-libs(例如。ColorPickerFontPreferences)。

如果您选择不使用解决方案1(我仍然不确定这两者中哪一个更具未来性),使用support.v7.preference时会有一些缺点。

使用解决方案2的重要缺点如下所述。

<强>依赖关系:

dependencies {
    ...
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:preference-v7:23.1.1'
    compile 'com.android.support:support-v4:23.1.1'
}

<强>主题: 您需要在styles.xml中定义 preferenceTheme ,否则运行您的应用会引发异常。

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
    <!-- Customize your theme here. -->
    <item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>

你可能想把它分成7 + / 14 + / 21 +的不同风格。在写这篇文章时,很多人都抱怨这是一辆马车。有一个非常全面的答案here

行为更改:使用原生首选项非常简单:您需要做的就是定义/维护preferences.xml并在addPreferencesFromResource(R.xml.preferences)中使用PreferenceFragment }。通过对DialogPreference进行子分类,然后仅在preferences.xml ... bam中引用,可以轻松完成自定义首选项。

不幸的是,support.v7.preference已将所有与处理Fragment相关的内容删除,使其失去了许多内置功能。你现在不得不维护一个XML,而是必须对很多东西进行子类化和覆盖,不幸的是,所有这些东西都没有记录。

PreferenceScreens: PreferenceScreens不再受框架管理。在PreferenceScreen中定义preference.xml(如docs中所述)将显示该条目,但点击它不会执行任何操作。现在由您决定显示和导航子屏幕。无聊。

有一种方法(描述为here),向PreferenceFragmentCompat.OnPreferenceStartScreenCallback添加了PreferenceFragmentCompat。虽然这种方法很快就实现了,但它只是交换了现有首选项片段的内容。缺点是:没有后退导航,你总是“在顶部”,这对用户来说不是很直观。

在另一种方法(描述为here)中,您还必须管理后台堆栈,以实现预期的后向导航。这使用preferenceScreen.getKey()作为每个新创建/显示的片段的根。

执行此操作时,您可能还会默认偶然发现PreferenceFragments透明,并且奇怪地相互叠加。人们倾向于覆盖PreferenceFragmentCompat.onViewCreated()以添加类似

的内容
// Set the default white background in the view so as to avoid transparency
view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.background_material_light));

自定义DialogPreference:制作自己的偏好也从琐碎到无聊。 DialogPreference现在有任何处理实际对话框的内容已删除。那一点现在住在PreferenceDialogFragmentCompat。因此,您必须对两者进行子类化,然后处理创建对话框并自行显示(解释here)。

查看PreferenceFragmentCompat.onDisplayPreferenceDialog()的来源,表明它知道如何处理2个对话框首选项(EditTextPreferenceListPreference),您需要使用{自己实现的所有其他内容{1}} ...有人想知道,为什么没有功能来处理OnPreferenceDisplayDialogCallback的子类!

以下是一些实现大多数解决方法的代码,并将它们放在lib模块中:

https://github.com/mstummer/extended-preferences-compat.git

主要意图是:

  • 无需在每个应用/项目中扩展和摆弄DialogPreferenceActivityPreferenceFragment现在再次成为唯一需要更改/维护的每个项目文件。
  • 按预期处理并显示preference.xml(子屏幕)。
  • 取消拆分PreferenceScreens以恢复原生行为。
  • 处理并显示DialogPreference
  • 的任何子类

不要认为它足够干净,只需开箱即用,但在处理类似问题时可能会给你一些提示。如果您有任何建议,请告诉我。

答案 1 :(得分:0)

我有一个替代解决方案,我喜欢反馈。

我为我的偏好片段制作了自定义布局,左上角有一个“后退”按钮。

首先,在“onCreatePreference”中我存储了根PreferenceScreen:

root = this.getPreferenceScreen();

然后,我如上所述添加OnPreferenceStartScreenCallback,并在其他线程中使片段转到子屏幕,但在我的“onPreferenceStartScreen”中,我还将后退按钮设置为可见,如下所示:

    public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) {
        preferenceFragmentCompat.setPreferenceScreen(preferenceScreen);
        backButton.setVisibility(View.VISIBLE);
        return true;
}

最后,backButton clickhandler:

    setPreferenceScreen(root);
    back.setVisibility(View.GONE);

这对我来说似乎很好。显然后面的堆栈不起作用,但我可以忍受,因为有一个后退按钮。

不完美,但考虑到糟糕的API,我觉得我很高兴。

如果有人认为这种做法存在任何问题,我很乐意听到。