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



我试图使用 support.v7.preference 实现 AppCompat 应用程序的首选项。我花了几天时间才摆弄它,因为 support.v7.ppreferred 与本机首选项有一些显着差异......一旦你知道,这还不错,但不幸的是,那里的文档很少。我想我会分享我的发现,这样其他人就不必经历同样的痛苦。


所以......问题:

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

以下是几个相关问题:

  • 使用support时首选项子屏幕未打开.v7.p首选项
  • 如何在首选项片段
  • 兼容中从首选项子屏幕移动到主屏幕?
  • 首选项
  • 片段兼容需要设置首选项主题
  • 如何使用 android.support.v7.preference 库创建自定义首选项?

官方文档在这里:

  • http://developer.android.com/guide/topics/ui/settings.html
  • http://developer.android.com/reference/android/support/v7/preference/Preference.html

解决方案 1:具有AppCompatActivity的本机PreferenceFragment

在 AndroidStudio 中,选择"文件>新建项目>...">"设置活动"。此模板使用一种解决方法,该解决方法将本机PreferenceFragment转换为与AppCompatActivity一起使用,类似于support.v4.Fragmentsupport.v7.PreferenceFragmentCompat

  • 优点:您现在可以在 AppCompat应用程序。这是使用 AS 模板时的快速方法,您可以坚持使用现有的首选项文档和工作流程。
  • 缺点:改造不是很直观或干净。另外,由于通常建议在可用的情况下使用支持库,因此我不确定这种方法是否适合未来。

解决方案 2:使用 AppCompatActivity 进行support.v7.preference.PreferenceFragmentCompat

  • 优点:最大化兼容性
  • 缺点:有很多差距需要弥合。此外,这可能不适用于任何现有的首选项扩展库(例如。 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'
}

主题:您需要在样式中定义preferenceTheme.xml,否则运行应用将引发异常。

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

您可能希望将其拆分为 7+/14+/21+ 的不同样式。在撰写本文时,很多人抱怨这是有缺陷的。这里有一个非常全面的答案。

行为改变:使用本机首选项非常简单:您需要做的就是定义/维护您的preferences.xml并在您的PreferenceFragment中使用addPreferencesFromResource(R.xml.preferences)。自定义首选项可以通过子类化DialogPreference轻松完成,然后只需在preferences.xml中引用...砰,工作。

不幸的是,support.v7.preference已经剥离了与处理Fragment相关的所有内容,使其失去了许多内置功能。您现在不仅要维护XML,还必须子类化并覆盖很多东西,不幸的是,所有这些东西都没有文档。

首选项屏幕:PreferenceScreens不再由框架管理。在preference.xml中定义PreferenceScreen(如文档中所述)将显示该条目,但单击它不会执行任何操作。现在由您来处理显示和导航子屏幕。无聊的。

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

在另一种方法(如此处所述)中,您还必须管理后退堆栈,以便按预期实现后退导航。这使用 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现在删除了处理实际对话框的任何内容。那一点现在住在PreferenceDialogFragmentCompat.因此,您必须对两者进行子类化,然后处理创建对话框并自己显示它(在此处解释)。

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


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

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

主要意图是:

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

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

我有一个替代解决方案,我希望得到反馈。

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

首先,在"onCreatePpreferences"中,我存储了根PpreferencesScreen:

root = this.getPreferenceScreen();

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

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

最后,后退按钮点击处理程序:

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

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

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

我很想听听是否有人认为这种方法有任何问题。

最新更新