Comment afficher la valeur actuelle d'une préférence Android dans le résumé des préférences?

457

Cela doit arriver très souvent.

Lorsque l'utilisateur modifie les préférences dans une application Android, j'aimerais qu'il puisse voir la valeur actuellement définie de la préférence dans le Preferencerésumé.

Exemple: si j'ai un paramètre de préférence pour "Supprimer les anciens messages" qui spécifie le nombre de jours après lesquels les messages doivent être nettoyés. Dans le PreferenceActivityJ'aimerais que l'utilisateur voie:

"Supprimer les anciens messages" <- title

"Nettoyer les messages après x jours" <- résuméx est la valeur de préférence actuelle

Crédit supplémentaire: rendez-le réutilisable, afin que je puisse facilement l'appliquer à toutes mes préférences, quel que soit leur type (pour qu'il fonctionne avec EditTextPreference, ListPreference, etc. avec un minimum de codage).

nyenyec
la source

Réponses:

151

Il existe des moyens d'en faire une 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 avoir ceci pour votre onSharedPreferenceChangedimplémentation:

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 getPreferenceCountet getPreferencedans PreferenceScreenet PreferenceCategory, vous pouvez facilement écrire une fonction générique pour parcourir l'arborescence des préférences en définissant les résumés de toutes les préférences des types que vous souhaitez sur leur toStringreprésentation

DozenCrows
la source
6
belle solution en effet. ne manque qu'une initialisation
njzk2
9
@ njzk2 tout ce que vous avez à faire est de vous assurer que l'activitéimplements OnSharedPreferenceChangeListener
4
NB: Il existe un moyen plus simple, voir la réponse de @ Robertas .
Salman von Abbas
6
En fait, vous pouvez définir sommaire "%s"pour ListPreferenceet ListPreference.getSummary()formaterez le résumé avec l'entrée en cours sélectionné (ou ""si aucun sélectionné).
SOFe
findPreference (clé) est obsolète, existe-t-il un autre moyen d'y accéder?
Nevermore
144

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());
        }
    }
}
EddieB
la source
Cela fonctionne très bien @EddieB ... sauf que j'ai un écran de préférence dans un écran de préférence. Avez-vous une idée de comment accéder à l'écran de préférence interne et remplir ceux avec un résumé?
taraloca
@taraloca - change if (p instanceof PreferenceCategory) {PreferenceCategory pCat = (PreferenceCategory) p; à if (p instanceof PreferenceGroup) {final PreferenceGroup pCat = (PreferenceGroup) p;
Martin Ždila
Cela fonctionne grand si EditTextPreferenceest android:password="true" elle montre la valeur
Chathura Wijesinghe
1
Comment dois-je modifier le code pour afficher le résumé du fichier de ressources (xml) si aucune valeur n'est définie (c.-à-d. if editTextPref.getText() == "")? Comment obtenir une valeur récapitulative à updatePrefSummary? p.getSummary()et editTextPref.getSummary()retourner des valeurs déjà modifiées.
LA_
Depuis les deux PreferenceCategoryet PreferenceScreenhéritant de PreferenceGroup, j'ai changé initSummarypour gérer un à la PreferenceGroupplace. Cela évite le besoin d'une autre boucle onCreate(). Changement de comportement: les PreferenceScreens imbriqués sont désormais également gérés de manière récursive.
Lekensteyn
96

La documentation Android 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 d'entrée actuelle sera remplacée à sa place.

android:summary="Clean up messages after %s days"Spécifier simplement dans la déclaration XML ListPreference a fonctionné pour moi.

Remarque: cela ne fonctionne que pour ListPreference.

Robertas
la source
Quelqu'un me corrige si je me trompe, mais la documentation de getSummary () indique qu'il a été ajouté au niveau 1 de l'API. Voulez-vous dire que le comportement était différent lors de sa première publication?
TheIT
10
Malheureusement, cela ne fonctionne que pour ListPreference. Je veux le même comportement pour EditTextPreference. Il est surprenant que Google n'ait pas ajouté cela pour toutes les DialogPreferences.
Vicki
2
De plus, je ne travaille pas tant que la valeur n'a pas été définie - lors du premier appel de l'activité Préférence, elle affiche uniquement% s, ce qui est vraiment stupide.
Zordid
3
@Zordid Cela peut être corrigé en spécifiant la valeur par défaut dans votre xml comme android:defaultValue="0"dans votre ListPreference. Ceci est la réponse la plus sensée et fonctionne pour moi.
Mohit Singh
@Mohit Singh / @Zordid, sur Lollipop API 22, le defaultValueet le %sne fonctionnent pas. Sur les autres versions, cela fonctionne généralement. Une solution s'il vous plait? Je ne veux certainement pas écrire une classe personnalisée pour cela. Incroyable que Google rend la tâche la plus triviale aussi pénible.
Narayana J
81

Si vous utilisez PreferenceFragment, c'est comme ça que 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"));
    }
  }
