如何动态地显示和隐藏Android上的偏好设置?

36

有没有一种方法可以动态显示和隐藏偏好设置? 在我的情况下,我有一个复选框首选项,它会禁用或启用两个首选项组(“带障碍”和“不带障碍”组之一)。 虽然这在桌面环境中是理想的GUI,但“带障碍”几乎占据了整个屏幕,而另一个“不带障碍”的只占据了屏幕的一小部分。

与其同时显示两个组,我想一次只显示其中一个,并根据复选框更改动态显示或隐藏两个组。 有没有一种方法可以实现这个功能?


1
请参见以下链接以获取更好的答案,如果您正在使用类别:https://dev59.com/DHE95IYBdhLWcg3wmvGh - Eyal
7个回答

67

从PreferenceActivity调用

Preference somePreference = findPreference(SOME_PREFERENCE_KEY);
PreferenceScreen preferenceScreen = getPreferenceScreen();
preferenceScreen.removePreference(somePreference);

你以后可以调用:

preferenceScreen.addPreference(somePreference);
唯一有点棘手的部分是在添加回去时正确排序。请查看PreferenceScreen文档,尤其是它的基类PreferenceGroup,以获取详细信息。 注意:上述仅适用于PreferenceScreen的直接子项。如果中间有PreferenceCategory,则需要从其父PreferenceCategory中删除首选项,而不是PreferenceScreen。首先确保在XML文件中PreferenceCategory设置了一个android:key属性,然后执行以下操作:
Preference somePreference = findPreference(SOME_PREFERENCE_KEY);
PreferenceCategory preferenceCategory = (PreferenceCategory) findPreference(SOME_PREFERENCE_CATEGORY_KEY);
preferenceCategory.removePreference(somePreference);

并且:

preferenceCategory.addPreference(somePreference);

2
移除了一些偏好设置后,再次调用“findPreference()”返回“null”,如何重新添加? - Mickey Tin
6
当你找到某个偏好设置(somePreference)时,将其保存为一个类成员,然后根据需要添加或移除即可。 - dhaag23
@dhaag23,对于主PreferenceScreen它运行良好,但对于内部PreferenceScreen则无法正常工作,即尝试将PreferenceCategory添加到内部PreferenceScreen中。 - Bipin Vayalu
2
如果Preference嵌套在PreferenceCategory中,请搜索PreferenceCategory而不是PreferenceScreen。然后尝试使用referenceCategory.remove/addPreference进行引用。 - sfszh
1
我刚刚注意到,当活动停止并重新启动时(例如,因为它被带到后台并再次带到前台),这会导致NPE,因为findPreference()将不再找到之前已删除的首选项。 - user149408
显示剩余2条评论

7

如果您只想根据另一个首选项来禁用/启用首选项,则可以指定 android:dependency="preferenceKey"Preference.setDependency(String)

以下是来自developer.android.com的示例:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
    <CheckBoxPreference
        android:key="pref_sync"
        android:title="@string/pref_sync"
        android:summary="@string/pref_sync_summ"
        android:defaultValue="true" />
    <ListPreference
        android:dependency="pref_sync"
        android:key="pref_syncConnectionType"
        android:title="@string/pref_syncConnectionType"
        android:dialogTitle="@string/pref_syncConnectionType"
        android:entries="@array/pref_syncConnectionTypes_entries"
        android:entryValues="@array/pref_syncConnectionTypes_values"
        android:defaultValue="@string/pref_syncConnectionTypes_default" />
</PreferenceScreen>

5

我建议使用V7 preference,它有setVisible()方法。但我还没有尝试过。


它可以工作,但你需要进行一些重构(新类)。此外,将可见性设置为其当前值会显示一些奇怪的错误(在23.3.1中),因此请确保检查可见性是否还不是您想要的。另外,从本地首选项切换到preference-v7会导致首选项的过时LAF,我还没有找出如何解决这个问题。 - user149408

1
如果您想在首选项中完全隐藏首选项,这里有一个示例。但是不允许再次将其显示出来。
public class RemovablePreference extends Preference {

@Override
protected void onBindView(View view) {
    super.onBindView(view);

    updateVisibility(); // possibly a better place available?
}

private void updateVisibility() {
    Context context = getContext(); // should be a PreferenceActivity
    if (context instanceof PreferenceActivity) {
        updateVisibility((PreferenceActivity)context);
    }
}

private void updateVisibility(PreferenceActivity activity) {
    updateVisibility(getPreferenceScreen(activity));
}

private PreferenceScreen getPreferenceScreen(PreferenceActivity activity) {

    if (activity.getPreferenceScreen() != null) {
        return activity.getPreferenceScreen(); // for old implementations
    }

    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.HONEYCOMB) {
        Fragment fragment = activity.getFragmentManager().findFragmentById(android.R.id.content);
        if (fragment instanceof PreferenceFragment) {
            return ((PreferenceFragment) fragment).getPreferenceScreen();
        }
    }
    return null;
}

