Come posso visualizzare il valore corrente di una preferenza Android nel Riepilogo preferenze?


457

Questo deve venire molto spesso.

Quando l'utente modifica le preferenze in un'app Android, vorrei che fossero in grado di vedere il valore della preferenza attualmente impostato nel Preferenceriepilogo.

Esempio: se ho un'impostazione Preferenza per "Elimina vecchi messaggi" che specifica il numero di giorni dopo i quali è necessario ripulire i messaggi. Nel PreferenceActivityvorrei che l'utente vedesse:

"Elimina i vecchi messaggi" <- titolo

"Elimina i messaggi dopo x giorni" <- riepilogo in cui x è il valore di preferenza corrente

Credito extra: rendilo riutilizzabile, così posso facilmente applicarlo a tutte le mie preferenze indipendentemente dal loro tipo (in modo che funzioni con EditTextPreference, ListPreference ecc. Con una quantità minima di codifica).

Risposte:


151

Ci sono modi per rendere questa una soluzione più generica, se soddisfa le tue esigenze.

Ad esempio, se si desidera che tutte le preferenze dell'elenco mostrino la loro scelta come riepilogo, è possibile disporre di questo per l' onSharedPreferenceChangedimplementazione:

public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    Preference pref = findPreference(key);

    if (pref instanceof ListPreference) {
        ListPreference listPref = (ListPreference) pref;
        pref.setSummary(listPref.getEntry());
    }
}

Questo è facilmente estendibile ad altre classi di preferenze.

E usando le funzionalità getPreferenceCounte getPreferencein PreferenceScreene PreferenceCategory, potresti facilmente scrivere una funzione generica per camminare nell'albero delle preferenze impostando i riepiloghi di tutte le preferenze dei tipi che desideri per la loro toStringrappresentazione


6
bella soluzione davvero. manca solo un'inizializzazione
njzk2

9
@ njzk2 tutto quello che devi fare è assicurarti che l'attivitàimplements OnSharedPreferenceChangeListener

4
NB: C'è un modo più semplice, vedi la risposta di @ Robertas .
Salman von Abbas,

6
In realtà, è possibile impostare il riepilogo su "%s"per ListPreferencee ListPreference.getSummary()formattare il riepilogo con la voce corrente selezionata (o ""se nessuna selezionata).
SOF

findPreference (key) è obsoleto, esiste un altro modo per accedervi?
Mai più il

144

Ecco la mia soluzione ... 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());
        }
    }
}

Questo funziona alla grande @EddieB ... tranne per il fatto che ho una schermata delle preferenze all'interno di una schermata delle preferenze. Qualche idea su come raggiungere la schermata delle preferenze interne e popolare quelle con un riepilogo?
Taraloca,

