Jak wyświetlić bieżącą wartość preferencji Androida w podsumowaniu preferencji?


457

To musi pojawiać się bardzo często.

Gdy użytkownik edytuje preferencje w aplikacji na Androida, chciałbym, aby w Preferencepodsumowaniu mógł zobaczyć aktualnie ustawioną wartość preferencji .

Przykład: jeśli mam ustawienie preferencji „Odrzuć stare wiadomości”, które określa liczbę dni, po których wiadomości muszą zostać wyczyszczone. W PreferenceActivitychciałbym, aby użytkownik zobaczył:

„Odrzuć stare wiadomości” <- tytuł

„Wyczyść wiadomości po x dniach” <- podsumowanie, gdzie x jest bieżącą wartością preferencji

Dodatkowy kredyt: uczyń to wielokrotnego użytku, dzięki czemu mogę łatwo zastosować go do wszystkich moich preferencji niezależnie od ich typu (tak, aby działał z EditTextPreference, ListPreference itp. Przy minimalnym stopniu kodowania).

Odpowiedzi:


151

Istnieją sposoby, aby uczynić to bardziej ogólnym rozwiązaniem, jeśli odpowiada Twoim potrzebom.

Na przykład, jeśli chcesz, aby wszystkie preferencje listy pokazywały swój wybór jako podsumowanie, możesz mieć to dla swojej onSharedPreferenceChangedimplementacji:

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

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

Można to łatwo rozszerzyć na inne klasy preferencji.

Za pomocą funkcji getPreferenceCounti getPreferencew PreferenceScreeni PreferenceCategorymożna łatwo napisać funkcję ogólną, aby przejść po drzewie preferencji, ustawiając podsumowania wszystkich preferencji typów, które mają być toStringreprezentowane


6
naprawdę dobre rozwiązanie. brakuje tylko inicjalizacji
njzk2

9
@ njzk2 wszystko, co musisz zrobić, to upewnić się, że aktywnośćimplements OnSharedPreferenceChangeListener

4
Uwaga: Istnieje prostszy sposób, patrz odpowiedź @ Robertasa .
Salman von Abbas,

6
W rzeczywistości można ustawić podsumowanie "%s"na ListPreferencei ListPreference.getSummary()sformatować podsumowanie z bieżącym wybranym wpisem (lub ""jeśli nie wybrano żadnego).
SOFe

findPreference (klucz) jest przestarzałe, czy istnieje inny sposób uzyskania do niego dostępu?
Nevermore

144

Oto moje rozwiązanie ... 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());
        }
    }
}

Działa to świetnie @EddieB ... poza tym, że mam ekran preferencji na ekranie preferencji. Masz pomysł, jak dotrzeć do ekranu preferencji wewnętrznych i wypełnić podsumowanie?
taraloca

