Japtar
Japtar

Reputation: 1155

How to show and hide preferences on Android dynamically?

Is there a way to dynamically show and hide preferences? In my case, I have a checkbox preference that would disable or enable one of 2 preference groups ("with-" and "without-handicap" groups). While this would be the ideal GUI in a desktop environment, the "with-handicap" takes up nearly the whole screen, while the other, "without-handicap" takes up only a small portion of the screen.

Rather than showing both groups at the same time, I'd like to show only one of them at a time, and dynamically show or hide the 2 groups when the checkbox changes. Is there a way to do this?

Upvotes: 36

Views: 35250

Answers (7)

ATL
ATL

Reputation: 444

Instead of doing this in onCreate in the settings activity:

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

You can initialize a global variable for the settings fragment and set it up like this:

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

Then further down you can set up an OnSharedPreferenceChangeListener with a global SharedPreferences.OnSharedPreferenceChangeListener to set up what should be shown or hidden when you change preferences:

// 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);

Then in onCreate in the settings fragment you can do something like this to set what should be hidden based on existing preferences:

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

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

Upvotes: 0

dhaag23
dhaag23

Reputation: 6126

From a PreferenceActivity call

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

you can later call:

preferenceScreen.addPreference(somePreference);

The only a little bit tricky part is getting the order correct when adding back in. Look at PreferenceScreen documentation, particularly it's base class, PreferenceGroup for details.

Note: The above will only work for immediate children of a PreferenceScreen. If there is a PreferenceCategory in between, you need to remove the preference from its parent PreferenceCategory, not the PreferenceScreen. First to ensure the PreferenceCategory has an android:key attribute set in the XML file. Then:

Preference somePreference = findPreference(SOME_PREFERENCE_KEY);
PreferenceCategory preferenceCategory = (PreferenceCategory) findPreference(SOME_PREFERENCE_CATEGORY_KEY);
preferenceCategory.removePreference(somePreference);

and:

preferenceCategory.addPreference(somePreference);

Upvotes: 67

Marline
Marline

Reputation: 269

For hiding preferences dynamically, I created an if-condition upon whose value I decide whether I want the pref to show or not. To do the actual hiding, I have been using:

    findPreference(getString(R.string.pref_key)).setLayoutResource(R.layout.hidden);

The tricky part is to make it visible again. There is no direct way to do it except to recreate the layout. If the value of the if-condition is false, which means the pref should be visible, then the code to hide the pref will never be executed, thus resulting in a visible pref. Here is how to recreate the layout (in my case, I am extending a PreferencesListFragment):

    getActivity().recreate();

I hope that was helpful.

Upvotes: 0

tequilasunset
tequilasunset

Reputation: 1269

I needed something similar: toggling a switch to hide or show two extra preferences. Check out the sample app from Android-Support-Preference-V7-Fix which bring some new preference types and fixes some issues from the official library. There's an example there to toggle a checkbox to show or hide a preference category.

In the fragment that extends PreferenceFragmentCompatDividers, you could use something like:

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_01 and pref_extra_stuff_02 are the two preferences that are hidden when pref_show_extra_stuff is toggled.

Upvotes: 0

Tea
Tea

Reputation: 256

I recommend using V7 preference, it has setVisible() method. But I have not tried it yet.

Upvotes: 5

digitalfootmark
digitalfootmark

Reputation: 744

If you want to implement the hiding of the preference completely in the Preference, here is one example. Does not allow to make it visible again, though.

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
}

Upvotes: 1

hidro
hidro

Reputation: 12521

Not exactly hiding/showing but if you only want disabling/enabling preference depending on another preference you can specify android:dependency="preferenceKey" or Preference.setDependency(String)

Example from 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>

Upvotes: 7

Related Questions