@taraloca - cambia if (p instanceof PreferenceCategory) {PreferenceCategory pCat = (PreferenceCategory) p; a if (p instanceof PreferenceGroup) {final PreferenceGroup pCat = (PreferenceGroup) p;
Martin Ždila,

questa grande sta lavorando che cosa se EditTextPreferenceè android:password="true" esso mostra il valore
Chathura Wijesinghe

1
Come devo modificare il codice per visualizzare il riepilogo dal file di risorse (xml) se non viene definito alcun valore (cioè if editTextPref.getText() == "")? Come ottenere il valore di riepilogo in updatePrefSummary? p.getSummary()e editTextPref.getSummary()restituisce valori già modificati.
LA_

Dal momento che entrambi PreferenceCategoryed PreferenceScreenereditare da PreferenceGroup, ho cambiato initSummaryper gestire un PreferenceGroupinvece. Questo evita la necessità di un altro loop in onCreate(). Cambiamenti nel comportamento: PreferenceScreens nidificati ora viene gestito anche in modo ricorsivo.
Lekensteyn,

96

La documentazione di Android afferma che è possibile utilizzare un marcatore di formattazione String in getSummary():

Se il riepilogo contiene un marcatore di formattazione String (ovvero "% s" o "% 1 $ s"), al suo posto verrà sostituito il valore della voce corrente.

Semplicemente specificando android:summary="Clean up messages after %s days"nella dichiarazione xml di ListPreference ha funzionato per me.

Nota: funziona solo per ListPreference.


Qualcuno mi correggerà se sbaglio, ma la documentazione per getSummary () afferma che è stato aggiunto nel livello API 1. Stai sottintendendo che il comportamento era diverso al primo rilascio?
TheIT

10
Sfortunatamente, questo funziona solo per ListPreference. Voglio lo stesso comportamento per EditTextPreference. È sorprendente che Google non l'abbia aggiunto per tutte le DialogPreferences.
Vicki,

2
Inoltre, non lavoro fintanto che il valore non è stato impostato: alla prima chiamata in assoluto dell'attività Preferenza, visualizza solo% s che è davvero stupido.
Zordid,

3
@Zordid Che può essere risolto specificando il valore predefinito nel tuo XML come android:defaultValue="0"in ListPreference. Questa è la risposta più sensata e funziona per me.
Mohit Singh,

@Mohit Singh / @Zordid, su Lollipop API 22, il defaultValuee il %snon funzionano. Su altre versioni, generalmente, funziona comunque. Qualche soluzione per favore? Non voglio scrivere una classe personalizzata per questo. Incredibile che Google renda i compiti più banali un tale dolore.
Narayana J,

81

Se lo usi PreferenceFragment, è così che l'ho risolto. È autoesplicativo.

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

3
Questa soluzione ha bisogno di più voti ... Mi dà fastidio che gli esempi sul sito degli sviluppatori MOSTRANO questo fatto, ma lo ometto completamente.
Justin Smith,

3
Per ottenere EditTextPreferences anche aggiornato aggiungilo a updatePreferenceCODE if (preference instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText()); }grazie @EddieB
Eugene van der Merwe

6
Dove chiami unregisterOnSharedPreferenceChangeListener?
CAMOBAP,

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 Sono ben consapevole di ciò che stai citando. Ti sta dicendo di non usare PreferenceActivity.findPreference(e molti altri metodi), perché Google vuole che passi alla tecnica mostrata in questa risposta, che usa PreferenceFragment.findPreferenceinvece.
Dan Hulme,

33

La mia opzione è estendere ListPreference ed è pulito:

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

Quindi aggiungi il tuo settings.xml:

<yourpackage.ListPreferenceShowSummary
    android:key="key" android:title="title"
    android:entries="@array/entries" android:entryValues="@array/values"
    android:defaultValue="first value"/>

Ho fatto una soluzione basata su questo. Nella mia soluzione ho un metodo per impostare una matrice di entrySummaries invece di utilizzare le stringhe di voci sia nel menu che nei riepiloghi. C'è un problema qui: getEntry () restituisce il valore precedente non quello nuovo.
pzulw,

1
In realtà init () è addirittura necessario? Ho appena nascosto getSummary () e sembra funzionare perfettamente!
Andy,

4
Sembra una soluzione molto più semplice e pulita di quella più votata!
muslidrikk,

2
La init()funzione è necessaria per aggiornare il summarymomento in cui l'utente modifica tale preferenza. Senza di essa, rimarrà semplicemente qualunque sia la voce inizialmente.
anthonylawson,

23

È possibile ignorare le classi di preferenze predefinite e implementare la funzione.

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

Più avanti nel tuo XML puoi usare preferenze personalizzate come

<your.package.name.MyListPreference 
    android:key="noteInterval"
    android:defaultValue="60"
    android:title="Notification Interval"
    android:entries="@array/noteInterval"
    android:entryValues="@array/noteIntervalValues"
    />

Eccellente metodo semplice. Fai attenzione a cose come% nella stringa getEntry in quanto potrebbero causare problemi (o lo hanno fatto per me)
Andrew

21

Dopo diverse ore sono stato speso per risolvere questo problema e ho implementato questo codice:

[AGGIORNAMENTO: l'elenco della versione 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);
    }
}

Questa è stata l'unica soluzione che ha funzionato bene per me. Prima ho provato a sottoclassare da ListPreferences e implementare android: summary = "bla bla bla% s". Né ha funzionato.


La tua strada è più chiara e usa meno codice di altri. Le risposte migliori funzionano usando "proxy" - gestore delle preferenze. Non è così chiaro come ascoltare i cambiamenti diretti nella lista.
Paul Annekov,

