How can I modify the summary of a ListPreference to the new "Entry" string selected by the user (not the entry value)
I suppouse its with setOnPreferenceChangeListener() but in
new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
return true;
}
}
using ((ListPreference)preference).getEntry() I get the old value (because it isn't changed yet) and newValue.toString() returns the entry value (not the entry text displayed to the user)
How can I do it? Thanks in advance
Just set the summary value to %s
in the xml description.
EDIT : I've tested it on several devices and it doesn't work really. That's strange because according to docs it must work: ListPreference.getSummary() .
But it's possible to implement this functionality by oneself. The implementation requires to inherit from the ListPreference
class:
public class MyListPreference extends ListPreference {
public MyListPreference(final Context context) {
this(context, null);
}
public MyListPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
}
@Override
public CharSequence getSummary() {
final CharSequence entry = getEntry();
final CharSequence summary = super.getSummary();
if (summary == null || entry == null) {
return null;
} else {
return String.format(summary.toString(), entry);
}
}
@Override
public void setValue(final String value) {
super.setValue(value);
notifyChanged();
}
}
As you can see MyListPreference
has its own summary field which can contain formatting markers. And when a preference's value changes, Preference.notifyChanged()
method is called and it causes MyListPreference.getSummary()
method to be called from Preference.onBindView()
.
PS: This approach hasn't been tested sufficiently so it may contain errors.
The %s
implementation is buggy. The view shows the correct value on first load (if a default list value is set), but the view does not update when selecting a list item. You have to toggle a checkbox or some other preference to update the view.
As a workaround, implement OnSharedPreferenceChangeListener
to override the summary for the list preference.
/src/apps/app_settings/SettingsActivity.java
package apps.app_settings;
import android.os.Bundle;
import android.preference.PreferenceActivity;
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* set fragment */
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}
}
/src/apps/app_settings/SettingsFragment.java
package apps.app_settings;
import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceFragment;
public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
/* set preferences */
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
/* get preference */
Preference preference = findPreference(key);
/* update summary */
if (key.equals("list_0")) {
preference.setSummary(((ListPreference) preference).getEntry());
}
}
@Override
public void onResume() {
super.onResume();
getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onPause() {
getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
super.onPause();
}
}
/res/xml/preferences.xml
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
xmlns:android="http://schemas.android.com/apk/res/android">
<ListPreference
android:key="list_0"
android:title="@string/settings_list_0_title"
android:summary="%s"
android:entries="@array/settings_list_0_entries"
android:entryValues="@array/settings_list_0_entry_values"
android:defaultValue="@string/settings_list_0_default_value"/>
</PreferenceScreen>
/res/values/strings.xml
<?xml version="1.0" encoding="utf-8"?>
<resources>
<string name="settings_list_0_title">list 0</string>
<string-array name="settings_list_0_entries">
<item>item 0</item>
<item>item 1</item>
<item>item 2</item>
</string-array>
<string-array name="settings_list_0_entry_values">
<item>0</item>
<item>1</item>
<item>2</item>
</string-array>
<string name="settings_list_0_default_value">0</string>
</resources>
i solved this problem with another and simple solution (https://gist.github.com/brunomateus/5617025) :
public class ListPreferenceWithSummary extends ListPreference{
public ListPreferenceWithSummary(Context context, AttributeSet attrs) {
super(context, attrs);
}
public ListPreferenceWithSummary(Context context) {
super(context);
}
@Override
public void setValue(String value) {
super.setValue(value);
setSummary(value);
}
@Override
public void setSummary(CharSequence summary) {
super.setSummary(getEntry());
}
}
This worked very fine on my GirgerBeard device. Even when is the first time running your app. Don't forget to provide default value on your xml prefence:
android:defaultValue="default value"
and set default values on your PreferenceActivity
or PrefenceFragment
:
PreferenceManager.setDefaultValues(this, R.xml.you pref file, false);
I recommend to implement the OnSharedPreferenceChangeListener in your PreferenceFragment or PreferenceActivity instead of Preference.setOnPreferenceChangeListner. Use setSummay to set the new changes. (Do not forget to register and unregister the listener.) This listener is called after the change to the preference has been completed. You should also set a default value in the XML for the preferences.
The "%s" solution works for me on android 4.0.3, by writting %s directly in the XML file. The problem is the text is not updated after I changed the value of the preference but it is when I modify another preference of my PreferenceScreen. Maybe some refresh is missing here.
This is the most simplified way I have implemented. Just take the values given by the onPreferenceChange listener
ListPreference preference;
@Override
protected void onCreate(Bundle savedInstanceState) {
preference = (ListPreference)findPreference("myKey");
preference.setSummary(preferenceColorButtons.getEntry());
preference.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
ListPreference listPreference = (ListPreference)preference;
int id = 0;
for (int i = 0; i < listPreference.getEntryValues().length; i++)
{
if(listPreference.getEntryValues()[i].equals(newValue.toString())){
id = i;
break;
}
}
preference.setSummary(listPreference.getEntries()[id]);
return true;
}
});
}
For all I know:
a) The %s does work on android 4, but not on 2.x.
b) The update is achieved if you set a dummy value in between, see here: https://stackoverflow.com/a/16397539/1854563
There is no need to extend ListPreference or to loop over the entryValues etc
public boolean onPreferenceChange(Preference preference, Object newValue) {
int i = ((ListPreference)preference).findIndexOfValue(newValue.toString());
CharSequence[] entries = ((ListPreference)preference).getEntries();
preference.setSummary(entries[i]);
return true;
}
I know that it's a very old question, but it's still actual. To have the summary automatically updated you have to call the original preferenceChangeListener:
final OnPreferenceChangeListener listener = preference.getOnPreferenceChangeListener();
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
{
@Override
public boolean onPreferenceChange(Preference preference, Object o)
{
if (listener !=null)
listener .onPreferenceChange(preference, o);
return true;
}
});
I also faced this problem and I finally found a solution by using the value coming from the listener. In my example below (for a ListPreference), I first get the index of the value in the ListPreference array, then I retrieve the label of the value using this index:
passwordFrequencyLP.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
int newFrequency = Integer.valueOf(newValue.toString());
prefs.edit().putInt("settings_key_password_frequency", newFrequency).commit();
//get the index of the new value selected in the ListPreference array
int index = passwordFrequencyLP.findIndexOfValue(String.valueOf(newValue));
//get the label of the new value selected
String label = (String) passwordFrequencyLP.getEntries()[index];
passwordFrequencyLP.setSummary(label);
makeToast(getResources().getString(R.string.password_frequency_saved));
return true;
}
});
This little trick works well, I found many different possible solutions to this problem but only this one worked for me.
Hi edited the above for EditText if that helps:)
package fr.bmigette.crocoschedulerconsoleandroid;
import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;
/**
* Created by bastien on 28/07/2015.
*/
public class EditTextPreferenceWithSummary extends EditTextPreference{
public EditTextPreferenceWithSummary(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextPreferenceWithSummary(Context context) {
super(context);
}
@Override
public void setText(String value) {
super.setText(value);
setSummary(value);
}
@Override
public void setSummary(CharSequence summary) {
super.setSummary(getText());
}
}
And creates the preference.xml like this:
<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >
<PreferenceCategory
android:key="pref_key_category_host"
android:title="@string/title_category_host" >
<fr.bmigette.crocoschedulerconsoleandroid.EditTextPreferenceWithSummary
android:defaultValue="@string/default_pref_host_1"
android:key="pref_key_host_1"
android:summary="@string/default_pref_host_1"
android:title="@string/title_pref_host_1" />
<fr.bmigette.crocoschedulerconsoleandroid.EditTextPreferenceWithSummary
android:defaultValue="@string/default_pref_port_1"
android:key="pref_key_port_1"
android:summary="@string/default_pref_port_1"
android:title="@string/title_pref_port_1" />
<fr.bmigette.crocoschedulerconsoleandroid.EditTextPreferenceWithSummary
android:defaultValue="@string/default_pref_pass_1"
android:key="pref_key_pass_1"
android:summary="@string/default_pref_pass_1"
android:title="@string/title_pref_pass_1" />
</PreferenceCategory>
</PreferenceScreen>
There is no need to do those extra coding, i have faced this problem and solved it by a single line.
After many hours looking on all the answers in this and other similar questions, i found out very easiest way to do this without extending ListPreference
, you can do it in common extends PreferenceActivity
, see the code bellow.
public class UserSettingsActivity extends PreferenceActivity
{
ListPreference listpref;
@Override
public void onCreate(Bundle savedInstenceState)
{
super.onCreate(savedInstenceState);
addPreferencesFromResource(R.xml.settings);
listpref = (ListPreference)findPreference("prefDefaultCurrency");
listpref.setOnPreferenceChangeListener(new OnPreferenceChangeListener()
{
@Override
public boolean onPreferenceChange(Preference preference, Object value) {
// TODO Auto-generated method stub
listpref.setSummary(listpref.getEntries()[Integer.parseInt(value.toString())]);
return true;
}
});
Thats it, with a single line, all you have to do is get value passed from the onPreferenceChange(Preference preference, Object value)
parse it to integer and pass it to listpref.setSummary(listpref.getEntries()[Integer.parseInt(value.toString())]);
Referring to the accepted answer ( @Michael ), if you modify the MyListPreference to add an onPreferenceChangeListener:
public MyListPreference(final Context context, final AttributeSet attrs) {
super(context, attrs);
setOnPreferenceChangeListener(this);
}
and have the listener implementation return true:
public boolean onPreferenceChange(Preference preference, Object newValue) {
// Do other stuff as needed, e.g. setTitle()
return true;
}
the summary '%s' always resolves to the latest setting. Otherwise, it always has the default setting.
Don't forget to add implements:
public class MyListPreference extends ListPreference implements Preference.OnPreferenceChangeListener
Simplest way in Kotlin
findPreference<ListPreference>(getString(R.string.pref_some_key)).apply {
summary = entry
setOnPreferenceChangeListener { _, newValue ->
summary = entries[entryValues.indexOf(newValue)]
return@setOnPreferenceChangeListener true
}
}
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.