Android: ListPreference hide/disable value - android

I'm generating a listPreference dialog based on xml (entries and entryValues).
<string-array name="listArray">
<item>Title (A-Z)</item>
<item>Title (Z-A)</item>
<item>Visits (default)</item>
<item>Date</item>
<item>Manual</item>
</string-array>
<string-array name="listValues">
<item>titleASC</item>
<item>titleDESC</item>
<item>visitsSort</item>
<item>createSort</item>
<item>manualSort</item>
</string-array>
I want to hide/disable some of the entries (for example: Manual) based on some other parameters.
I understand it should be inside this scope:
Preference sorted = (Preference) findPreference(OPT_SORT);
sorted.setOnPreferenceClickListener(new OnPreferenceClickListener() {
public boolean onPreferenceClick(Preference preference) {
if (params) {
What should i put here to hide/disable some of the entries?
}
return true;
}
});
Thank you!
EDIT:
Best solution I found is to load a different set of Entries and EntryValues.
On Preference class (onCreate):
ListPreference sortBy = (ListPreference) findPreference(OPT_SORT);
if (isTabletDevice()) {
sortBy.setEntries(getResources().getStringArray(R.array.HClistArray));
sortBy.setEntryValues(getResources().getStringArray(R.array.HClistValues));
}
Hope this helps anyone! :)

AFAIK, ListPreference does not support this. You might be able to create your own subclass of ListPreference where you use a custom Adapter and indicate which items are and are not enabled.

It's quite late answer, I hope that's will help.
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
// For list preferences, look up the correct display value in
// the preference's 'entries' list.
ListPreference listPreference = (ListPreference) preference;
int index = listPreference.findIndexOfValue(stringValue);
// Set the summary to reflect the new value.
preference
.setSummary(index >= 0 ? listPreference.getEntries()[index]
: null);
// If it's sync_factory_list, enable/disable appropriate settings
if(preference.getKey().equalsIgnoreCase("sync_factory_list")){
Preference p_api_key = preference.getPreferenceManager().findPreference("ws_api_key");
Preference p_api_url = preference.getPreferenceManager().findPreference("ws_api_url");
switch ( index) {
case 0: //local
p_api_key.setEnabled(false);
p_api_url.setEnabled(false);
break;
case 1: //prestashop webservice
p_api_key.setEnabled(true);
p_api_url.setEnabled(true);
break;
case 2: //thrift
p_api_key.setEnabled(false);
p_api_url.setEnabled(false);
break;
default:
p_api_key.setEnabled(false);
p_api_url.setEnabled(false);
break;
}
}
}
...
return true;
}
}

Related

How to hide dependent Edittextpreferences when a Checkboxpreference is checked?

I have a CheckBoxPreference and two EditTextPreferences which are dependent on the CheckBoxPreference (all defined in an xml file and all three together inside a single PreferenceScreen).
My question is this: How to hide and redisplay those two EditTextPreferences when the user unchecks and checks the Checkboxpreference respectively?
Currently I am just able to enable/disable them by adding the android:dependency attribute to them.
Solutions to do so in java or in xml will be appreciated. :)
I'm not aware of anyway to do this through xml, which always my preferred choice. But this java solution should work.
CheckBoxPreference chkPref = (CheckBoxPreference)findPreference("myCheckPref");
EditTextPreference editPref1 = (EditTextPreference)findPreference("myEditCheckPref");
PreferenceGroup editTextParent = getParent(editPref1);
chkPref.setOnPreferenceChangeListener(new OnPreferenceChangeListener(){
public boolean onPreferenceChange(Preference pref, Object value)
{
if(value)
editTextParent.addPreference(editPref1);
else
editTextParent.removePreference(editPref1);
return true;
}
});
As there is no in built way to find the parent group of a parent, you will also have to define these functions:
private PreferenceGroup getParent(Preference preference)
{
return getParent(getPreferenceScreen(), preference);
}
private PreferenceGroup getParent(PreferenceGroup root, Preference preference)
{
for (int i = 0; i < root.getPreferenceCount(); i++)
{
Preference p = root.getPreference(i);
if (p == preference)
return root;
if (PreferenceGroup.class.isInstance(p))
{
PreferenceGroup parent = getParent((PreferenceGroup)p, preference);
if (parent != null)
return parent;
}
}
return null;
}

Get Key, not value, of the ListPreference selection - Possible?

