Cela doit arriver très souvent.
Lorsque l'utilisateur modifie ses préférences dans une application Android, j'aimerais qu'il soit en mesure de voir la valeur actuellement définie de la préférence dans le résumé Preference
.
Exemple: si j’ai un paramètre Préférence pour "Supprimer les anciens messages" qui spécifie le nombre de jours après lequel les messages doivent être nettoyés. Dans la PreferenceActivity
, j'aimerais que l'utilisateur voie:
"Supprimer les anciens messages" <- titre
"Nettoyer les messages après x jours" <- récapitulatif où x est la valeur de préférence actuelle.
Crédit supplémentaire: permet de le réutiliser, afin que je puisse facilement l’appliquer à toutes mes préférences, quel que soit leur type (afin qu’il fonctionne avec EditTextPreference, ListPreference, etc. avec un minimum de codage).
Il existe des moyens de rendre cette solution plus générique, si cela convient à vos besoins.
Par exemple, si vous souhaitez que toutes les préférences de liste affichent leur choix sous forme de résumé, vous pouvez définir ceci pour votre implémentation onSharedPreferenceChanged
:
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
}
Ceci est facilement extensible à d'autres classes de préférence.
Et en utilisant les fonctionnalités getPreferenceCount
et getPreference
dans PreferenceScreen
et PreferenceCategory
, vous pouvez facilement écrire une fonction générique pour parcourir l’arbre des préférences en définissant les résumés de toutes les préférences des types souhaités avec leur représentation toString
Voici ma solution ... FWIW
package com.example.PrefTest;
import Android.content.SharedPreferences;
import Android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import Android.os.Bundle;
import Android.preference.EditTextPreference;
import Android.preference.ListPreference;
import Android.preference.Preference;
import Android.preference.PreferenceActivity;
import Android.preference.PreferenceGroup;
import Android.preference.PreferenceManager;
public class Preferences extends PreferenceActivity implements
OnSharedPreferenceChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
PreferenceManager.setDefaultValues(Preferences.this, R.xml.preferences,
false);
initSummary(getPreferenceScreen());
}
@Override
protected void onResume() {
super.onResume();
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPause() {
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences()
.unregisterOnSharedPreferenceChangeListener(this);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
String key) {
updatePrefSummary(findPreference(key));
}
private void initSummary(Preference p) {
if (p instanceof PreferenceGroup) {
PreferenceGroup pGrp = (PreferenceGroup) p;
for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
initSummary(pGrp.getPreference(i));
}
} else {
updatePrefSummary(p);
}
}
private void updatePrefSummary(Preference p) {
if (p instanceof ListPreference) {
ListPreference listPref = (ListPreference) p;
p.setSummary(listPref.getEntry());
}
if (p instanceof EditTextPreference) {
EditTextPreference editTextPref = (EditTextPreference) p;
if (p.getTitle().toString().toLowerCase().contains("password"))
{
p.setSummary("******");
} else {
p.setSummary(editTextPref.getText());
}
}
if (p instanceof MultiSelectListPreference) {
EditTextPreference editTextPref = (EditTextPreference) p;
p.setSummary(editTextPref.getText());
}
}
}
Android documentation indique que l’on peut utiliser un marqueur de formatage de chaîne dans getSummary()
:
Si le résumé contient un marqueur de formatage de chaîne (c'est-à-dire "% s" ou "% 1 $ s"), la valeur de l'entrée actuelle sera remplacée à la place.
Spécifier simplement Android:summary="Clean up messages after %s days"
dans la déclaration ListPreference xml a fonctionné pour moi.
Note: Ceci ne fonctionne que pour ListPreference
.
Si vous utilisez PreferenceFragment
, voici comment je l'ai résolu. C'est explicite.
public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onResume() {
super.onResume();
for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i) {
Preference preference = getPreferenceScreen().getPreference(i);
if (preference instanceof PreferenceGroup) {
PreferenceGroup preferenceGroup = (PreferenceGroup) preference;
for (int j = 0; j < preferenceGroup.getPreferenceCount(); ++j) {
Preference singlePref = preferenceGroup.getPreference(j);
updatePreference(singlePref, singlePref.getKey());
}
} else {
updatePreference(preference, preference.getKey());
}
}
}
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updatePreference(findPreference(key), key);
}
private void updatePreference(Preference preference, String key) {
if (preference == null) return;
if (preference instanceof ListPreference) {
ListPreference listPreference = (ListPreference) preference;
listPreference.setSummary(listPreference.getEntry());
return;
}
SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
preference.setSummary(sharedPrefs.getString(key, "Default"));
}
}
Mon option est d'étendre ListPreference et c'est propre:
public class ListPreferenceShowSummary extends ListPreference {
private final static String TAG = ListPreferenceShowSummary.class.getName();
public ListPreferenceShowSummary(Context context, AttributeSet attrs) {
super(context, attrs);
init();
}
public ListPreferenceShowSummary(Context context) {
super(context);
init();
}
private void init() {
setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference arg0, Object arg1) {
arg0.setSummary(getEntry());
return true;
}
});
}
@Override
public CharSequence getSummary() {
return super.getEntry();
}
}
Ensuite, vous ajoutez dans votre fichier settings.xml:
<yourpackage.ListPreferenceShowSummary
Android:key="key" Android:title="title"
Android:entries="@array/entries" Android:entryValues="@array/values"
Android:defaultValue="first value"/>
Vous pouvez remplacer les classes de préférence par défaut et implémenter la fonctionnalité.
public class MyListPreference extends ListPreference {
public MyListPreference(Context context) { super(context); }
public MyListPreference(Context context, AttributeSet attrs) { super(context, attrs); }
@Override
public void setValue(String value) {
super.setValue(value);
setSummary(getEntry());
}
}
Plus tard dans votre XML, vous pouvez utiliser les préférences personnalisées comme
<your.package.name.MyListPreference
Android:key="noteInterval"
Android:defaultValue="60"
Android:title="Notification Interval"
Android:entries="@array/noteInterval"
Android:entryValues="@array/noteIntervalValues"
/>
Après plusieurs heures passées à résoudre un tel problème, j'ai implémenté ce code:
[UPDATE: la liste de la version finale]
public class MyPreferencesActivity extends PreferenceActivity {
...
ListPreference m_updateList;
...
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
m_updateList = (ListPreference) findPreference(getString(R.string.pref_update_interval_key));
String currentValue = m_updateList.getValue();
if (currentValue == null) {
m_updateList.setValue((String)m_updateList.getEntryValues()[DEFAULT_UPDATE_TIME_INDEX]);
currentValue = m_updateList.getValue();
}
updateListSummary(currentValue);
m_updateList.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
updateListSummary(newValue.toString());
return true;
}
});
}
private void updateListSummary(String newValue) {
int index = m_updateList.findIndexOfValue(newValue);
CharSequence entry = m_updateList.getEntries()[index];
m_updateList.setSummary(entry);
}
}
C'était la seule solution qui a bien fonctionné pour moi. Avant, j'avais essayé de sous-classer à partir de ListPreferences et d'implémenter Android: summary = "bla bla bla% s". Ni travaillé.
Peut-être comme ListPreference: Modifiez getSummary pour obtenir ce que vous voulez:
package your.package.preference;
import Android.content.Context;
import Android.util.AttributeSet;
public class EditTextPreference extends Android.preference.EditTextPreference{
public EditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public EditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextPreference(Context context) {
super(context);
}
@Override
public CharSequence getSummary() {
if(super.getSummary() == null) return null;
String summary = super.getSummary().toString();
return String.format(summary, getText());
}
}
Et utilisez ceci dans votre XML:
<your.package.EditTextPreference
Android:key="pref_alpha"
Android:summary="Actual value: %s"
Android:title="Title"
Android:defaultValue="default"
/>
Vous pouvez donc écrire un résumé avec %s
au lieu de la valeur réelle.
C'est le code dont vous avez besoin pour définir le résumé à la valeur choisie. Il définit également les valeurs au démarrage et respecte les valeurs par défaut, pas seulement en cas de modification. Changez simplement "R.layout.prefs" dans votre fichier xml et étendez la méthode setSummary à vos besoins. En réalité, il s’agit uniquement de gérer les préférences de liste, mais il est facile de le personnaliser pour respecter les autres préférences.
package de.koem.timetunnel;
import Android.content.SharedPreferences;
import Android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import Android.os.Bundle;
import Android.preference.ListPreference;
import Android.preference.Preference;
import Android.preference.PreferenceActivity;
import Android.preference.PreferenceGroup;
public class Prefs
extends PreferenceActivity
implements OnSharedPreferenceChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
this.addPreferencesFromResource(R.layout.prefs);
this.initSummaries(this.getPreferenceScreen());
this.getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
/**
* Set the summaries of all preferences
*/
private void initSummaries(PreferenceGroup pg) {
for (int i = 0; i < pg.getPreferenceCount(); ++i) {
Preference p = pg.getPreference(i);
if (p instanceof PreferenceGroup)
this.initSummaries((PreferenceGroup) p); // recursion
else
this.setSummary(p);
}
}
/**
* Set the summaries of the given preference
*/
private void setSummary(Preference pref) {
// react on type or key
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
}
/**
* used to change the summary of a preference
*/
public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
Preference pref = findPreference(key);
this.setSummary(pref);
}
// private static final String LOGTAG = "Prefs";
}
koem
En fait, CheckBoxPreference a la possibilité de spécifier un résumé différent en fonction de la valeur de la case à cocher. Voir les attributs Android: summaryOff et Android: summaryOn (ainsi que les méthodes CheckBoxPreference correspondantes).
public class MyEditTextPreference extends EditTextPreference {
public MyEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
public MyEditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setText(String text) {
super.setText(text);
setSummary(text);
}
}
Si quelqu'un cherche toujours des réponses à cette question, vous devriez vérifier la réponse de trentethreeforty s.
<ListPreference
Android:key="pref_list"
Android:title="A list of preferences"
Android:summary="%s"
Android:entries="@array/pref_list_entries"
Android:entryValues="@array/pref_list_entries_values"
Android:defaultValue="0" />
Android remplacera% s par la valeur de chaîne actuelle de la préférence, telle qu'affichée par le sélecteur ListPreference.
Merci pour ce conseil!
J'ai un écran de préférences et je souhaite afficher la valeur de chaque préférence de liste sous forme de résumé.
C'est mon chemin maintenant:
public class Preferences extends PreferenceActivity implements OnSharedPreferenceChangeListener {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
protected void onResume() {
super.onResume();
// Set up initial values for all list preferences
Map<String, ?> sharedPreferencesMap = getPreferenceScreen().getSharedPreferences().getAll();
Preference pref;
ListPreference listPref;
for (Map.Entry<String, ?> entry : sharedPreferencesMap.entrySet()) {
pref = findPreference(entry.getKey());
if (pref instanceof ListPreference) {
listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
}
// Set up a listener whenever a key changes
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
protected void onPause() {
super.onPause();
// Unregister the listener whenever a key changes
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
Preference pref = findPreference(key);
if (pref instanceof ListPreference) {
ListPreference listPref = (ListPreference) pref;
pref.setSummary(listPref.getEntry());
}
}
Cela fonctionne pour moi, mais je me demande quelle est la meilleure solution (performances, stabilité, évolutivité): celle que Koem montre ou celle-ci?
Merci, Reto, pour l'explication détaillée!
Au cas où cela aiderait quelqu'un, je devais changer le code proposé par Reto Meier pour le faire fonctionner avec le SDK pour Android 1.5
@Override
protected void onResume() {
super.onResume();
// Setup the initial values
mListPreference.setSummary("Current value is " + mListPreference.getEntry().toString());
// Set up a listener whenever a key changes
...
}
Le même changement s'applique à la fonction de rappel onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)
À votre santé,
Chris
J'ai vu toutes les réponses votées montrer comment définir le résumé avec la valeur actuelle exacte, mais le PO voulait également quelque chose comme:
"Nettoyer les messages après x jours" * <- résumé où x est la valeur de préférence actuelle
Voici ma réponse pour y parvenir
Comme documentation dit à propos de ListPreference.getSummary()
:
Retourne le résumé de cette ListPreference. Si le résumé contient un marqueur de mise en forme de chaîne (c'est-à-dire "% s" ou "% 1 $ s"), alors le .__ actuel. la valeur d’entrée sera substituée à sa place.
Cependant, j'ai essayé plusieurs appareils et cela ne semble pas fonctionner. Après quelques recherches, j'ai trouvé une bonne solution dans cette réponse . Cela consiste simplement à étendre chaque Preference
utilisée et à remplacer getSummary()
pour fonctionner comme spécifié par la documentation Android.
J'ai résolu le problème avec le descendant suivant de ListPreference:
public class EnumPreference extends ListPreference {
public EnumPreference(Context aContext, AttributeSet attrs) {
super(aContext,attrs);
}
@Override
protected View onCreateView(ViewGroup parent) {
setSummary(getEntry());
return super.onCreateView(parent);
}
@Override
protected boolean persistString(String aNewValue) {
if (super.persistString(aNewValue)) {
setSummary(getEntry());
notifyChanged();
return true;
} else {
return false;
}
}
}
Semble fonctionner correctement pour moi dans 1.6 à 4.0.4.
public class ProfileManagement extends PreferenceActivity implements
OnPreferenceChangeListener {
EditTextPreference screenName;
ListPreference sex;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.layout.profile_management);
screenName = (EditTextPreference) findPreference("editTextPref");
sex = (ListPreference) findPreference("sexSelector");
screenName.setOnPreferenceChangeListener(this);
sex.setOnPreferenceChangeListener(this);
}
@Override
public boolean onPreferenceChange(Preference preference, Object newValue) {
preference.setSummary(newValue.toString());
return true;
}
}
Voici ma solution:
protected String getPreference(Preference x) {
// http://stackoverflow.com/questions/3993982/how-to-check-type-of-variable-in-Java
if (x instanceof CheckBoxPreference)
return "CheckBoxPreference";
else if (x instanceof EditTextPreference)
return "EditTextPreference";
else if (x instanceof ListPreference)
return "ListPreference";
else if (x instanceof MultiSelectListPreference)
return "MultiSelectListPreference";
else if (x instanceof RingtonePreference)
return "RingtonePreference";
else if (x instanceof SwitchPreference)
return "SwitchPreference";
else if (x instanceof TwoStatePreference)
return "TwoStatePreference";
else if (x instanceof DialogPreference) // Needs to be after ListPreference
return "DialogPreference";
else
return "undefined";
}
public void onSharedPreferenceChanged(SharedPreferences prefs, String key) {
Log.i(TAG, "+ onSharedPreferenceChanged(prefs:" + prefs + ", key:" + key + ")");
if( key != null ) {
updatePreference(prefs, key);
setSummary(key);
} else {
Log.e(TAG, "Preference without key!");
}
Log.i(TAG, "- onSharedPreferenceChanged()");
}
protected boolean setSummary() {
return _setSummary(null);
}
protected boolean setSummary(String sKey) {
return _setSummary(sKey);
}
private boolean _setSummary(String sKey) {
if (sKey == null) Log.i(TAG, "Initializing");
else Log.i(TAG, sKey);
// Get Preferences
SharedPreferences sharedPrefs = PreferenceManager
.getDefaultSharedPreferences(this);
// Iterate through all Shared Preferences
// http://stackoverflow.com/questions/9310479/how-to-iterate-through-all-keys-of-shared-preferences
Map<String, ?> keys = sharedPrefs.getAll();
for (Map.Entry<String, ?> entry : keys.entrySet()) {
String key = entry.getKey();
// Do work only if initializing (null) or updating specific preference key
if ( (sKey == null) || (sKey.equals(key)) ) {
String value = entry.getValue().toString();
Preference pref = findPreference(key);
String preference = getPreference(pref);
Log.d("map values", key + " | " + value + " | " + preference);
pref.setSummary(key + " | " + value + " | " + preference);
if (sKey != null) return true;
}
}
return false;
}
private void updatePreference(SharedPreferences prefs, String key) {
Log.i(TAG, "+ updatePreference(prefs:" + prefs + ", key:" + key + ")");
Preference pref = findPreference(key);
String preferenceType = getPreference(pref);
Log.i(TAG, "preferenceType = " + preferenceType);
Log.i(TAG, "- updatePreference()");
}
Créer une classe publique qui PreferenceActivity et implémenter OnSharedPreferenceChangeListener
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
PreferenceManager.setDefaultValues(this, R.xml.global_preferences,
false);
this.addPreferencesFromResource(R.xml.global_preferences);
this.getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
protected void onResume() {
super.onResume();
setSummary();
}
Simplement:
listPreference.setSummary("%s");
Si vous souhaitez uniquement afficher la valeur de texte brut de chaque champ sous forme de résumé, le code suivant devrait être le plus facile à gérer. Il ne nécessite que deux modifications (lignes 13 et 21, marquées par "change here"):
package com.my.package;
import Android.content.SharedPreferences;
import Android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import Android.os.Bundle;
import Android.preference.EditTextPreference;
import Android.preference.ListPreference;
import Android.preference.Preference;
import Android.preference.PreferenceActivity;
public class PreferencesActivity extends PreferenceActivity implements OnSharedPreferenceChangeListener {
private final String[] mAutoSummaryFields = { "pref_key1", "pref_key2", "pref_key3" }; // change here
private final int mEntryCount = mAutoSummaryFields.length;
private Preference[] mPreferenceEntries;
@SuppressWarnings("deprecation")
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences_file); // change here
mPreferenceEntries = new Preference[mEntryCount];
for (int i = 0; i < mEntryCount; i++) {
mPreferenceEntries[i] = getPreferenceScreen().findPreference(mAutoSummaryFields[i]);
}
}
@SuppressWarnings("deprecation")
@Override
protected void onResume() {
super.onResume();
for (int i = 0; i < mEntryCount; i++) {
updateSummary(mAutoSummaryFields[i]); // initialization
}
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this); // register change listener
}
@SuppressWarnings("deprecation")
@Override
protected void onPause() {
super.onPause();
getPreferenceScreen().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this); // unregister change listener
}
private void updateSummary(String key) {
for (int i = 0; i < mEntryCount; i++) {
if (key.equals(mAutoSummaryFields[i])) {
if (mPreferenceEntries[i] instanceof EditTextPreference) {
final EditTextPreference currentPreference = (EditTextPreference) mPreferenceEntries[i];
mPreferenceEntries[i].setSummary(currentPreference.getText());
}
else if (mPreferenceEntries[i] instanceof ListPreference) {
final ListPreference currentPreference = (ListPreference) mPreferenceEntries[i];
mPreferenceEntries[i].setSummary(currentPreference.getEntry());
}
break;
}
}
}
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updateSummary(key);
}
}
FYI:
findPreference(CharSequence key)
This method was deprecated in API level 11. This function is not relevant
for a modern fragment-based PreferenceActivity.
Raison de plus pour regarder la très variable Answer
de @ASD ci-dessus ( source trouvée ici ) disant d'utiliser %s
dans Android:summary
pour chaque champ dans preferences.xml
. (La valeur actuelle de la préférence est remplacée par %s
.)
<ListPreference
...
Android:summary="Length of longest Word to return as match is %s"
...
/>
Pour EditTextPreference :
Je suis venu à cette solution, bien sûr, juste si vous avez besoin de edittextpreference particulier mais vous pouvez le faire avec chaque préférence:
............
private static final String KEY_EDIT_TEXT_PREFERENCE2 = "on_a1";
public static String value = "";
............
private void updatePreference(Preference preference, String key) {
if (key.equals(KEY_EDIT_TEXT_PREFERENCE2)) {
preference = findPreference(key);
if (preference instanceof EditTextPreference) {
editTextPreference = (EditTextPreference) preference;
editTextPreference.setSummary(editTextPreference.getText());
value = editTextPreference.getText().toString();
return;
}
SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
preference.setSummary(sharedPrefs.getString(KEY_EDIT_TEXT_PREFERENCE2, ""));
}
}
Puis dans onResume ();
@Override
public void onResume() {
super.onResume();
SharedPreferences etext = getPreferenceManager().getSharedPreferences();
String str = etext.getString("value", "");
editTextPreference = (EditTextPreference) findPreference(KEY_EDIT_TEXT_PREFERENCE2);
editTextPreference.setText(str);
editTextPreference.setSummary(editTextPreference.getText());
getPreferenceScreen().getSharedPreferences()
.registerOnSharedPreferenceChangeListener(this);
}
Dans:
@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
updatePreference(findPreference(key), key);
}
Ici, tous ceux-ci sont extraits de l'exemple Eclipse SettingsActivity
. Je dois copier tous ces codes trop nombreux pour montrer comment ces développeurs Android choisissent parfaitement un style de code plus généralisé et stable ..__
J'ai laissé les codes pour adapter la PreferenceActivity
à la tablette et à une API supérieure.
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
setupSummaryUpdatablePreferencesScreen();
}
private void setupSummaryUpdatablePreferencesScreen() {
// In the simplified UI, fragments are not used at all and we instead
// use the older PreferenceActivity APIs.
// Add 'general' preferences.
addPreferencesFromResource(R.xml.pref_general);
// Bind the summaries of EditText/List/Dialog preferences to
// their values. When their values change, their summaries are updated
// to reflect the new value, per the Android Design guidelines.
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
/**
* A preference value change listener that updates the preference's summary
* to reflect its new value.
*/
private static Preference.OnPreferenceChangeListener sBindPreferenceSummaryToValueListener = new Preference.OnPreferenceChangeListener() {
private String TAG = SettingsActivity.class.getSimpleName();
@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);
} else {
// For all other preferences, set the summary to the value's
// simple string representation.
preference.setSummary(stringValue);
}
Log.i(TAG, "pref changed : " + preference.getKey() + " " + value);
return true;
}
};
/**
* Binds a preference's summary to its value. More specifically, when the
* preference's value is changed, its summary (line of text below the
* preference title) is updated to reflect the value. The summary is also
* immediately updated upon calling this method. The exact display format is
* dependent on the type of preference.
*
* @see #sBindPreferenceSummaryToValueListener
*/
private static void bindPreferenceSummaryToValue(Preference preference) {
// Set the listener to watch for value changes.
preference.setOnPreferenceChangeListener(sBindPreferenceSummaryToValueListener);
// Trigger the listener immediately with the preference's
// current value.
sBindPreferenceSummaryToValueListener.onPreferenceChange(preference,
PreferenceManager
.getDefaultSharedPreferences(preference.getContext())
.getString(preference.getKey(), ""));
}
}
xml/pref_general.xml
<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android" >
<!-- NOTE: EditTextPreference accepts EditText attributes. -->
<!-- NOTE: EditTextPreference's summary should be set to its value by the activity code. -->
<EditTextPreference
Android:capitalize="words"
Android:defaultValue="@string/pref_default_display_name"
Android:inputType="textCapWords"
Android:key="example_text"
Android:maxLines="1"
Android:selectAllOnFocus="true"
Android:singleLine="true"
Android:title="@string/pref_title_display_name" />
<!-- NOTE: Hide buttons to simplify the UI. Users can touch outside the dialog todismiss it.-->
<!-- NOTE: ListPreference's summary should be set to its value by the activity code. -->
<ListPreference
Android:defaultValue="-1"
Android:entries="@array/pref_example_list_titles"
Android:entryValues="@array/pref_example_list_values"
Android:key="example_list"
Android:negativeButtonText="@null"
Android:positiveButtonText="@null"
Android:title="@string/pref_title_add_friends_to_messages" />
</PreferenceScreen>
values/strings_activity_settings.xml
<resources>
<!-- Strings related to Settings -->
<!-- Example General settings -->
<string name="pref_title_display_name">Display name</string>
<string name="pref_default_display_name">John Smith</string>
<string name="pref_title_add_friends_to_messages">Add friends to messages</string>
<string-array name="pref_example_list_titles">
<item>Always</item>
<item>When possible</item>
<item>Never</item>
</string-array>
<string-array name="pref_example_list_values">
<item>1</item>
<item>0</item>
<item>-1</item>
</string-array>
</resources>
NOTE: En fait, je voudrais juste commenter comme "L’échantillon de Google pour PreferenceActivity est également intéressant". Mais je n'ai pas assez de points de réputation. Alors, s'il vous plaît, ne m'en voulez pas.
(Désolé pour mon mauvais anglais)
Vous devez utiliser la fonction bindPreferenceSummaryToValue sur la méthode onCreate.
Exemple:
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Add 'general' preferences, defined in the XML file
addPreferencesFromResource(R.xml.pref_general);
// For all preferences, attach an OnPreferenceChangeListener so the UI summary can be
// updated when the preference changes.
bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_location_key)));
bindPreferenceSummaryToValue(findPreference(getString(R.string.pref_units_key)));
}
Voir la leçon 3 sur Udacity Android Course: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601
Ma solution est de créer une EditTextPreference
personnalisée, utilisée en XML comme ceci: <com.example.EditTextPreference Android:title="Example Title" />
EditTextPreference.Java : -
package com.example;
import Android.content.Context;
import Android.util.AttributeSet;
public class EditTextPreference extends Android.preference.EditTextPreference
{
public EditTextPreference(Context context, AttributeSet attrs, int defStyle)
{
super(context, attrs, defStyle);
}
public EditTextPreference(Context context, AttributeSet attrs)
{
super(context, attrs);
}
public EditTextPreference(Context context)
{
super(context, null);
}
@Override
protected void onDialogClosed(boolean positiveResult)
{
super.onDialogClosed(positiveResult);
setSummary(getSummary());
}
@Override
public CharSequence getSummary()
{
return getText();
}
}
Comme dans androidx, la classe Preference possède l'interface SummaryProvider , vous pouvez le faire sans OnSharedPreferenceChangeListener. Des implémentations simples sont fournies pour EditTextPreference et ListPreference. S'appuyant sur La réponse d'EddieB peut ressembler à ceci. Testé sur androidx.preference: préférence: 1.1.0-alpha03.
package com.example.util.timereminder.ui.prefs;
import Android.os.Bundle;
import com.example.util.timereminder.R;
import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;
/**
* Displays different preferences.
*/
public class PrefsFragmentExample extends PreferenceFragmentCompat {
@Override
public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
addPreferencesFromResource(R.xml.preferences);
initSummary(getPreferenceScreen());
}
/**
* Walks through all preferences.
*
* @param p The starting preference to search from.
*/
private void initSummary(Preference p) {
if (p instanceof PreferenceGroup) {
PreferenceGroup pGrp = (PreferenceGroup) p;
for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
initSummary(pGrp.getPreference(i));
}
} else {
setPreferenceSummary(p);
}
}
/**
* Sets up summary providers for the preferences.
*
* @param p The preference to set up summary provider.
*/
private void setPreferenceSummary(Preference p) {
// No need to set up preference summaries for checkbox preferences because
// they can be set up in xml using summaryOff and summary On
if (p instanceof ListPreference) {
p.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
} else if (p instanceof EditTextPreference) {
p.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
}
}
}
Étant donné que j'utilise une variable PreferenceDataStore
personnalisée, je ne peux pas ajouter d'auditeur à une variable SharedPreference
et j'ai donc dû écrire une solution quelque peu compliquée qui écoute chaque préférence
class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
private val handler: Handler by lazy { Handler(Looper.getMainLooper()) }
override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
preferenceManager.preferenceDataStore = prefs
addPreferencesFromResource(R.xml.app_preferences)
onPreferenceChange(preferenceScreen, null)
}
override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
preference.onPreferenceChangeListener = this
when (preference) {
is PreferenceGroup -> for (i in 0 until preference.preferenceCount) {
onPreferenceChange(preference.getPreference(i), null)
}
is ListPreference -> {
if (preference.value == null) {
preference.isPersistent = false
preference.value = Preference::class.Java.getDeclaredField("mDefaultValue")
.apply { isAccessible = true }
.get(preference).toString()
preference.isPersistent = true
}
postPreferenceUpdate(Runnable { preference.summary = preference.entry })
}
}
return true
}
/**
* We can't directly update the preference summary update because [onPreferenceChange]'s result
* is used to decide whether or not to update the pref value.
*/
private fun postPreferenceUpdate(r: Runnable) = handler.post(r)
}
Pour définir le récapitulatif d'une ListPreference
sur la valeur sélectionnée dans une boîte de dialogue, vous pouvez utiliser ce code:
package yourpackage;
import Android.content.Context;
import Android.util.AttributeSet;
public class ListPreference extends Android.preference.ListPreference {
public ListPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
protected void onDialogClosed(boolean positiveResult) {
super.onDialogClosed(positiveResult);
if (positiveResult) setSummary(getEntry());
}
protected void onSetInitialValue(boolean restoreValue, Object defaultValue) {
super.onSetInitialValue(restoreValue, defaultValue);
setSummary(getEntry());
}
}
et référencez l'objet yourpackage.ListPreference
dans votre preferences.xml
en vous rappelant d'y spécifier votre Android:defaultValue
car cela déclenche l'appel à onSetInitialValue()
.
Si vous le souhaitez, vous pouvez modifier le texte avant d'appeler setSummary()
pour l'adapter à votre application.
Selon docs Android , vous pouvez utiliser app:useSimpleSummaryProvider="true"
dans les composants ListPreference et EditTextPreference.
Si vous utilisez AndroidX, vous pouvez utiliser une SummaryProvider
personnalisée. Cette approche peut être utilisée pour toute variable Preference
.
Exemple de documentation (Java):
EditTextPreference countingPreference = (EditTextPreference) findPreference("counting");
countingPreference.setSummaryProvider(new SummaryProvider<EditTextPreference>() {
@Override
public CharSequence provideSummary(EditTextPreference preference) {
String text = preference.getText();
if (TextUtils.isEmpty(text)){
return "Not set";
}
return "Length of saved value: " + text.length();
}
});
Exemple de documentation (Kotlin):
val countingPreference = findPreference("counting") as EditTextPreference
countingPreference.summaryProvider = SummaryProvider<EditTextPreference> { preference ->
val text = preference.text
if (TextUtils.isEmpty(text)) {
"Not set"
} else {
"Length of saved value: " + text.length
}
}
J'ai trouvé cette méthode pour rendre EditTextPreference
à partir de la bibliothèque de support gérer le "%s"
en résumé (comme ListPreference
le gère déjà):
public class EditTextPreference extends Android.support.v7.preference.EditTextPreference {
public EditTextPreference(Context context, AttributeSet attrs) {
super(context, attrs);
}
@Override
public void setText(String text) {
super.setText(text);
notifyChanged();
}
@Override
public CharSequence getSummary() {
String text = super.getText();
String summary = super.getSummary().toString();
return String.format(summary, text == null ? "" : text);
}
}
En XML, cela ressemblera à ceci:
<com.example.yourapp.EditTextPreference
Android:defaultValue="1"
Android:key="cleanup_period"
Android:summary="Clean up messages after %s days"
Android:title="Clean up period" />
Voici une solution opérationnelle pour tous les EditTextPreference
s à l'intérieur d'un PreferenceFragment
basé sur la réponse @tdeveaux:
public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
private static final String TAG = "SettingsFragment";
@Override
public void onCreate (Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
}
@Override
public void onResume () {
super.onResume();
for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i) {
Preference preference = getPreferenceScreen().getPreference(i);
updatePreference(preference);
}
}
@Override
public void onSharedPreferenceChanged (SharedPreferences sharedPreferences, String key) {
updatePreference(findPreference(key));
}
private void updatePreference (Preference preference) {
if (preference instanceof EditTextPreference) {
EditTextPreference editTextPreference = (EditTextPreference)preference;
editTextPreference.setSummary(editTextPreference.getText());
}
}
}