Remove/hide a preference from the screen
Asked Answered
A

16

148

I have an activity which extends PreferenceActivity. I'm loading preferences from the xml file. But in some cases i need completely hide one of the preferences from the screen based on my app state. There is a setEnabled method, but it's not exactly what i want. I want to remove that preference from the screen completely. Is it possible ?

Atmometer answered 10/2, 2010 at 21:4 Comment(0)
B
179

Yes, if you have a reference to both the Preference, and its parent (a PreferenceCategory, or PreferenceScreen)

myPreferenceScreen.removePreference(myPreference);
Braddy answered 10/2, 2010 at 21:7 Comment(5)
I might have answered my own question through this? https://mcmap.net/q/160575/-how-to-show-and-hide-preferences-on-android-dynamicallyHumectant
Unfortunately, it permanently removes the preference. Is it possible just to hide it?Kelliekellina
It also doesn't work for me. The preference remains!Kelliekellina
@Kelliekellina You can just gray it out with setEnabled()Grovel
@Kelliekellina You need to call removePreference on the direct parent, which you can get with getParent() (see this answer).Kieger
U
219

If your Preference is within a PreferenceCategory, you have to do this:

XML:

<PreferenceCategory
    android:key="category_foo"
    android:title="foo">

    <CheckBoxPreference
        android:key="checkPref" />

Java:

CheckBoxPreference mCheckBoxPref = (CheckBoxPreference) findPreference("checkPref");
PreferenceCategory mCategory = (PreferenceCategory) findPreference("category_foo");
mCategory.removePreference(mCheckBoxPref);
Uranian answered 18/4, 2011 at 15:18 Comment(1)
To be fair, the above answer does say that you need the parent PreferenceCategory.Zashin
B
179

Yes, if you have a reference to both the Preference, and its parent (a PreferenceCategory, or PreferenceScreen)

myPreferenceScreen.removePreference(myPreference);
Braddy answered 10/2, 2010 at 21:7 Comment(5)
I might have answered my own question through this? https://mcmap.net/q/160575/-how-to-show-and-hide-preferences-on-android-dynamicallyHumectant
Unfortunately, it permanently removes the preference. Is it possible just to hide it?Kelliekellina
It also doesn't work for me. The preference remains!Kelliekellina
@Kelliekellina You can just gray it out with setEnabled()Grovel
@Kelliekellina You need to call removePreference on the direct parent, which you can get with getParent() (see this answer).Kieger
P
54

In the case where the Preference is a direct child of the preference screen, here is some stand-alone code:

PreferenceScreen screen = getPreferenceScreen();
Preference pref = getPreferenceManager().findPreference("mypreference");
screen.removePreference(pref);
Pulverable answered 17/9, 2013 at 16:43 Comment(2)
This wont work if the preference is located inside category. you have to findPreference for the category, and remove the preference from the categoryElmer
@MBH: Thanks for mentioning that caveat!Nadia
N
21

If you are using PreferenceFragmentCompat you can set the visiblity in xml.

The preferences in your xml will be converted to AppCompat versions automatically. You can then use the 'app:isPreferenceVisible' attribute in your xml

preferences.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto"
    xmlns:tools="http://schemas.android.com/tools">

    <CheckBoxPreference
        android:defaultValue="false"
        android:key="show.navigation"
        android:title="Show navigation"
        app:isPreferenceVisible="false" />

...

The attribute is documented at https://developer.android.com/guide/topics/ui/settings/components-and-attributes

Adding PreferenceFragmentCompat is documented at https://developer.android.com/guide/topics/ui/settings/#inflate_the_hierarchy

Example:

public class MySettingsActivity extends AppCompatActivity {

    public static class MySettingsFragment extends PreferenceFragmentCompat {
        @Override
        public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
            setPreferencesFromResource(R.xml.preferences, rootKey);
        }
    }

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        getSupportFragmentManager()
                .beginTransaction()
                .replace(R.id.settings_container, new MySettingsFragment())
                .commit();
    }
} 
Namtar answered 11/1, 2019 at 22:5 Comment(1)
This is the right answer!! OP asked to HIDE a preference, NOT remove.Beverleebeverley
G
9

