如何使用android.support.v7.preference库创build自定义首选项?

我想至less支持api 10,我希望能够很好地设置我的喜好,我希望能够有标题(或显示PreferenceScreen )。 PreferenceActivity似乎没有完全支持AppCompat的着色,不适合。 所以我试图使用AppCompatActivityPreferenceFragmentCompat

 public class Prefs extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); if (savedInstanceState == null) getSupportFragmentManager().beginTransaction() .replace(android.R.id.content, new PreferencesFragment()) .commit(); } public static class PreferencesFragment extends PreferenceFragmentCompat { @Override public void onCreate(final Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.preferences); } @Override public void onDisplayPreferenceDialog(Preference preference) { // the following call results in a dialogue being shown super.onDisplayPreferenceDialog(preference); } @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) { // I can probably use this to go to to a nested preference screen // I'm not sure... } } } 

现在,我想创build一个自定义首选项,将提供一个字体的select。 有了PreferenceActivity ,我可以简单地做

 import android.preference.DialogPreference; public class FontPreference extends DialogPreference { public FontPreference(Context context, AttributeSet attrs) {super(context, attrs);} @Override protected void onPrepareDialogBuilder(Builder builder) { super.onPrepareDialogBuilder(builder); // do something with builder and make a nice cute dialogue, for example, like this builder.setSingleChoiceItems(new FontAdapter(), 0, null); } } 

并使用这样的XML来显示它

 <my.app.FontPreference android:title="Choose font" android:summary="Unnecessary summary" /> 

但是现在android.support.v7.preference.DialogPreference没有onPrepareDialogBuilder了。 相反,它被移到了PreferenceDialogFragmentCompat 。 我发现很less有关于如何使用这个东西的信息,我不知道如何从xml去显示它。 v14首选片段具有以下代码:

 public void onDisplayPreferenceDialog(Preference preference) { ... final DialogFragment f; if (preference instanceof EditTextPreference) f = EditTextPreferenceDialogFragment.newInstance(preference.getKey()); ... f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG); } 

我尝试了onDisplayPreferenceDialog android.support.v7.preference.DialogPreference并使onDisplayPreferenceDialog使用类似的一段代码实例化一个虚拟的FontPreferenceFragment但它失败,出现以下exception。

 java.lang.IllegalStateException: Target fragment must implement TargetFragment interface 

在这一点上,我已经深陷困境,不想进一步挖掘。 Google对这个例外一无所知。 无论如何,这个方法似乎太复杂了。 那么,使用android.support.v7.preference库创build自定义首选项的最佳方法是什么?

Solutions Collecting From Web of "如何使用android.support.v7.preference库创build自定义首选项?"

重要说明:目前(v7库的v23.0.1)仍然有很多“PreferenceThemeOverlay”的主题问题(请参阅此问题 )。 例如,在棒棒糖,你最终与全息风格的类别标题。

经过一段令人沮丧的时间,我终于成功地创build了一个自定义v7偏好。 创build自己的Preference似乎比你想象的要困难。 所以一定要花点时间。

起初,您可能会想知道为什么您会为每个首选项typesfindDialogPreferencePreferenceDialogFragmentCompat 。 事实certificate,第一个是实际的首选项,第二个是显示首选项的DialogFragment 。不幸的是,您需要将这两个子类化。

别担心,您不需要更改任何代码。 您只需要重新定位一些方法:

  • 所有首选项编辑方法(如setTitle()persist*() )都可以在DialogPreference类中find。
  • 所有的对话(-editing)方法( onBindDialogView(View)onDialogClosed(boolean) )已被移到PreferenceDialogFragmentCompat

你可能希望现有的课程扩展第一个课程,这样你就不必改变我的想法。 自动完成应该可以帮助您find缺less的方法。

当你完成上述步骤时,是时候将这两个类绑定在一起了。 在你的xml文件中,你会参考偏好部分。 但是,Android还不知道当您的自定义首选项需要时它必须膨胀哪个Fragment 。 因此,您需要重写onDisplayPreferenceDialog(Preference)

 @Override public void onDisplayPreferenceDialog(Preference preference) { DialogFragment fragment; if (preference instanceof LocationChooserDialog) { fragment = LocationChooserFragmentCompat.newInstance(preference); fragment.setTargetFragment(this, 0); fragment.show(getFragmentManager(), "android.support.v7.preference.PreferenceFragment.DIALOG"); } else super.onDisplayPreferenceDialog(preference); } 

而且你的DialogFragment也需要处理'key':

 public static YourPreferenceDialogFragmentCompat newInstance(Preference preference) { YourPreferenceDialogFragmentCompat fragment = new YourPreferenceDialogFragmentCompat(); Bundle bundle = new Bundle(1); bundle.putString("key", preference.getKey()); fragment.setArguments(bundle); return fragment; } 

这应该够了吧。 如果您遇到问题,请尝试查看现有的子类,并查看Android如何解决它(在Android Studio中:input类的名称,然后按Ctrl + b查看反编译的类)。 希望能帮助到你。

当你的FontPreferenceFragment没有实现DialogPreference.TargetFragment的时候会导致exception。 你需要确保你的片段实现了这个接口。