如何将support.v7.preference与AppCompat一起使用以及潜在的缺点 [英] HowTo use support.v7.preference with AppCompat and potential drawbacks

查看:145
本文介绍了如何将support.v7.preference与AppCompat一起使用以及潜在的缺点的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图使用support.v7.preference来实现AppCompat应用程序的首选项.我花了几天的时间来弄弄它,因为support.v7.preference与本机首选项有一些显着的区别……一旦知道,这还不错,但是不幸的是,那里几乎没有文档.我以为我会分享我的发现,这样其他人就不必经历同样的痛苦.


所以...问题:

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

以下是两个相关的问题:

此处的官方文档:

解决方案

解决方案1:本机PreferenceFragmentAppCompatActivity

在AndroidStudio中,选择文件>新建项目> ...> SettingsActivity .该模板使用一种变通办法,可对本机PreferenceFragment进行改进以使其与AppCompatActivity一起使用,类似于support.v4.Fragmentsupport.v7.PreferenceFragmentCompat.

  • 专业版:您现在可以在 AppCompat应用.使用AS模板时,这是一种快速的方法,您可以坚持使用现有的首选项"文档和工作流程.
  • 缺点:改装不是很直观或干净.另外,由于通常建议在可用的情况下使用支持库,因此我不确定这种方法的适用性如何.

解决方案2:support.v7.preference.PreferenceFragmentCompatAppCompatActivity

  • 专业版:最大限度地提高兼容性
  • 缺点:很多差距可以弥补.同样,这可能不适用于任何现有的preferences-extensions-lib(例如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 +的不同样式.在撰写本文时,许多人抱怨这是越野车. 此处.

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

不幸的是,support.v7.preference剥离了与处理Fragment有关的所有内容,从而使其失去了很多内置功能.现在,您不仅要维护XML,还必须对它们进行子类化和重写,而不幸的是,所有这些都没有文档记录.

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

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

在另一种方法中(在在此处所述),您还必须管理后退堆栈以实现后退导航按预期.对于每个新创建/显示的片段,它以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中.因此,您必须对这两个子类都进行子类化,然后创建对话框并自行显示(在此处解释).

查看PreferenceFragmentCompat.onDisplayPreferenceDialog()的源代码表明,它知道如何精确地处理2个对话框首选项(EditTextPreferenceListPreference),您还必须使用OnPreferenceDisplayDialogCallback s来实现自己的所有其他事情.一个人纳闷,为什么没有功能来处理DialogPreference的子类!


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

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

主要目的是:

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

不要认为它干净得可以立即使用,但是在处理类似问题时可能会给您一些提示.试一下,如果您有任何建议,请告诉我.

I was trying to implement preferences for an AppCompat app, using support.v7.preference. It took me a couple of days to fiddle through it, since support.v7.preference has some significant differences to the native preferences... which isn't too bad once you know, but unfortunately there's little documentation out there. I thought I'd share my findings so others don't have to go through the same pain.


So... question:

How do you best implement Preferences for AppCompat apps (with PreferenceFragment and AppCompatAcitivity being incompatible)?

Here are a couple of related questions:

Official docs here:

解决方案

Solution 1: Native PreferenceFragment with AppCompatActivity

In AndroidStudio, choose File > New Project >...> SettingsActivity. This template uses a workaround that retrofits the native PreferenceFragment to work with AppCompatActivity, similar to the support.v4.Fragment or the support.v7.PreferenceFragmentCompat.

  • Pro: you can now use the native Preference functionality within an AppCompat app. It's a quick approach when using the AS template, and you can stick to the existing Preference docs and workflows.
  • Con: the retrofitting isn't very intuitive or clean. Also since it's usually advisable to use support libs where available, I'm not sure how future-proof this approach is.

Solution 2: support.v7.preference.PreferenceFragmentCompat with AppCompatActivity

  • Pro: maximizes compatibility
  • Con: a lot of gaps to bridge. Also this might not work with any of the existing preference-extensions-libs out there (eg. ColorPicker or FontPreferences).

Should you choose not to use Solution 1 (I'm still not sure which of the two is more future proof), there are a couple of drawbacks when using support.v7.preference.

Important drawbacks of using Solution 2 are mentioned below.

Dependencies:

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'
}

Theme: You'll need to define a preferenceTheme in your styles.xml, otherwise running your app will raise an exception.

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

You might wanna split this into different styles for 7+/14+/21+. A lot of people complain about this being buggy at the time of this writing. There is a very comprehensive answer available here.

Behavior changes: using the native preferences is extremely straight forward: all you need to do is define/maintain your preferences.xml and use addPreferencesFromResource(R.xml.preferences) within your PreferenceFragment. Custom preferences are easily done by sub-classing DialogPreference, and then just referenced to within the preferences.xml... bam, works.

Unfortunately, support.v7.preference has had everything related to dealing with Fragment stripped out, making it loose a lot of it's built-in functionality. Instead of just maintaining an XML, you now have to sub-class and override a lot of stuff, all of which is unfortunately undocumented.

PreferenceScreens: PreferenceScreens are no longer managed by the framework. Defining a PreferenceScreen in your preference.xml (as described in the docs) will display the entry, but clicking on it does nothing. It's now up to you to deal with displaying and navigating sub-screens. Boring.

There is one approach (described here), adding a PreferenceFragmentCompat.OnPreferenceStartScreenCallback to your PreferenceFragmentCompat. While this approach is quickly implemented, it simply swaps the content of the existing preference fragment. Downside is: there is no back navigation, you're always 'at the top', which isn't very intuitive for the user.

In another approach (described here), you'll also have to manage the back stack in order to achieve back navigation as expected. This uses preferenceScreen.getKey() as a root for each newly created/displayed fragment.

When doing so, you might also stumble over the PreferenceFragments being transparent by default and adding up oddly on top of each other. People tend to override PreferenceFragmentCompat.onViewCreated() to add something like

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

Custom DialogPreference: Making your own preferences has also gone from trivial to boring. DialogPreference now has anything that deals with the actual dialog, removed. That bit now lives in PreferenceDialogFragmentCompat. So you'll have to sub-class both, then deal with creating the dialog and displaying it yourself (explained here).

Looking at the source of PreferenceFragmentCompat.onDisplayPreferenceDialog() shows that it knows how to deal with exactly 2 dialog preferences (EditTextPreference, ListPreference), everything else you'll have to implement yourself using OnPreferenceDisplayDialogCallbacks... one wonders, why there is no functionality to handle sub-class of DialogPreference!


Here is some code that implements most of these workarounds and boxes them in a lib module:

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

Main intentions were:

  • Remove the need to extend and fiddle with Activity and PreferenceFragment in each app/projects. preference.xml is now again the only per-project file to change/maintain.
  • Handle and display PreferenceScreens (sub-screens) as expected.
  • Un-split DialogPreference to restore the native behavior.
  • Handle and display any sub-class of DialogPreference.

Don't think it's clean enough to be just used out of the box, but it might give you some hints when dealing with similar issues. Give it a spin and let me know if you've got any suggestions.

这篇关于如何将support.v7.preference与AppCompat一起使用以及潜在的缺点的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
相关文章
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