tdevaux
la source
3
Cette solution a besoin de plus de votes ... Cela me dérange que les exemples sur le site du développeur MONTRENT cela, mais omettez-le complètement.
Justin Smith
3
Pour que EditTextPreferences soit également mis à jour, ajoutez ceci à updatePreferenceCODE if (preference instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText()); }merci @EddieB
Eugene van der Merwe
6
Où appelez-vous unregisterOnSharedPreferenceChangeListener?
CAMOBAP du
1
findPreference(CharSequence key) This method was deprecated in API level 11. This function is not relevant for a modern fragment-based PreferenceActivity.
DSlomer64
2
@ DSlomer64 Je suis bien conscient de ce que vous citez. Cela vous dit de ne pas utiliser PreferenceActivity.findPreference(et plusieurs autres méthodes), car Google veut que vous passiez à la technique indiquée dans cette réponse, qui utilise à la PreferenceFragment.findPreferenceplace.
Dan Hulme
33

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 settings.xml:

<yourpackage.ListPreferenceShowSummary
    android:key="key" android:title="title"
    android:entries="@array/entries" android:entryValues="@array/values"
    android:defaultValue="first value"/>
Youyougoslave
la source
J'ai fait une solution basée sur cela. Dans ma solution, j'ai une méthode pour définir un tableau de entrySummaries au lieu d'utiliser les chaînes d'entrées dans le menu et les résumés. Il y a un problème ici: getEntry () renvoie la valeur précédente et non la nouvelle.
pzulw
1
En fait, init () est-il même nécessaire? Je viens de remplacer getSummary () et cela semble fonctionner parfaitement!
Andy
4
Semble une solution beaucoup plus facile et plus propre que la plus votée!
muslidrikk
2
La init()fonction est nécessaire pour mettre à jour le summarylorsque l'utilisateur modifie cette préférence. Sans cela, il restera simplement quelle que soit l'entrée au départ.
anthonylawson
23

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 des 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"
    />
Palani
la source
Excellente méthode simple. Faites juste attention aux choses comme% dans la chaîne getEntry car elles pourraient causer des problèmes (ou elles l'ont fait pour moi)
Andrew
21

Après plusieurs heures passées à résoudre un tel problème, j'ai implémenté ce code:

[MISE À JOUR: la liste des versions finales]

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 fonctionnait bien pour moi. Avant, j'ai essayé de sous-classer ListPreferences et d'implémenter android: summary = "bla bla bla% s". Aucun n'a fonctionné.

Renard subtil
la source
Votre chemin est plus clair et utilise moins de code que les autres. Les meilleures réponses fonctionnent en utilisant "proxy" - gestionnaire de préférences. Ce n'est pas aussi clair que d'écouter les changements directs dans la liste.
Paul Annekov
@Subtle Fox, solution soignée. juste curieux si vous avez fait 'setDefaultValue ()' alors pourquoi vérifier (ss == null)
Samuel
Parce que setDefaultValue () ne devrait pas être là :) J'ai mis ce code avant le refactoring
Subtle Fox
20

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 %sau lieu de la valeur réelle.

Eruvanos
la source
1
@Eruvanos @ serv-inc Au moins avec une sous-classe de android.support.v7.preference.EditTextPreference, cela ne met pas à jour le résumé lorsque la préférence est modifiée, uniquement lorsque l'activité des préférences est créée. Un moyen de contourner cela sans implémenter OnSharedPreferenceChangeListener.onSharedPreferenceChangeddans la classe de fragment de préférences est de surcharger également android.support.v7.preference.EditTextPreference.setText(String text):@Override public void setText(String text) { super.setText(text); this.setSummary(this.getText()); }
PointedEars
@PointedEars: terminé. Mais cela semble également être une copie de stackoverflow.com/a/21906829/1587329
serv-inc
18

Il s'agit du code dont vous avez besoin pour définir le résumé sur la valeur choisie. Il définit également les valeurs au démarrage et respecte les valeurs par défaut, non seulement au changement. Modifiez simplement "R.layout.prefs" dans votre fichier xml et étendez la méthode setSummary à vos besoins. En fait, il ne gère que ListPreferences, mais il est facile à 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

Koem
la source
Merci beaucoup! J'ai créé une classe à partir de cela, en donnant l'ID de ressource comme argument à onCreate () - de cette façon, c'était une modification d'une ligne à mes écrans de paramètres pour qu'ils affichent les valeurs en résumé.
Asmo Soinio
2
BTW: Notez que les préférences non persistantes ne seront pas mises à jour en utilisant ce système. Les modifications doivent être écoutées à l'aide de la setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)méthode des préférences individuelles.
Asmo Soinio
11

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).

dhaag23
la source
11

Pour EditTextPreference:

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);
    }
}
lordmegamax
la source
9

Si quelqu'un cherche toujours des réponses à cette question, vous devriez vérifier la réponse de trente-trois ans .

<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.

Irritateur
la source
Travaux. C'est la solution la plus simple et la meilleure aujourd'hui.
davidgyoung
1
Notez que le "% s" peut être placé n'importe où dans votre chaîne de résumé. Et oui, cela inclut les chaînes de ressources!
Scott Biggs
7