Getting the value of the currently selected item in a ListPreference is straightforward:
String selected = sharedPrefs.getString(
getString(R.string.list_preference_array),
"default string"
);
But now I need to get the key of the currently selected item, instead. Is this possible?
To clarify, a typical ListPreference definition in the XML file has the following components:
<ListPreference
android:key="#string/list_preference_array"
android:title="Title of ENTIRE list (not seen by user?)"
android:summary="this is what the user sees in small fonts"
android:defaultValue="just in case"
android:entries="#array/user_friendly_labels"
android:entryValues="#array/code_meaningful_strings"
android:dialogTitle="User Prompt(big font)"
android:showDefault="true"
android:showSilent="true"
/>
What sharedPrefs.getString() returns is the current selection from android:entryValues. What I am interested in getting is the current selection from android:entries. I mistakenly called it "key" but really it is a "corresponding label", which must be different than actual content.
A bit of a guess:
int index = mylistpreference.findIndexOfValue(selected) // <- selected taken from your code above
String entry = mylistpreference.getEntries()[index];
just use:
mylistpreference.getEntry()
to get mylistpreference use:
mylistpreference= (ListPreference) getPreferenceScreen().findPreference(key);
key is the android:key you defined in preference.xml inside < ListPreference> tag.
The function is defined as
SharedPreferences.getString(String key, String defaultValue);
So in your example code, getString(R.string.select_string) would return the key.
When you add the SharedPreference, you need to specify the key, so the key would be the same one you used to set the value.
Edit:
using SharedPreferences.getString() with the ListPreference key as the key will return the value the user selected from the list. You don't need to create keys for each option in the ListPreference array, and these keys aren't created automatically. Use case statements that correlate to the ListPreference's entryValues.
#shai Your method lags to last selected entry
listPreference.getEntry()
Rather #Erik 's method works nicely
int index = listPreference.findIndexOfValue((String) value)
String entry = listpreference.getEntries()[index];
To properly update the summary of a ListPreference (using the label, instead of the key).
#Override
public boolean onPreferenceChange(Preference preference, Object value) {
String stringValue = value.toString();
if (preference instanceof ListPreference) {
ListPreference listPreference = (ListPreference) preference;
int prefIndex = listPreference.findIndexOfValue(stringValue);
if (prefIndex >= 0) {
CharSequence[] labels = listPreference.getEntries();
preference.setSummary(labels[prefIndex]);
}
} else {
preference.setSummary(stringValue);
}
return true;
}

How to open or simulate a click on an android Preference, created with XML, programmatically?