If you want something that will dynamically change the prefs for example on a SwitchPreference, I have found the best way is to put all my sub options into two category containers. Initially you'll have everything shown, then you just remove the bits you don't want. The clever bit, is you just trigger recreate when something changes and then you don't have to manually create anything or worry about putting things back in in the correct order.

protected void onCreate(Bundle savedInstanceState) {
  super.onCreate(savedInstanceState);
  addPreferencesFromResource(R.xml.preferences);
  PreferenceCategory prefCatOne= (PreferenceCategory)findPreference("prefCatOne");
  PreferenceCategory prefCatTwo= (PreferenceCategory)findPreference("prefCatTwo");
  SwitchPreference mySwitchPref= (SwitchPreference)findPreference("mySwitchPref");
  PreferenceScreen screen = getPreferenceScreen();
  if (mySwitchPref.isChecked()) {
    screen.removePreference(prefCatOne);
  } else {
    screen.removePreference(prefCatTwo);
  }
}

public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
    if (key.equals("mySwitchPref")) {
        this.recreate();
    }
}

The only downside that I can see with this, is there is a flash as the screen is recreated from scratch.

Germainegerman answered 16/2, 2015 at 4:27 Comment(3)
The case does not work, at least not in 22. But changing it to a Preference (even though it's a grouping of preferences) does work.Snocat
Rob, I just tested the above code in an API22 AVD and it's working just fine. Make sure your preference XML content matches your code. For the above example the SwitchPreference can be anywhere, but you need the PreferenceCategorys to be direct children of the PreferenceScreen.Germainegerman
I just got the Category as a Preference, no cast, and removed it. Worked.Snocat
T
8

In your XML file:

<PreferenceScreen 
    xmlns:android="http://schemas.android.com/apk/res/android" 
    android:key="preferenceScreen">

    <PreferenceCategory
        android:key="personalisation"
        android:title="your title here">

        <ThemedPreference
            android:key="animation" />

</PreferenceScreen>

In your code:

PreferenceScreen pPreferenceScreen = (PreferenceScreen) findPreference("preferenceScreen");

PreferenceCategory pCategory = (PreferenceCategory) findPreference("personalisation");
ThemedPreference pThemePref = (ThemedPreference) findPreference("animation");

pPreferenceScreen.removePreference(pCategory); //remove category
pCategory.removePreference(pThemePref);   // remove preference
Teddie answered 24/7, 2017 at 6:36 Comment(0)
B
7

I recommend using v7 preference, it has setVisible() method. But I have not tried it yet. Accordingly you have to use PreferenceFragment instead of PreferenceActivity.

Bandsman answered 9/6, 2017 at 3:30 Comment(2)
The accepted answer won't work for V7. Using setVisible does work for V7Pesce
V7 also has getParent(), so you can actually remove the preference as described in this answer.Kieger
S
3

In the XML file you can make a hidden preference by leaving the title and summary tags empty.

<EditTextPreference
    android:defaultValue="toddlerCam"
    android:key="save_photo_dir"
/>
Saxony answered 16/4, 2018 at 22:38 Comment(1)
This is the perfect answer to me. I've been looking for this. Thank you!Bellwether
T
3

Since Android API 26 getParent() method is available: https://developer.android.com/reference/android/preference/Preference.html#getParent()

Though you can do the following:

preference.getParent().removePreference(preference);
Tetrachloride answered 14/9, 2018 at 17:11 Comment(1)
This is also available for below API 26 with the androidx support library.Kieger
J
2

Here's a generic way to do this that works regardless of whether the preference is under a PreferenceCategory or PreferenceScreen.

private void removePreference(Preference preference) {
    PreferenceGroup parent = getParent(getPreferenceScreen(), preference);
    if (parent == null)
        throw new RuntimeException("Couldn't find preference");

    parent.removePreference(preference);
}

private PreferenceGroup getParent(PreferenceGroup groupToSearchIn, Preference preference) {
    for (int i = 0; i < groupToSearchIn.getPreferenceCount(); ++i) {
        Preference child = groupToSearchIn.getPreference(i);

        if (child == preference)
            return groupToSearchIn;

        if (child instanceof PreferenceGroup) {
            PreferenceGroup childGroup = (PreferenceGroup)child;
            PreferenceGroup result = getParent(childGroup, preference);
            if (result != null)
                return result;
        }
    }

    return null;
}
Jorgensen answered 25/5, 2017 at 2:39 Comment(0)
D
2

There is a simple workaround:

//In your Activity code after finding the preference to hide:
    if(pref!=null) {
        pref.setEnabled(false);
        pref.setSelectable(false);
        //Following line will replace the layout of your preference by an empty one
        pref.setLayoutResource(R.layout.preference_hidden);
    }

And create a preference_hidden layout:

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="0dp"/>

Wherever is your Preference to hide (in a PreferenceGroup or at root) it will work!

Designing answered 28/5, 2021 at 22:35 Comment(1)
Thank you. Worked for me perfectly. But for make sure I added: android:visibility="gone"Solus
H
0

If you want to evaluate, and based on that mask, an alternative may be

SwitchPreference autenticacionUsuario = 
    (SwitchPreference) findPreference("key_autenticacion_usuario");

final EditTextPreference Username = 
    (EditTextPreference) findPreference("key_username_mqtt");
final EditTextPreference Password = 
    (EditTextPreference) findPreference("key_password_mqtt");

if (!autenticacionUsuario.isChecked()) {
    PreferenceCategory preferenceCategory = 
        (PreferenceCategory) findPreference("category_mqtt");
    preferenceCategory.removePreference(Username);
    preferenceCategory.removePreference(Password);
}

All this must be within

public static class PrefsFragment extends PreferenceFragment {

    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
Haddad answered 12/5, 2016 at 23:38 Comment(3)
Sorry, but this is an English site. Can you answer in English?Newport
Of course my intention was also to provide for people who do not speak EnglishHaddad
@GustavoEduardoBelduma then you may need to read this meta.https://mcmap.net/q/102913/-creating-a-selector-from-a-method-name-with-parametersSchmooze
C
0

You can do this in 2 ways:

1.If you use support library, you can build a map of the tree of preferences and their parents, and then remove a preference by using its parent. Here's a function to generate such a map:

public static Map<Preference, PreferenceGroup> buildPreferenceParentTree(@NonNull final PreferenceScreen preferenceScreen) {
    final Map<Preference, PreferenceGroup> result = new HashMap<>();
    final Stack<PreferenceGroup> curParents = new Stack<>();
    curParents.add(preferenceScreen);
    while (!curParents.isEmpty()) {
        final PreferenceGroup parent = curParents.pop();
        final int childCount = parent.getPreferenceCount();
        for (int i = 0; i < childCount; ++i) {
            final Preference child = parent.getPreference(i);
            result.put(child, parent);
            if (child instanceof PreferenceGroup)
                curParents.push((PreferenceGroup) child);
        }
    }
    return result;
}
  1. If you use the new android-x preference API, you can just set the visibility, by using setVisible function on it.
Collogue answered 9/10, 2018 at 11:41 Comment(5)
According to the docs and Tea's answer setVisible() is available since version 24.1.0 of the Support library.Theomania
Have you looked at what I wrote? I specifically wrote that it's possible now... Also, the first solution helps with removal, which is a bit different than hiding..Collogue
Yes, I read your answer. I was referring to your 2nd point. It reads to as if the setVisibile() method is available from android-x which I tried to clarify. No offense please.Theomania
Android-X is the one to replace all support libraries. There won't be any new versions of support library as we know them.Collogue
Correct. I am aware of this. Still, people who are stucked with former versions can make use of the method.Theomania
C
0

If you're doing what I think you're trying to do (because I'm trying to do it now) it might be better to enable/disable the preference. Because removing it takes it out of the preference screen and you might not be able to add it back where you want it if you made the screen programmatically.

pref.setEnabled(false); pref.setEnabled(true);

although this might be deprecated. It works for the use case that I'm going through right now.

Countless answered 12/12, 2019 at 16:17 Comment(0)
S
0

If all you need is not to show the preference i.e. hide the preference then do the following

findPreference<Preference>("keyName").isVisible = false

code is in kotlin

Note : This is AndroidX preferences (don't know if same with hold with earlier Preference)

Spoilage answered 14/5, 2021 at 7:58 Comment(0)
J
0

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 you can do something like this further down in onCreate to set what should be hidden based on existing preferences, or to change what is hidden/visible based on conditions in your OnSharedPreferenceChangeListener:

settingsFragment.findPreference("setting key").setVisible(false);
Julenejulep answered 18/2, 2023 at 0:10 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.