Merci pour cette astuce!

J'ai un écran de préférence et je souhaite afficher la valeur de chaque préférence de liste comme résumé.

C'est ma voie 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?

alexx
la source
6

Merci, Reto, pour l'explication détaillée!

Au cas où cela serait utile à quiconque, j'ai dû 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

Chris
la source
4

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 bien fonctionner pour moi dans 1.6 jusqu'à 4.0.4.

Oncle Code Monkey
la source
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;
    }
}
GalkinAndrew
la source
4

J'ai vu toutes les réponses votées montrer comment définir le résumé avec la valeur actuelle exacte, mais l'OP 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 le dit la documentation sur ListPreference.getSummary():

Renvoie le résumé de ce ListPreference. Si le résumé contient un marqueur de formatage de chaîne (c'est-à-dire "% s" ou "% 1 $ s"), la valeur d'entrée actuelle sera remplacée à sa place.

Cependant, j'ai essayé sur plusieurs appareils et cela ne semble pas fonctionner. Avec quelques recherches, j'ai trouvé une bonne solution dans cette réponse . Il consiste simplement à étendre tout ce que Preferencevous utilisez et à remplacer getSummary()pour qu'il fonctionne comme spécifié par la documentation Android.

Christian García
la source
1
Cela semble fonctionner initialement, mais lorsque vous choisissez une nouvelle valeur, elle ne se met pas à jour automatiquement tant que vous n'avez pas fait quelque chose pour invalider toute l'activité et la faire redessiner. Je suis sur Android 4.0.4.
eidylon
Ce serait bien si Google pouvait ajouter une chaîne de mise en forme à l'objet de préférence.
Justin Smith
3

Si vous souhaitez uniquement afficher la valeur en texte brut de chaque champ comme résumé, le code suivant doit être le plus facile à gérer. Il ne nécessite que deux modifications (lignes 13 et 21, marquées "changer ici"):

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);
    }

}
croasser
la source
3

Voici ma solution:

Construisez une méthode de type getter de préférence.

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";
}

Créez une méthode 'setSummaryInit'.

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()");
    }

Initialiser

Créer une classe publique qui PreferenceActivity et implémente 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();
}
Page2PagePro
la source
3

Simplement:

listPreference.setSummary("%s");
Breed Oded
la source
3

Pour info:

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 le très lisse Answerde @ASD ci-dessus ( source trouvée ici ) disant d'utiliser %sin android:summarypour chaque champ dans preferences.xml. (La valeur actuelle de préférence est remplacée %s.)

entrez la description de l'image ici

<ListPreference
 ...        
 android:summary="Length of longest word to return as match is %s"
 ...
 />
DSlomer64
la source
3

Étant donné que dans la classe de préférences androidx a l' interface SummaryProvider , cela peut être fait sans OnSharedPreferenceChangeListener. Des implémentations simples sont fournies pour EditTextPreference et ListPreference. En s'appuyant sur la réponse d'EddieB, cela 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());
        }
    }
}
Razeeman
la source
3

Selon les documents Android, vous pouvez utiliser les app:useSimpleSummaryProvider="true"composants ListPreference et EditTextPreference.

alishir
la source
2

Ici, tous ceux-ci sont coupés de l'échantillon Eclipse SettingsActivity . Je dois copier tous ces codes trop pour montrer comment ces développeurs Android choisissent parfaitement pour un style de codage plus généralisé et plus stable.

J'ai laissé les codes pour l'adaptation PreferenceActivityà la tablette et à une plus grande API.

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>

REMARQUE: En fait, je veux juste commenter comme "l'exemple de Google pour PreferenceActivity est également intéressant". Mais je n'ai pas assez de points de réputation, alors ne m'en voulez pas.

(Désolé pour mon mauvais anglais)

johnkarka
la source
2

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 le cours Udacity Android: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601

Pablo
la source
2

Pour EditTextPreference :

Je suis venu à cette solution, bien sûr, juste si vous avez besoin d'une edittextpreference particulière, 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);
}
Stanojkovic
la source
2

Ma solution est de créer un custom EditTextPreference, utilisé 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();
    }
}
Salman von Abbas
la source
1

Pour définir le résumé de a ListPreferencesur 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' yourpackage.ListPreferenceobjet dans votre preferences.xmlmémoire pour y spécifier votre android:defaultValuecar cela déclenche l'appel à onSetInitialValue().

Si vous le souhaitez, vous pouvez ensuite modifier le texte avant d'appeler setSummary()ce qui convient à votre application.

gicci
la source
1

Parce que j'utilise une coutume PreferenceDataStore , je ne peux pas ajouter d'écouteur à certains SharedPreference, j'ai donc dû écrire une solution quelque peu hacky 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)
}
SUPERCILEX
la source
1

Si vous utilisez AndroidX, vous pouvez utiliser une personnalisationSummaryProvider . Cette approche peut être utilisée pour tout 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
    }
}
Andrew Churilo
la source