Add preferences to specific places in PreferenceScreen programmatically
Asked Answered
R

3

5

I am populating parts of my preferences programmatically. This works fine. Unfortunately new preferences there has to be added, when the user changes some preferences (think of an 'add a new alarm'-preference). This works fine as well, when I use PreferenceCategories (because the new ones are added at the end of one such, so myPreferenceCategory.addPreference(newPreference) does the trick). But what can I do to programmatically add a Preference to any specific place (not just the end of usual categories/the prefScreen??


not so invisible category

I tried to use some kind of "invisible" PreferenceCategory, by setting android:layout="my_custom_invis_layout" with

<TextView xmlns:android="http://schemas.android.com/apk/res/android"
  android:id="@+id/my_custom_invis_layout"
  android:layout_width="match_parent"
  android:layout_height="wrap_content"
  android:paddingBottom="0dp"
  android:paddingTop="0dp"
  android:layout_marginTop="0dp"
  android:layout_marginBottom="0dp"/>

Unfortunately those padding and margin does not seem to have an impact on the minimum space the empty category take (but do so with positive values, which is - of cause - of no help).


I tried as well to nullify the layout by

<PreferenceCategory
    android:layout="@null">

but this just enlarges the space the category takes to those the other preferences have.


Unfortunately SO did not help me on this so far. I would be very happy if anyone can point me to something like "add a preference A below preference B" or on how to make a category taking no space at all (as this would resolve my problem as well).

Rapeseed answered 4/4, 2017 at 21:42 Comment(1)
With over a week going by, I dont seem to have asked a stupidly easy question, at least. Unfortunately, I have still not found a solution for this.Rapeseed
B
3

Ok, I've tried that other approach with Preferences#setOrder(int). (I left the previous answer there, cause for some use cases it might be the easier solution.) Does this one better suit your needs?

public class PreferencesFragment extends PreferenceFragmentCompat {
    private SharedPreferences mSharedPreferences;
    PreferenceCategory mMyPreferenceCategory;
    // ArrayList to keep track of the currently added Preferences
    ArrayList<Preference> mPreferenceList = new ArrayList<>();
    // this counter only serves for name-giving of the added
    // Preferences in this example
    int mCounter = 0;

    @Override
    public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.preferences);
        mMyPreferenceCategory = (PreferenceCategory) findPreference("preferenceCategoryKey");
        addPreference(null);
    }

    // adds a Preference that is inserted on the position of the
    // clicked Preference, moving the clicked Preference - and all
    // Preferences after - one position down
    private void addPreference(Preference pref) {
        int order = 0;
        if (pref != null) {
            order = pref.getOrder();
        }
        for (Preference preference : mPreferenceList) {
            int oldOrder = preference.getOrder();
            if (oldOrder >= order) {
                preference.setOrder(oldOrder+1);
            }
        }
        Preference newPreference = new Preference(getContext());
        newPreference.setTitle("Preference " + mCounter);
        newPreference.setOrder(order);
        newPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                addPreference(preference);
                return false;
            }
        });
        mMyPreferenceCategory.addPreference(newPreference);
        mPreferenceList.add(newPreference);
        mCounter++;
    }
}
Bases answered 23/10, 2017 at 9:0 Comment(2)
Sorry for taking so long. Finally I got some time to test this out and I have to say: Hurray, it works like a charm! Thanks a lot for pointing this out to me!Rapeseed
Cool, glad I could help! :)Bases
B
5

I see this question is quite old, but since I was facing a similar problem and managed to solved it, I figured there would be no harm done by posting anyway. The way I solved this is by adding the Preference (in my case a category that needed to be added in a particular spot amongst the other categories) in xml from the start, removing it programmatically if not yet needed. When putting it back (programmatically) afterwards, it appears at the same position it was before removing it. Haven't tried your particular case (with single Preferences needing to go in a particular spot within a category), but I bet it works the same way.

public class PreferencesFragment extends PreferenceFragmentCompat {
    private SharedPreferences mSharedPreferences;
    private PreferenceCategory mPreferenceCategory;

    @Override
    public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.preferences);
        mPreferenceCategory = (PreferenceCategory) findPreference("preferenceCategoryKey");

        if (preferenceNotRequiredYet) {
            removePreferenceCategory();
        }

        // an I have a SharedPreferenceListener attached that calls
        // addPreferenceCategory when I need to add it back
    }

    private void removePreferenceCategory() {
        PreferenceScreen parentScreen = (PreferenceScreen) findPreference("parent_screen_key");
        parentScreen.removePreference(mPreferenceCategory);
    }

    private void addPreferenceCategory() {
        PreferenceScreen parentScreen = (PreferenceScreen) findPreference("parent_screen_key");
        parentScreen.addPreference(mPreferenceCategory);
    }
}
Bases answered 22/10, 2017 at 13:1 Comment(2)
Thanks for that answer - I believe this will work very well for a single preference, as you expected, too. BUT I do not know how many of the preferences the user want to have there. Therefore I am afraid I can't use your solution for my case (apart from guessing a big (random) number x and hopeing noone will ever try to exceed that). There has to be a solution somehow ...Rapeseed
Have you tried Preference#setOrder(int)?Bases
B
3

Ok, I've tried that other approach with Preferences#setOrder(int). (I left the previous answer there, cause for some use cases it might be the easier solution.) Does this one better suit your needs?

public class PreferencesFragment extends PreferenceFragmentCompat {
    private SharedPreferences mSharedPreferences;
    PreferenceCategory mMyPreferenceCategory;
    // ArrayList to keep track of the currently added Preferences
    ArrayList<Preference> mPreferenceList = new ArrayList<>();
    // this counter only serves for name-giving of the added
    // Preferences in this example
    int mCounter = 0;

    @Override
    public void onCreatePreferences(@Nullable Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.preferences);
        mMyPreferenceCategory = (PreferenceCategory) findPreference("preferenceCategoryKey");
        addPreference(null);
    }

    // adds a Preference that is inserted on the position of the
    // clicked Preference, moving the clicked Preference - and all
    // Preferences after - one position down
    private void addPreference(Preference pref) {
        int order = 0;
        if (pref != null) {
            order = pref.getOrder();
        }
        for (Preference preference : mPreferenceList) {
            int oldOrder = preference.getOrder();
            if (oldOrder >= order) {
                preference.setOrder(oldOrder+1);
            }
        }
        Preference newPreference = new Preference(getContext());
        newPreference.setTitle("Preference " + mCounter);
        newPreference.setOrder(order);
        newPreference.setOnPreferenceClickListener(new Preference.OnPreferenceClickListener() {
            @Override
            public boolean onPreferenceClick(Preference preference) {
                addPreference(preference);
                return false;
            }
        });
        mMyPreferenceCategory.addPreference(newPreference);
        mPreferenceList.add(newPreference);
        mCounter++;
    }
}
Bases answered 23/10, 2017 at 9:0 Comment(2)
Sorry for taking so long. Finally I got some time to test this out and I have to say: Hurray, it works like a charm! Thanks a lot for pointing this out to me!Rapeseed
Cool, glad I could help! :)Bases
V
0

You can sort preferences alphabetically by title. To do so you need to set isOrderingAsAdded to false for the PreferenceGroup your are using, category or screen. Thus when you add a new preference it just takes its place.

Volute answered 30/7, 2023 at 17:8 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.