如何使用 android.support.v7.preference 库创建自定义首选项? [英] How do I create custom preferences using android.support.v7.preference library?

查看:30
本文介绍了如何使用 android.support.v7.preference 库创建自定义首选项?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我希望至少支持 api 10,我希望能够很好地设置我的首选项样式,我希望能够有标题(或显示 PreferenceScreens).AppCompat 的着色不完全支持 PreferenceActivity 似乎不适合.所以我正在尝试使用 AppCompatActivityPreferenceFragmentCompat.

I want to support at least api 10, I want to be able to style my preferences nicely, I want to be able to have headers (or to show PreferenceScreens). It seems that PreferenceActivity, not fully supported by AppCompat's coloring, will not fit. So I'm trying to use AppCompatActivity and PreferenceFragmentCompat.

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

现在,我想创建一个自定义首选项来提供字体选择.使用 PreferenceActivity,我可以简单地做

Now, I want to create a custom preference that will provide the choice of a font. With PreferenceActivity, I could simply do

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来显示

and use xml such as this to display it

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

但是现在,android.support.v7.preference.DialogPreference 中没有 onPrepareDialogBu​​ilder.相反,它已移至 PreferenceDialogFragmentCompat.我发现关于如何使用那个东西的信息很少,我不确定如何从 xml 到显示它.v14 偏好片段有以下代码:

But now, there is no onPrepareDialogBuilder in android.support.v7.preference.DialogPreference. Instead, it's been moved to PreferenceDialogFragmentCompat. I found little information on how to use that thing, and I'm not sure how to go from xml to displaying it. v14 preference fragment has the following code:

public void onDisplayPreferenceDialog(Preference preference) {
    ...

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

我尝试子类化 android.support.v7.preference.DialogPreference 并让 onDisplayPreferenceDialog 使用一段类似的代码来实例化一个虚拟的 FontPreferenceFragment但它失败了,但有以下例外.

I tried subclassing android.support.v7.preference.DialogPreference and having onDisplayPreferenceDialog use a similar piece of code to instantiate a dummy FontPreferenceFragment but it fails with the following exception.

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

在这一点上,我已经陷入困境,不想进一步挖掘.谷歌对此异常一无所知.不管怎样,这个方法似乎过于复杂了.那么,使用 android.support.v7.preference 库创建自定义首选项的最佳方法是什么?

At this point I'm already too deep into the mess and don't want to dig further. Google knows nothing about this exception. Anyways, this method seems to be overly complicated. So, what's the best way to create custom preferences using android.support.v7.preference library?

推荐答案

重要提示:目前(v7 库的 v23.0.1)PreferenceThemeOverlay"仍然存在很多主题问题(参见 这个问题).例如,在 Lollipop 上,您最终会得到 Holo 样式的类别标题.

Important note: Currently (v23.0.1 of the v7 library) there are still a lot of theme-issues with the 'PreferenceThemeOverlay'(see this issue). On Lollipop for example, you end up with Holo-styled category headers.

经过令人沮丧的几个小时后,我终于成功创建了自定义 v7 首选项.创建您自己的 Preference 似乎比您想象的要困难.所以一定要花一些时间.

After some frustrating hours, I finally succeeded to create a custom v7 Preference. Creating your own Preference appears to be harder than you might think is needed. So make sure to take some time.

起初您可能想知道为什么您会为每个首选项类型找到 DialogPreferencePreferenceDialogFragmentCompat.事实证明,第一个是实际首选项,第二个是显示首选项的 DialogFragment.遗憾的是,您需要对它们进行子类化两者.

At first you might be wondering why you will find both a DialogPreference and a PreferenceDialogFragmentCompat for each preference type. As it turns out, the first one is the actual preference, the second is the DialogFragment where the preference would be displayed in. Sadly, you are required to subclass both of them.

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

Don't worry, you won't need to change any piece of code. You only need to relocate some methods:

  • 所有偏好编辑方法(如 setTitle()persist*())都可以在 DialogPreference 类中找到.莉>
  • 所有对话框(-editing)方法(onBindDialogView(View) & onDialogClosed(boolean))已移至PreferenceDialogFragmentCompat.
  • All preference-editing methods (like setTitle() or persist*()) can be found in the DialogPreference class.
  • All dialog (-editing) methods (onBindDialogView(View) & onDialogClosed(boolean)) have been moved to PreferenceDialogFragmentCompat.

您可能希望现有的类扩展第一个类,这样我认为您不必更改太多.自动完成应该可以帮助您找到缺失的方法.

You might want your existing class to extend the first one, that way you don't have to change to much I think. Autocomplete should help you find missing methods.

完成上述步骤后,就可以将这两个类绑定在一起了.在您的 xml 文件中,您将参考首选项部分.但是,当您的自定义首选项需要时,Android 尚不知道它必须膨胀哪个 Fragment.因此,您需要覆盖onDisplayPreferenceDialog(Preference):

When you have completed the above steps, it is time to bind these two classes together. In your xml file, you will refer to the preference-part. However, Android doesn't know yet which Fragment it must inflate when your custom preference needs to be. Therefore, you need to override 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 需要处理键":

and also your DialogFragment needs to handle the '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 中:键入类名并按 Ctrl+b 以查看反编译的类).希望有帮助.

That should do the trick. If you encounter problems, try taking a look at existing subclasses and see how Android solved it (in Android Studio: type a class' name and press Ctrl+b to see the decompiled class). Hope it helps.

这篇关于如何使用 android.support.v7.preference 库创建自定义首选项?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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