@taraloca - zmień, jeśli (p instanceof PreferenceCategory) {PreferenceCategory pCat = (PreferenceCategory) p; to if (p instanceof PreferenceGroup) {final PreferenceGroup pCat = (PreferenceGroup) p;
Martin Ždila

ten wielki pracuje co, jeśli EditTextPreferencejest android:password="true" ona pokazuje wartość
Chathura Wijesinghe

1
Jak zmodyfikować kod, aby wyświetlał podsumowanie z pliku zasobów (xml), jeśli nie zdefiniowano żadnej wartości (tj. if editTextPref.getText() == "")? Jak uzyskać wartość podsumowania w updatePrefSummary? p.getSummary()i editTextPref.getSummary()zwróć już zmodyfikowane wartości.
LA_

Ponieważ oba PreferenceCategoryi PreferenceScreendziedziczą po PreferenceGroup, zmieniłem initSummaryna obsługę PreferenceGroupzamiast. Pozwala to uniknąć konieczności kolejnej pętli onCreate(). Zmiana zachowania: zagnieżdżone ekrany preferencji są teraz obsługiwane również rekurencyjnie.
Lekensteyn

96

Dokumentacja Androida mówi, że można użyć znacznika formatowania ciągu w getSummary():

Jeśli podsumowanie zawiera znacznik formatowania łańcucha (tj. „% S” lub „% 1 $ s”), wówczas bieżąca wartość wpisu zostanie zastąpiona w jego miejsce.

Po prostu określenie android:summary="Clean up messages after %s days"w deklaracji XML ListPreference działało dla mnie.

Uwaga: Działa to tylko w przypadku ListPreference.


Ktoś poprawi mnie, jeśli się mylę, ale dokumentacja getSummary () stwierdza, że ​​została dodana na poziomie API 1. Czy sugerujesz, że zachowanie było inne po pierwszym wydaniu?
TheIT,

10
Niestety działa to tylko w przypadku ListPreference. Chcę takie samo zachowanie dla EditTextPreference. Zaskakujące jest to, że Google nie dodał tego dla wszystkich preferencji Dialog.
Vicki

2
Ponadto nie działam, dopóki wartość nie zostanie ustawiona - przy pierwszym wywołaniu działania Preference wyświetla tylko% s, co jest naprawdę głupie.
Zordid,

3
@Zordid Można to naprawić, określając wartość domyślną android:defaultValue="0"w pliku XML, podobnie jak w ListPreference. To najbardziej sensowna odpowiedź i działa dla mnie.
Mohit Singh

@Mohit Singh / @Zordid, na Lollipop API 22, defaultValuei %snie działają. Jednak w innych wersjach ogólnie działa. Jakieś rozwiązanie proszę? Na pewno nie chcę do tego pisać niestandardowej klasy. Niewiarygodne, że Google sprawia, że ​​najbardziej trywialne zadania są uciążliwe.
Narayana J

81

Jeśli używasz PreferenceFragment, tak to rozwiązałem. To jest oczywiste.

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
To rozwiązanie wymaga więcej głosów ... Wkurza mnie to, że przykłady w witrynie dla programistów pokazują, że jest to zrobione, ale całkowicie go pomija.
Justin Smith,

3
Aby uzyskać EditTextPreferencje również zaktualizowane, dodaj to do updatePreferenceKODU if (preference instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText()); }dzięki @EddieB
Eugene van der Merwe

6
Gdzie zadzwonić 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 Jestem w pełni świadomy tego, co cytujesz. Mówi ci, abyś nie używał PreferenceActivity.findPreference(i kilku innych metod), ponieważ Google chce, abyś przeszedł na technikę pokazaną w tej odpowiedzi, która używa PreferenceFragment.findPreferencezamiast tego.
Dan Hulme

33

Moja opcja to rozszerzenie ListPreference i to jest czyste:

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

Następnie dodajesz w pliku settings.xml:

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

Na tej podstawie stworzyłem rozwiązanie. W moim rozwiązaniu mam metodę ustawiania tablicy entrySummaries zamiast używania łańcuchów wpisów zarówno w menu, jak i podsumowaniach. Jest tutaj jeden problem: getEntry () zwraca poprzednią wartość, a nie nową.
pzulw

1
Czy właściwie init () jest nawet potrzebny? Właśnie przesłoniłem getSummary () i wygląda na to, że działa idealnie!
Andy,

4
Wydaje się o wiele łatwiejsze i czystsze rozwiązanie niż najwyżej ocenione!
muslidrikk

2
Ta init()funkcja jest konieczna do aktualizacji, summarykiedy użytkownik zmieni tę preferencję. Bez tego pozostanie bez względu na to, jaki był początkowo wpis.
Anthonylawson

23

Możesz zastąpić domyślne klasy preferencji i zaimplementować tę funkcję.

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

Później możesz użyć własnych preferencji, takich jak

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

Doskonała prosta metoda. Uważaj tylko na takie elementy, jak% w ciągu getEntry, ponieważ mogą powodować problemy (lub zrobiły to dla mnie)
Andrew

21

Po kilku godzinach spędzonych na rozwiązaniu takiego problemu zaimplementowałem ten kod:

[AKTUALIZACJA: ostateczna lista wersji]

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

To było jedyne rozwiązanie, które działało dla mnie dobrze. Zanim spróbowałem podklasować z ListPreferences i zaimplementować Androida: Summary = "bla bla bla% s". Żaden nie działał.


Twoja droga jest bardziej przejrzysta i zużywa mniej kodu niż inne. Najlepsze odpowiedzi działają przy użyciu „proxy” - menedżera preferencji. To nie jest tak jasne, jak nasłuchiwanie bezpośrednich zmian na liście.
Paul Annekov,

@Subtle Fox, schludne rozwiązanie. tylko ciekawy, czy zrobiłeś 'setDefaultValue ()', to po co sprawdzać (ss == null)
Samuel

Ponieważ setDefaultValue () nie powinno tam być :) Umieściłem ten kod przed refaktoryzacją
Subtle Fox