@Subtle Fox, soluzione pulita. solo curioso di sapere se hai impostato 'setDefaultValue ()', quindi perché controllare (ss == null)
Samuel

Perché setDefaultValue () non dovrebbe essere lì :) Ho inserito questo codice prima del refactoring
Fox sottile

20

Forse come ListPreference: modifica getSummary per ottenere ciò che desideri:

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

E usa questo nel tuo XML:

<your.package.EditTextPreference
                android:key="pref_alpha"
                android:summary="Actual value: %s"
                android:title="Title"
                android:defaultValue="default"
                />

Quindi sei in grado di scrivere un riepilogo con %sinvece del valore effettivo.


1
@Eruvanos @ serv-inc Almeno con una sottoclasse di android.support.v7.preference.EditTextPreference, questo non aggiorna il riepilogo quando viene modificata la preferenza, solo quando viene creata l'attività delle preferenze. Un modo per aggirare questo problema senza implementare OnSharedPreferenceChangeListener.onSharedPreferenceChangednella classe del frammento delle preferenze è anche quello di sovrascrivere android.support.v7.preference.EditTextPreference.setText(String text):@Override public void setText(String text) { super.setText(text); this.setSummary(this.getText()); }
Pointed Ears

@PointedEars: fatto. Ma anche questa sembra essere una copia di stackoverflow.com/a/21906829/1587329
serv-inc,

18

Questo è il codice necessario per impostare il riepilogo sul valore scelto. Imposta inoltre i valori all'avvio e rispetta i valori predefiniti, non solo in caso di modifica. Basta cambiare "R.layout.prefs" nel file xml ed estendere il metodo setSummary alle proprie esigenze. In realtà gestisce solo ListPreferences, ma è facile da personalizzare per rispettare le altre preferenze.

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


Molte grazie! Ho creato una classe da questo, fornendo l'ID risorsa come argomento a onCreate () - in questo modo è stata una modifica di una riga alle schermate delle mie impostazioni per far sì che mostrassero i valori in sintesi.
Asmo Soinio,

2
A proposito: si noti che le preferenze non persistenti non verranno aggiornate utilizzando questo sistema. Le modifiche ad esse devono essere ascoltate usando il setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)metodo delle singole Preferenze.
Asmo Soinio,

11

In realtà, CheckBoxPreference ha la possibilità di specificare un riepilogo diverso in base al valore della casella di controllo. Vedi gli attributi android: summaryOff e android: summaryOn (così come i corrispondenti metodi CheckBoxPreference).


11

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

9

Se qualcuno è ancora alla ricerca di risposte a questo, dovresti dare un'occhiata alla risposta di trentaquattro .

<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 sostituirà% s con il valore di stringa corrente della preferenza, come visualizzato dal selettore di ListPreference.


Lavori. Questa è la soluzione più semplice e migliore oggi.
davidgyoung,

1
Si noti che "% s" può essere posizionato ovunque nella stringa di riepilogo. E sì, questo include stringhe di risorse!
Scott Biggs

7

Grazie per questo suggerimento!

Ho una schermata delle preferenze e voglio mostrare il valore per ciascuna preferenza dell'elenco come riepilogo.

Questo è il mio modo ora:

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

Questo funziona per me, ma mi chiedo quale sia la soluzione migliore (prestazioni, stabilità, scalabilità): quella che Koem sta mostrando o questa?


6

Grazie, Reto, per la spiegazione dettagliata!

Nel caso in cui questo fosse di qualche aiuto per qualcuno, ho dovuto cambiare il codice proposto da Reto Meier per farlo funzionare con l'SDK per 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            
    ...
}

La stessa modifica si applica alla funzione di richiamata onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)

Saluti,

Chris


4

Ho risolto il problema con il seguente discendente di 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;
        }
    }
}

Sembra funzionare bene per me in 1.6 fino a 4.0.4.


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

4

Ho visto tutte le risposte votate mostrare come impostare il riepilogo con il valore corrente esatto, ma l'OP voleva anche qualcosa di simile:

"Elimina i messaggi dopo x giorni" * <- riepilogo in cui x è il valore di preferenza corrente

Ecco la mia risposta per raggiungerlo

Come dice la documentazione su ListPreference.getSummary():