I've an android application with preferences declared in XML, loaded with addPreferencesFromResource. The user can open preferences, click on each item and edit them, all works.
One preference I have is:
<ListPreference android:key="abc"
android:title="#string/abc"
android:summary="#string/cde"
android:persistent="true"/>
How can I show the preference dialog to a user automatically (without the need for the user to go to the preference screen and click on it?).
I tried ( (android.preference.DialogPreference) prefMgr.findPreference( "abc" )).showDialog(null), but is says it is a protected method...? Called it from my main activity (which is a PreferenceActivity), that's why it obviously cannot work. But how else?
EDIT
I just found two threads (1, and 2) with the idea to use findViewById to access the preference, but with no success. It always returns null (does for me, too).
It looks like there is really no possibility to do this from code.
See the new accepted answer for a much cleaner approach! This was working, but not really the clean way of doing it.
Damn it, it got me several hours, but it finally works.
The solution is the undocumented call public void onItemClick (...). It takes several arguments, and as pointed out by this question it can be used to simulate a click according to the index of the element you want to call.
My problem was the item I want to call is deeply nested in an XML-structure. But the solution is very easy: add a key to the PreferenceScreen the item you want to open is in:
<PreferenceScreen
android:key="pref_key"
....
/>
<ListPreference android:key="abc"
android:title="#string/abc"
android:summary="#string/cde"
android:persistent="true"/>
</PreferenceScreen>
And the you can just to the following:
// the preference screen your item is in must be known
PreferenceScreen screen = (PreferenceScreen) findPreference("pref_key");
// the position of your item inside the preference screen above
int pos = findPreference("abc").getOrder();
// simulate a click / call it!!
screen.onItemClick( null, null, pos, 0 );
And the Dialog pops up!
It would be nice to get the PreferenceScreen a Preference is in (so you would not have to know where your Preference is in), because moving the preference/changing the XML could break the automatic dialog silently and might not get noticed (if not tested).
For this I wrote a function which will search through all preferences and return the PreferenceScreen your preference is on, so you don't need to have your PreferenceScreen a key!
private PreferenceScreen findPreferenceScreenForPreference( String key, PreferenceScreen screen ) {
if( screen == null ) {
screen = getPreferenceScreen();
}
PreferenceScreen result = null;
android.widget.Adapter ada = screen.getRootAdapter();
for( int i = 0; i < ada.getCount(); i++ ) {
String prefKey = ((Preference)ada.getItem(i)).getKey();
if( prefKey != null && prefKey.equals( key ) ) {
return screen;
}
if( ada.getItem(i).getClass().equals(android.preference.PreferenceScreen.class) ) {
result = findPreferenceScreenForPreference( key, (PreferenceScreen) ada.getItem(i) );
if( result != null ) {
return result;
}
}
}
return null;
}
private void openPreference( String key ) {
PreferenceScreen screen = findPreferenceScreenForPreference( key, null );
if( screen != null ) {
screen.onItemClick(null, null, findPreference(key).getOrder(), 0);
}
}
// With this, you can call your `Preference` like this from code, you do
// not even have to give your PreferenceScreen a key!
openPreference( "abc" );
You could have extended ListPreference to create your dialog, then included your own public method that calls the protected showDialog method of ListPreference. Something like:
public void show()
{
showDialog(null);
}
This way you won't run into the issue of getOrder() not working when there are PreferenceGroups as several people have pointed out in the comments your answer.
This can be done with any preference types that has a protected showDialog method.
If you use the support library you can open a dialog easily with PreferenceManager.showDialog(Preference).
In your PreferenceFragmentCompat:
getPreferenceManager().showDialog(findPreference("pref_name"));
Note that support preference package has many issues:
non-material styling and
it crashes when rotated with an open dialog.
PreferenceScreen preferenceScreen = (PreferenceScreen) findPreference("pref_key");
final ListAdapter listAdapter = preferenceScreen.getRootAdapter();
EditTextPreference editPreference = (EditTextPreference) findPreference("set_password_preference");
final int itemsCount = listAdapter.getCount();
int itemNumber;
for (itemNumber = 0; itemNumber < itemsCount; ++itemNumber) {
if (listAdapter.getItem(itemNumber).equals(editPreference)) {
preferenceScreen.onItemClick(null, null, itemNumber, 0);
break;
}
}
}
}
Improving deepak goel's answer:
private void openPreference(String key) {
PreferenceScreen preferenceScreen = getPreferenceScreen();
final ListAdapter listAdapter = preferenceScreen.getRootAdapter();
final int itemsCount = listAdapter.getCount();
int itemNumber;
for (itemNumber = 0; itemNumber < itemsCount; ++itemNumber) {
if (listAdapter.getItem(itemNumber).equals(findPreference(key))) {
preferenceScreen.onItemClick(null, null, itemNumber, 0);
break;
}
}
}
If you're using AndroidX Preference library, it is quite simple.
public class CustomPreferenceFragment extends PreferenceFragmentCompat {
#Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.your_preference);
DialogPreference dialogPreference = (DialogPreference) findPreference("your_preference_key");
onDisplayPreferenceDialog(dialogPreference);
}
}
wait, u can do something like this as well
Preference p=findPreference("settings_background_color");
p.setOnPreferenceClickListener(new OnPreferenceClickListener() {
#Override
public boolean onPreferenceClick(Preference preference) {
int color=PreferenceManager.getDefaultSharedPreferences(ALifePatternsWallpaperSettings.this).getInt("settings_background_color", Color.BLACK);
new ColorPickerDialog(ALifePatternsWallpaperSettings.this, ALifePatternsWallpaperSettings.this, "settings_background_color", color, Color.BLACK).show();
return true;
}
});
hi friends try this code in works fine
getPreferenceManager().findPreference("YOUR PREF_KEY").setOnPreferenceClickListener(new OnPreferenceClickListener()
{
public boolean onPreferenceClick(Preference preference)
{
//your code here
return true;
}
});

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?
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);
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>
I recommend using V7 preference, it has setVisible() method. But I have not tried it yet.
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
}
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.
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.
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);
}

How to edit a ListPreference value from java code in Android

I know how to change the value of a CheckBoxPreference, but I can't get it to work for a ListPreference.
Here is how my preference screen is built:
one CheckBox for the default
A ListPreference to select a color other than the default.
The ListPreference is defined with the key "titleColor", as follows :
CharSequence[] entries = { "Dark grey", "Light grey", "Light red", "Red" };
CharSequence[] entryValues = { "#4c4c4c", "#b5b5b5", "#ab6a68", "#962622" };
final ListPreference color = (ListPreference) findPreference("titleColor");
color.setEntries(entries);
color.setEntryValues(entryValues);
Now, when I select a color I do this:
color.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
System.out.println("In the onClick method");
System.out.println("change title color");
Editor editor2 = defaultColor.getEditor();
editor2.putBoolean("defaultColor", false);
editor2.commit();
return true;
}
});
And this seems to work, though I'm not sure to do this properly.
Now I have been trying to do something similar when I select the default color, but I can't get the list to either uncheck everything OR check a color that would be the default.
Any idea?
In the case of the CheckBox:
If you had a default color CheckBox it would be fixed using android:dependency, but since you don't have it, I guess that's the only way.
Related with the ListPreference, is quite similar:
ListPreference lp = (ListPreference)findPreference("listPreference_key");
lp.setValue("");
You can check the docs to know which methods are available.

Categories

Resources