20

Może jak ListPreference: Zmodyfikuj getSummary, aby uzyskać to, czego chcesz:

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

I użyj tego w swoim xml:

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

Możesz więc napisać podsumowanie %szamiast rzeczywistej wartości.


1
@Eruvanos @ serv-inc Przynajmniej z podklasą android.support.v7.preference.EditTextPreferencenie powoduje to aktualizacji podsumowania po zmianie preferencji, tylko po utworzeniu działania preferencji. Aby obejść ten problem bez implementacji OnSharedPreferenceChangeListener.onSharedPreferenceChangedw klasie fragmentów preferencji, należy również przesłonić android.support.v7.preference.EditTextPreference.setText(String text):@Override public void setText(String text) { super.setText(text); this.setSummary(this.getText()); }
PointedEars

@PointedEars: gotowe. Ale to też wydaje się być kopią stackoverflow.com/a/21906829/1587329
serv-inc

18

To jest kod, którego potrzebujesz, aby ustawić podsumowanie na wybraną wartość. Ustawia także wartości przy uruchamianiu i przestrzega wartości domyślnych, nie tylko przy zmianie. Wystarczy zmienić „R.layout.prefs” na plik xml i rozszerzyć metodę setSummary na swoje potrzeby. W rzeczywistości obsługuje tylko ListPreferences, ale można łatwo dostosować do innych preferencji.

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


Wielkie dzięki! Z tego utworzyłem klasę, podając identyfikator zasobu jako argument funkcji onCreate () - w ten sposób była to zmiana w jednym wierszu na ekranach ustawień, aby wyświetlały wartości w podsumowaniu.
Asmo Soinio

2
BTW: Pamiętaj, że nietrwałe preferencje nie będą aktualizowane przy użyciu tego systemu. Zmiany w nich muszą zostać wysłuchane przy użyciu metody setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)poszczególnych Preferencji.
Asmo Soinio,

11

W rzeczywistości CheckBoxPreference ma możliwość określenia innego podsumowania na podstawie wartości pola wyboru. Zobacz atrybuty android: summaryOff i android: summaryOn (a także odpowiednie metody CheckBoxPreference).


11

W przypadku 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

Jeśli ktoś nadal szuka odpowiedzi na to pytanie, powinieneś sprawdzić odpowiedź trzydziestego trzydziestego czwartego .

<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 zastąpi% s bieżącą wartością ciągu preferencji, wyświetlaną przez selektor ListPreference.


Pracuje. To jest obecnie najłatwiejsze i najlepsze rozwiązanie.
davidgyoung

1
Zauważ, że „% s” można umieścić w dowolnym miejscu ciągu podsumowania. I tak, to obejmuje ciągi zasobów!
Scott Biggs,

7

Dzięki za tę wskazówkę!

Mam jeden ekran preferencji i chcę pokazać wartość każdej preferencji listy jako podsumowanie.

Oto moja droga:

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

Działa to dla mnie, ale zastanawiam się, jakie jest najlepsze rozwiązanie (wydajność, stabilność, skalowalność): ten, który pokazuje Koem, czy ten?


6

Dzięki, Reto, za szczegółowe wyjaśnienie!

Na wypadek, gdyby komuś to pomogło, musiałem zmienić kod zaproponowany przez Reto Meiera, aby działał z SDK dla Androida 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            
    ...
}

Ta sama zmiana dotyczy funkcji oddzwaniania onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)

Twoje zdrowie,

Chris


4

Rozwiązałem problem z następującym potomkiem 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;
        }
    }
}

Wygląda na to, że działa mi dobrze w wersji od 1.6 do 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

Widziałem, że wszystkie głosowane odpowiedzi pokazują, jak ustawić podsumowanie z dokładną bieżącą wartością, ale OP chciał również coś takiego:

„Wyczyść wiadomości po x dniach” * <- podsumowanie, gdzie x jest bieżącą wartością preferencji

Oto moja odpowiedź na osiągnięcie tego

Jak mówi dokumentacja na temat ListPreference.getSummary():