private void updateVisibility(PreferenceScreen screen) {
    if (!isVisible() && screen != null) {
        hidePreference(screen, this);
    }
}

private boolean hidePreference(PreferenceGroup prefGroup, Preference removedPreference) {
    boolean removed = false;

    if (prefGroup.removePreference(removedPreference)) {
        removed = true;
    }

    for (int i = 0; i < prefGroup.getPreferenceCount(); i++) {
        Preference preference = prefGroup.getPreference(i);
        if (preference instanceof PreferenceGroup) {
            PreferenceGroup prefGroup2 = (PreferenceGroup)preference;
            if (hidePreference(prefGroup2, this)) {
                // The whole group is now empty -> remove also the group
                if (prefGroup2.getPreferenceCount() == 0) {
                    removed = true;
                    prefGroup.removePreference(prefGroup2);
                }
            }
        }
    }

    return removed;
}

protected boolean isVisible() {
    return true; // override
}

0
为了动态隐藏偏好设置,我创建了一个if条件,根据其值决定是否显示偏好设置。要进行实际的隐藏,我一直在使用:
    findPreference(getString(R.string.pref_key)).setLayoutResource(R.layout.hidden);

关键部分是再次使它可见。除了重新创建布局,没有直接的方法来做到这一点。如果if条件的值为false,也就是说,pref应该是可见的,那么隐藏pref的代码将永远不会被执行,因此导致pref可见。以下是如何重新创建布局(在我的情况下,我正在扩展PreferencesListFragment):
    getActivity().recreate();

希望这对你有所帮助。


R.layout.hidden 似乎是一个自定义布局。你能分享一下吗?另外,如果要撤销此操作,可能需要找出首选项项目使用的默认布局并重新分配它。 - user149408
@user249408 这是hidden.xml文件<?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="fill_parent" android:layout_height="fill_parent" android:visibility="gone"> </LinearLayout> - Marline

0
我需要类似的东西:切换开关以隐藏或显示两个额外的偏好设置。请查看Android-Support-Preference-V7-Fix的示例应用程序,它带来了一些新的偏好设置类型,并修复了官方库中的一些问题。那里有一个示例可以切换复选框以显示或隐藏偏好设置类别。
在扩展PreferenceFragmentCompatDividers的片段中,您可以使用类似以下的内容:
findPreference("pref_show_extra_stuff").setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            findPreference("pref_extra_stuff_01").setVisible((Boolean) newValue);
            findPreference("pref_extra_stuff_02").setVisible((Boolean) newValue);
            return true;
        }
    });

pref_extra_stuff_01pref_extra_stuff_02是两个偏好设置,当pref_show_extra_stuff被切换时会隐藏。


0

不要在设置界面的onCreate中执行这个操作:

getSupportFragmentManager().beginTransaction()
    .replace(R.id.settings_container, new SettingsFragment()).commit();

你可以为设置片段初始化一个全局变量,并像这样设置它:
settingsFragment = new SettingsFragment();
getSupportFragmentManager().beginTransaction()
    .replace(R.id.settings_container, settingsFragment).commit();

然后,你可以使用一个全局的SharedPreferences.OnSharedPreferenceChangeListener来设置当你更改偏好时应该显示或隐藏什么内容:

// Global SharedPreferences.OnSharedPreferenceChangeListener
sharedPreferenceChangeListener = new SharedPreferences.OnSharedPreferenceChangeListener()
{
    Override
    public void onSharedPreferenceChanged(SharedPreferences preferences, String key)
    {
        if (key.equals("switch key"))
        {
            boolean newPref = preferences.getBoolean("switch key", true);

            settingsFragment.findPreference("seekbar key").setVisible(newPref);
        }
    }
};

sharedPreferences.registerOnSharedPreferenceChangeListener(sharedPreferenceChangeListener);

然后在设置片段的onCreate中,您可以像这样做,根据现有的首选项设置应该隐藏什么:

SharedPreferences sharedPreferences = PreferenceManager.getDefaultSharedPreferences(getContext());

if (!sharedPreferences.getBoolean("switch key", true)
{
    SeekBarPreference seekBarPreference = findPreference("seekbar key");
    seekBarPreference.setVisible(false);
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接