Restituisce il riepilogo di questo ListPreference. Se il riepilogo contiene un marcatore di formattazione String (ovvero "% s" o "% 1 $ s"), al suo posto verrà sostituito il valore della voce corrente.

Tuttavia, ho provato su diversi dispositivi e non sembra funzionare. Con alcune ricerche, ho trovato una buona soluzione in questa risposta . Consiste semplicemente nell'estensione di ogniPreference utilizzo e sostituzione getSummary()per funzionare come specificato dalla documentazione di Android.


1
Sembra funzionare inizialmente, ma quando si sceglie un nuovo valore non si aggiorna automaticamente fino a quando non si fa qualcosa per invalidare l'intera attività e farla ridisegnare. Sono su Android 4.0.4.
eidylon,

Sarebbe bello se Google potesse aggiungere una stringa di formattazione all'oggetto preferenza.
Justin Smith,

3

Se si desidera visualizzare solo il valore di testo semplice di ciascun campo come riepilogo, il codice seguente dovrebbe essere il più semplice da mantenere. Richiede solo due modifiche (linee 13 e 21, contrassegnate con "cambia qui"):

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

}

3

Ecco la mia soluzione:

Crea un metodo di tipo 'getter' di preferenza.

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

Costruisci un metodo '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()");
    }

Inizializzare

Creare classe pubblica che PreferenceActivity e implementa 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();
}


3

FYI:

findPreference(CharSequence key)
This method was deprecated in API level 11. This function is not relevant
for a modern fragment-based PreferenceActivity.

Un motivo in più per guardare lo slick Answerdi @ASD sopra ( fonte trovata qui ) che dice di usare %sin android:summaryper ogni campo in preferences.xml. (Il valore corrente della preferenza viene sostituito %s.)

inserisci qui la descrizione dell'immagine

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

3

Poiché nella classe di preferenza androidx ha l' interfaccia SummaryProvider , può essere fatto senza OnSharedPreferenceChangeListener. Sono previste implementazioni semplici per EditTextPreference e ListPreference. Basandosi sulla risposta di EddieB può sembrare così. Testato su androidx.preference: preferenza: 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());
        }
    }
}


2

Qui, tutti questi sono tagliati dal campione Eclipse SettingsActivity . Devo copiare tutti questi troppi codici per mostrare come questi sviluppatori Android scelgono perfettamente per uno stile di codifica più generalizzato e stabile.

Ho lasciato i codici per adattare l' PreferenceActivityAPI tablet e maggiore.

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>

NOTA: In realtà voglio solo commentare come "Anche il campione di Google per PreferenceActivity è interessante". Ma non ho abbastanza punti reputazione, quindi per favore non incolparmi.

(Scusa per il pessimo inglese)


2

Devi usare la funzione bindPreferenceSummaryToValue sul metodo onCreate.

Esempio:

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

Guarda la lezione 3 sul corso Udacity Android: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601


2

Per EditTextPreference :

Sono arrivato a questa soluzione, ovviamente, solo se hai bisogno di un particolare edittextpreference ma puoi farlo con ogni preferenza:

............

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, ""));

            }
}

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

In:

@Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            updatePreference(findPreference(key), key);
}

2

La mia soluzione è quella di creare un personalizzato EditTextPreference, utilizzato in XML in questo modo:<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();
    }
}

1

Per impostare il riepilogo di ListPreferencea sul valore selezionato in una finestra di dialogo, è possibile utilizzare questo codice:

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

e yourpackage.ListPreferencefai riferimento all'oggetto nel tuo preferences.xmlricordo per specificare lì il tuo in android:defaultValuequanto ciò innesca la chiamata a onSetInitialValue().

Se lo desideri, puoi modificare il testo prima di chiamare setSummary()quello che preferisci .


1

Dato che sto usando un'abitudine PreferenceDataStore, non posso aggiungere un ascoltatore ad alcuni, SharedPreferencequindi ho dovuto scrivere una soluzione un po 'confusa che ascolta ogni preferenza:

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

1

Se stai usando AndroidX puoi usarne uno personalizzatoSummaryProvider . Questo approccio può essere utilizzato per qualsiasi Preference.

Esempio dalla documentazione (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();
    }
});

Esempio dalla documentazione (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
    }
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.