Zwraca podsumowanie tej ListPreference. Jeśli podsumowanie zawiera znacznik formatowania łańcucha (tj. „% S” lub „% 1 $ s”), wówczas bieżąca wartość wpisu zostanie zastąpiona w jego miejsce.

Próbowałem jednak na kilku urządzeniach i wydaje się, że to nie działa. Po przeprowadzeniu niektórych badań znalazłem dobre rozwiązanie w tej odpowiedzi . Po prostu polega na rozszerzeniu każdego Preferenceużywanego i nadpisanego getSummary()do pracy zgodnie z dokumentacją Androida.


1
Wydaje się, że początkowo działa, ale gdy wybierzesz nową wartość, nie aktualizuje się ona automatycznie, dopóki nie zrobisz czegoś, co unieważni całą aktywność i spowoduje ponowne przerysowanie. Jestem na Androidzie 4.0.4.
eidylon

Byłoby miło, gdyby Google mógł dodać ciąg formatujący do obiektu preferencji.
Justin Smith,

3

Jeśli chcesz wyświetlać tylko zwykły tekst każdego pola jako jego podsumowanie, poniższy kod powinien być najłatwiejszy do utrzymania. Wymaga tylko dwóch zmian (wiersze 13 i 21, oznaczone „zmień tutaj”):

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

Oto moje rozwiązanie:

Zbuduj metodę „getter” typu preferencji.

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

Zbuduj metodę „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()");
    }

Zainicjuj

Utwórz klasę publiczną, która PreferenceActivity i implementuje 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.

Tym bardziej patrzeć na bardzo gładkim Answero @ASD powyżej ( źródło tutaj ) mówi w użyciu %sw android:summarydla każdego pola preferences.xml. (Bieżąca wartość preferencji jest zastępowana %s.)

wprowadź opis zdjęcia tutaj

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

3

Ponieważ w klasie preferencji androidx ma interfejs SummaryProvider , można to zrobić bez OnSharedPreferenceChangeListener. Dostępne są proste implementacje dla EditTextPreference i ListPreference. Opierając się na odpowiedzi EddieB, może to wyglądać następująco. Testowane na androidx.preference: preferencja: 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

Tutaj wszystkie są wycięte z próbki Eclipse SettingsActivity . Muszę skopiować wszystkie te zbyt wiele kodów, aby pokazać, jak ci programiści Androida wybierają idealnie dla bardziej ogólnego i stabilnego stylu kodowania.

Zostawiłem kody do dostosowania PreferenceActivitytabletu i lepszego 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>

UWAGA: Właściwie chcę po prostu skomentować: „Próbka Google dla PreferenceActivity jest również interesująca”. Ale nie mam wystarczającej liczby punktów reputacji, więc proszę nie obwiniaj mnie.

(Przepraszam, za słaby angielski)


2

Musisz użyć funkcji bindPreferenceSummaryToValue w metodzie onCreate.

Przykład:

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

Zobacz lekcję 3 na kursie Udacity dla Androida: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601


2

W przypadku EditTextPreference :

Doszedłem do tego rozwiązania, oczywiście, jeśli potrzebujesz konkretnej preferencji edytuj, ale możesz to zrobić z każdą Preferencją:

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

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

            }
}

Następnie w 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);
        }

W:

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

2

Moje rozwiązanie polega na utworzeniu niestandardowego EditTextPreference, używanego w XML w następujący sposób:<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

Aby ustawić podsumowanie a ListPreferencena wartość wybraną w oknie dialogowym, możesz użyć tego kodu:

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

i odwołaj się do yourpackage.ListPreferenceobiektu w twojej preferences.xmlpamięci, aby określić tam swój, android:defaultValueponieważ spowoduje to wywołanieonSetInitialValue() .

Jeśli chcesz, możesz zmodyfikować tekst, zanim zadzwonisz setSummary()do dowolnej aplikacji.


1

Ponieważ używam niestandardowego PreferenceDataStore, nie mogę dodać detektora do niektórych, SharedPreferencewięc musiałem napisać nieco zhackowane rozwiązanie, które słucha każdej preferencji:

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

Jeśli używasz AndroidaX, możesz użyć niestandardowegoSummaryProvider . Takie podejście można zastosować do każdego Preference.

Przykład z dokumentacji (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();
    }
});

Przykład z dokumentacji (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
    }
}
Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.