Como faço para exibir o valor atual de uma preferência do Android no resumo de preferências?

457

Isso deve surgir com muita frequência.

Quando o usuário está editando preferências em um aplicativo Android, gostaria que eles pudessem ver o valor atualmente definido da preferência no Preference resumo.

Exemplo: se eu tiver uma configuração de preferência para "Descartar mensagens antigas" que especifique o número de dias após os quais as mensagens precisam ser limpas. No PreferenceActivityeu gostaria que o usuário visse:

"Descartar mensagens antigas" <- title

"Limpar mensagens após x dias" <- resumo onde x é o valor atual da Preferência

Crédito extra: torne isso reutilizável, para que eu possa aplicá-lo facilmente a todas as minhas preferências, independentemente do tipo (para que funcione com EditTextPreference, ListPreference etc. com uma quantidade mínima de codificação).

Nyenyec
fonte

Respostas:

151

Existem maneiras de tornar essa uma solução mais genérica, se isso atender às suas necessidades.

Por exemplo, se você deseja que genericamente todas as preferências de lista mostrem suas opções como resumo, você pode ter isso para sua onSharedPreferenceChangedimplementação:

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

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

Isso é facilmente extensível a outras classes de preferências.

E usando a funcionalidade getPreferenceCounte getPreferenceem PreferenceScreene PreferenceCategory, você poderia facilmente escrever uma função genérica para percorrer a árvore de preferências, definindo os resumos de todas as preferências dos tipos que você deseja para sua toStringrepresentação.

DozenCrows
fonte
6
boa solução de fato. só falta uma inicialização #
22412 njzk2
9
@ njzk2 tudo que você tem a fazer é certificar-se de atividadeimplements OnSharedPreferenceChangeListener
4
NB: Existe uma maneira mais simples, veja a resposta de @ Robertas .
Salman von Abbas
6
Na verdade, você pode definir o resumo como "%s"para ListPreferencee ListPreference.getSummary()formatará o resumo com a entrada selecionada atual (ou ""se nenhuma).
SOFe 3/08/16
findPreference (key) está obsoleta. Existe outra maneira de acessar isso?
Nevermore
144

Aqui está a minha solução ... FWIW

package com.example.PrefTest;

import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.EditTextPreference;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;
import android.preference.PreferenceManager;

public class Preferences extends PreferenceActivity implements
        OnSharedPreferenceChangeListener {

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        PreferenceManager.setDefaultValues(Preferences.this, R.xml.preferences,
            false);
        initSummary(getPreferenceScreen());
    }

    @Override
    protected void onResume() {
        super.onResume();
        // Set up a listener whenever a key changes
        getPreferenceScreen().getSharedPreferences()
                .registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    protected void onPause() {
        super.onPause();
        // Unregister the listener whenever a key changes
        getPreferenceScreen().getSharedPreferences()
                .unregisterOnSharedPreferenceChangeListener(this);
    }

    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
            String key) {
        updatePrefSummary(findPreference(key));
    }

    private void initSummary(Preference p) {
        if (p instanceof PreferenceGroup) {
            PreferenceGroup pGrp = (PreferenceGroup) p;
            for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
                initSummary(pGrp.getPreference(i));
            }
        } else {
            updatePrefSummary(p);
        }
    }

    private void updatePrefSummary(Preference p) {
        if (p instanceof ListPreference) {
            ListPreference listPref = (ListPreference) p;
            p.setSummary(listPref.getEntry());
        }
        if (p instanceof EditTextPreference) {
            EditTextPreference editTextPref = (EditTextPreference) p;
            if (p.getTitle().toString().toLowerCase().contains("password"))
            {
                p.setSummary("******");
            } else {
                p.setSummary(editTextPref.getText());
            }
        }
        if (p instanceof MultiSelectListPreference) {
            EditTextPreference editTextPref = (EditTextPreference) p;
            p.setSummary(editTextPref.getText());
        }
    }
}
EddieB
fonte
Isso funciona muito bem no @EddieB ... exceto que eu tenho uma tela de preferências dentro de uma tela de preferências. Alguma idéia de como acessar a tela de preferências internas e preencher aquelas com resumo?
Taraloca
@taraloca - altera if (p exemplo de PreferenceCategory) {PreferenceCategory pCat = (PreferenceCategory) p; para if (p exemplo do PreferenceGroup) {final PreferenceGroup pCat = (PreferenceGroup) p;
Martin Ždila
este grande está trabalhando e se EditTextPreferenceé android:password="true" ele mostra o valor
Chathura Wijesinghe
1
Como devo modificar o código para exibir o resumo do arquivo de recurso (xml) se nenhum valor estiver definido (por exemplo if editTextPref.getText() == "")? Como obter um valor resumido em updatePrefSummary? p.getSummary()e editTextPref.getSummary()retorne valores já modificados.
La_
Desde que ambos PreferenceCategorye PreferenceScreenherdar de PreferenceGroup, eu mudei initSummarypara lidar com um em PreferenceGroupvez disso. Isso evita a necessidade de outro loop onCreate(). Mudança de comportamento: as PreferenceScreens aninhadas agora também são tratadas de forma recursiva.
Lekensteyn
96

A documentação do Android diz que é possível usar um marcador de formatação de String em getSummary():

Se o resumo tiver um marcador de formatação de String (por exemplo, "% s" ou "% 1 $ s"), o valor atual da entrada será substituído em seu lugar.

Simplesmente especificar android:summary="Clean up messages after %s days"na declaração XML ListPreference funcionou para mim.

Nota: Isso funciona apenas para ListPreference.

Robertas
fonte
Alguém me corrija se eu estiver errado, mas a documentação para getSummary () afirma que foi adicionada no nível 1 da API. Você está sugerindo que o comportamento era diferente quando foi lançado pela primeira vez?
TheIT
10
Infelizmente, isso funciona apenas para ListPreference. Eu quero o mesmo comportamento para EditTextPreference. É surpreendente que o Google não tenha adicionado isso para todas as DialogPreferences.
Vicki
2
Além disso, eu não trabalho desde que o valor não tenha sido definido - na primeira chamada da atividade Preferências, ele exibe apenas% s, o que é realmente idiota.
Zordid 31/01
3
@Zordid Isso pode ser corrigido especificando o valor padrão no seu xml, como android:defaultValue="0"no seu ListPreference. Esta é a resposta mais sensata e funciona para mim.
Mohit Singh
@Mohit Singh / @Zordid, na API 22 do Lollipop, oe defaultValueo %snão funcionam. Em outras versões, geralmente, ele funciona. Alguma solução, por favor? Eu com certeza não quero escrever uma classe personalizada para isso. Inacreditável que o Google faça das tarefas mais triviais uma dor.
Narayana J
81

Se você usar PreferenceFragment, é assim que eu resolvi. É auto-explicativo.

public static class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      addPreferencesFromResource(R.xml.settings);
      getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onResume() {
      super.onResume();
      for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i) {
        Preference preference = getPreferenceScreen().getPreference(i);
        if (preference instanceof PreferenceGroup) {
          PreferenceGroup preferenceGroup = (PreferenceGroup) preference;
          for (int j = 0; j < preferenceGroup.getPreferenceCount(); ++j) {
            Preference singlePref = preferenceGroup.getPreference(j);
            updatePreference(singlePref, singlePref.getKey());
          }
        } else {
          updatePreference(preference, preference.getKey());
        }
      }
    }

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

    private void updatePreference(Preference preference, String key) {
      if (preference == null) return;
      if (preference instanceof ListPreference) {
        ListPreference listPreference = (ListPreference) preference;
        listPreference.setSummary(listPreference.getEntry());
        return;
      }
      SharedPreferences sharedPrefs = getPreferenceManager().getSharedPreferences();
      preference.setSummary(sharedPrefs.getString(key, "Default"));
    }
  }
tdevaux
fonte
3
Esta solução precisa de mais votos ... Me incomoda que os exemplos no site do desenvolvedor MOSTREM isso sendo feito, mas o omitam completamente.
Justin Smith
3
Para obter EditTextPreferences também atualizados adicionar este à updatePreferenceCODE if (preference instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText()); }graças @EddieB
Eugene van der Merwe
6
Para onde você liga 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 Estou bem ciente do que você está citando. Está dizendo para você não usar PreferenceActivity.findPreference(e vários outros métodos), porque o Google quer que você mude para a técnica mostrada nesta resposta, que usa em seu PreferenceFragment.findPreferencelugar.
Dan Hulme
33

Minha opção é estender o ListPreference e é limpo:

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

Então você adiciona seu settings.xml:

<yourpackage.ListPreferenceShowSummary
    android:key="key" android:title="title"
    android:entries="@array/entries" android:entryValues="@array/values"
    android:defaultValue="first value"/>
Youyougoslave
fonte
Eu fiz uma solução com base nisso. Na minha solução, tenho um método para definir uma matriz de entrySummaries em vez de usar as seqüências de caracteres de entradas no menu e nos resumos. Há um problema aqui: getEntry () retorna o valor anterior, não o novo.
24512 pzulw
1
Na verdade, init () é mesmo necessário? Acabei de substituir getSummary () e parece funcionar perfeitamente!
Andy
4
Parece uma solução muito mais fácil e limpa do que a mais votada!
muslidrikk
2
A init()função é necessária para atualizar summaryquando o usuário altera essa preferência. Sem ele, ele permanecerá como a entrada foi inicialmente.
anthonylawson
23

Você pode substituir as classes de preferência padrão e implementar o recurso.

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

Mais tarde, no xml, você pode usar preferências personalizadas como

<your.package.name.MyListPreference 
    android:key="noteInterval"
    android:defaultValue="60"
    android:title="Notification Interval"
    android:entries="@array/noteInterval"
    android:entryValues="@array/noteIntervalValues"
    />
Palani
fonte
Excelente método simples. Apenas atente para coisas como% na string getEntry, pois elas podem causar problemas (ou o fizeram por mim) #
Andrew Andrew
21

Depois de várias horas gasto para resolver esse problema, implementei este código:

[UPDATE: a lista da versão final]

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

Essa foi a única solução que funcionou bem para mim. Antes eu tentei subclassificar de ListPreferences e implementar o android: summary = "bla bla bla% s". Nem funcionou.

Subtle Fox
fonte
Seu caminho é mais claro e usa menos código do que outros. As principais respostas funcionam usando "proxy" - gerenciador de preferências. Não é tão claro como ouvir mudanças diretas na lista.
Paul Annekov
@ Fox Subtle, solução pura. apenas curioso se você fez 'setDefaultValue ()', então por cheque (ss == null)
Samuel
Porque setDefaultValue () não deveria estar lá :) Eu coloquei este código antes de refatoração
Subtle Fox
20

Talvez como ListPreference: Modifique getSummary para obter o que deseja:

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 use isso no seu xml:

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

Assim, você pode escrever um resumo com %so valor real.

Eruvanos
fonte
1
@Eruvanos @ serv-inc Pelo menos com uma subclasse de android.support.v7.preference.EditTextPreference, isso não atualiza o resumo quando a preferência é alterada, apenas quando a atividade de preferências é criada. Uma maneira de contornar isso sem implementar OnSharedPreferenceChangeListener.onSharedPreferenceChangedna classe de fragmento de preferências é também substituir android.support.v7.preference.EditTextPreference.setText(String text):@Override public void setText(String text) { super.setText(text); this.setSummary(this.getText()); }
PointedEars
@ PointedEars: pronto. Mas isso também parece ser uma cópia do stackoverflow.com/a/21906829/1587329
serv-inc
18

Este é o código que você precisa para definir o resumo com o valor escolhido. Ele também define os valores na inicialização e respeita os valores padrão, não apenas na alteração. Apenas mude "R.layout.prefs" para seu arquivo xml e estenda o método setSummary às suas necessidades. Na verdade, trata apenas de ListPreferences, mas é fácil personalizar para respeitar outras Preferências.

package de.koem.timetunnel;

import android.content.SharedPreferences;
import android.content.SharedPreferences.OnSharedPreferenceChangeListener;
import android.os.Bundle;
import android.preference.ListPreference;
import android.preference.Preference;
import android.preference.PreferenceActivity;
import android.preference.PreferenceGroup;

public class Prefs 
    extends PreferenceActivity 
    implements OnSharedPreferenceChangeListener {

   @Override
   protected void onCreate(Bundle savedInstanceState) {
       super.onCreate(savedInstanceState);

       this.addPreferencesFromResource(R.layout.prefs);
       this.initSummaries(this.getPreferenceScreen());

       this.getPreferenceScreen().getSharedPreferences()
           .registerOnSharedPreferenceChangeListener(this);
    }

  /**
    * Set the summaries of all preferences
    */
  private void initSummaries(PreferenceGroup pg) {
      for (int i = 0; i < pg.getPreferenceCount(); ++i) {
          Preference p = pg.getPreference(i);
          if (p instanceof PreferenceGroup)
              this.initSummaries((PreferenceGroup) p); // recursion
          else
              this.setSummary(p);
      }
  }

  /**
    * Set the summaries of the given preference
    */
  private void setSummary(Preference pref) {
      // react on type or key
      if (pref instanceof ListPreference) {
          ListPreference listPref = (ListPreference) pref;
          pref.setSummary(listPref.getEntry());
      }
  }

  /**
    * used to change the summary of a preference
    */
  public void onSharedPreferenceChanged(SharedPreferences sp, String key) {
     Preference pref = findPreference(key);
     this.setSummary(pref);
  }

  // private static final String LOGTAG = "Prefs";
}

koem

Koem
fonte
Muito obrigado! Criei uma classe a partir disso, fornecendo o ID do recurso como argumento para o onCreate () - dessa maneira, houve uma alteração de uma linha nas telas de minhas configurações para que eles mostrassem os valores em resumo.
Asmo Soinio
2
BTW: Observe que as preferências não persistentes não serão atualizadas usando este sistema. As alterações nelas devem ser ouvidas usando o setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)método de Preferências individuais.
Asmo Soinio 7/02
11

Na verdade, CheckBoxPreference tem a capacidade de especificar um resumo diferente com base no valor da caixa de seleção. Consulte os atributos android: summaryOff e android: summaryOn (bem como os métodos CheckBoxPreference correspondentes).

dhaag23
fonte
11

Para EditTextPreference:

public class MyEditTextPreference extends EditTextPreference {
    public MyEditTextPreference(Context context, AttributeSet attrs, int defStyle) {
        super(context, attrs, defStyle);
    }

    public MyEditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setText(String text) {
        super.setText(text);
        setSummary(text);
    }
}
lordmegamax
fonte
9

Se alguém ainda estiver procurando respostas para isso, verifique a resposta de trinta e três .

<ListPreference
    android:key="pref_list"
    android:title="A list of preferences"
    android:summary="%s"
    android:entries="@array/pref_list_entries"
    android:entryValues="@array/pref_list_entries_values"
    android:defaultValue="0" />

O Android substituirá% s pelo valor atual da string da preferência, conforme exibido pelo seletor do ListPreference.

Irritator
fonte
Trabalho. Esta é a melhor e mais fácil solução hoje.
Davidgyoung
1
Observe que o "% s" pode ser colocado em qualquer lugar da sua sequência de resumo. E sim, isso inclui cadeias de recursos!
Scott Biggs
7

Obrigado por esta dica!

Eu tenho uma tela de preferências e quero mostrar o valor de cada preferência de lista como o resumo.

Este é o meu caminho agora:

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

Isso funciona para mim, mas estou me perguntando qual é a melhor solução (desempenho, estabilidade, escalabilidade): a que o Koem está mostrando ou esta?

alexx
fonte
6

Obrigado, Reto, pela explicação detalhada!

Caso isso ajude alguém, tive que alterar o código proposto por Reto Meier para que ele funcionasse com o SDK para 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            
    ...
}

A mesma alteração se aplica à função de retorno de chamada onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)

Felicidades,

Chris

Chris
fonte
4

Resolvi o problema com o seguinte descendente de ListPreference:

public class EnumPreference extends ListPreference {

    public EnumPreference(Context aContext, AttributeSet attrs) {
        super(aContext,attrs);
    }

    @Override
    protected View onCreateView(ViewGroup parent) {
        setSummary(getEntry());
        return super.onCreateView(parent);
    }

    @Override
    protected boolean persistString(String aNewValue) {
        if (super.persistString(aNewValue)) {
            setSummary(getEntry());
            notifyChanged();
            return true;
        } else {
            return false;
        }
    }
}

Parece funcionar bem para mim em 1.6 até 4.0.4.

Uncle Code Monkey
fonte
4
public class ProfileManagement extends PreferenceActivity implements
OnPreferenceChangeListener {
    EditTextPreference screenName;
    ListPreference sex;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.layout.profile_management);

            screenName = (EditTextPreference) findPreference("editTextPref");
            sex = (ListPreference) findPreference("sexSelector");

            screenName.setOnPreferenceChangeListener(this);
            sex.setOnPreferenceChangeListener(this);

    }   

    @Override
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        preference.setSummary(newValue.toString());
        return true;
    }
}
GalkinAndrew
fonte
4

Vi todas as respostas votadas mostrarem como definir o resumo com o valor atual exato, mas o OP também queria algo como:

"Limpar mensagens após x dias" * <- resumo em que x é o valor atual da Preferência

Aqui está a minha resposta para conseguir isso

Como a documentação diz sobre ListPreference.getSummary():

Retorna o resumo desta ListPreference. Se o resumo tiver um marcador de formatação de String (por exemplo, "% s" ou "% 1 $ s"), o valor atual da entrada será substituído em seu lugar.

No entanto, tentei em vários dispositivos e parece não funcionar. Com algumas pesquisas, encontrei uma boa solução nesta resposta . Simplesmente consiste em estender cada Preferenceuso e substituição getSummary()para funcionar conforme especificado na documentação do Android.

Christian García
fonte
1
Parece funcionar inicialmente, mas quando você escolhe um novo valor, ele não é atualizado automaticamente até você fazer algo para invalidar toda a atividade e fazer com que ela seja redesenhada. Estou no Android 4.0.4.
eidylon
Seria bom se o Google pudesse adicionar uma sequência de formatação ao objeto de preferência.
Justin Smith
3

Se você deseja exibir apenas o valor de texto sem formatação de cada campo como seu resumo, o código a seguir deve ser o mais fácil de manter. Requer apenas duas alterações (linhas 13 e 21, marcadas com "alterar aqui"):

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

}
caw
fonte
3

Aqui está a minha solução:

Crie um método de tipo 'getter' de preferência.

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

Crie um método '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()");
    }

Inicializar

Crie uma classe pública que PreferenceActivity e implemente OnSharedPreferenceChangeListener

protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    PreferenceManager.setDefaultValues(this, R.xml.global_preferences,
    false);
    this.addPreferencesFromResource(R.xml.global_preferences);
    this.getPreferenceScreen().getSharedPreferences()
        .registerOnSharedPreferenceChangeListener(this);
}

protected void onResume() {
    super.onResume();
    setSummary();
}
Page2PagePro
fonte
3

Simplesmente:

listPreference.setSummary("%s");
Oded Breiner
fonte
3

PARA SUA INFORMAÇÃO:

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

Mais uma razão para olhar para a mancha lisa Answerdo @ASD acima ( fonte encontrada aqui ) dizendo para usar %sem android:summarycada campo no preferences.xml. (O valor atual da preferência é substituído %s.)

insira a descrição da imagem aqui

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

Como na classe Preference androidx possui a interface SummaryProvider , isso pode ser feito sem o OnSharedPreferenceChangeListener. Implementações simples são fornecidas para EditTextPreference e ListPreference. Com base na resposta de EddieB , pode ser assim. Testado em androidx.preference: preferência: 1.1.0-alpha03.

package com.example.util.timereminder.ui.prefs;

import android.os.Bundle;

import com.example.util.timereminder.R;

import androidx.preference.EditTextPreference;
import androidx.preference.ListPreference;
import androidx.preference.Preference;
import androidx.preference.PreferenceFragmentCompat;
import androidx.preference.PreferenceGroup;

/**
 * Displays different preferences.
 */
public class PrefsFragmentExample extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        addPreferencesFromResource(R.xml.preferences);

        initSummary(getPreferenceScreen());
    }

    /**
     * Walks through all preferences.
     *
     * @param p The starting preference to search from.
     */
    private void initSummary(Preference p) {
        if (p instanceof PreferenceGroup) {
            PreferenceGroup pGrp = (PreferenceGroup) p;
            for (int i = 0; i < pGrp.getPreferenceCount(); i++) {
                initSummary(pGrp.getPreference(i));
            }
        } else {
            setPreferenceSummary(p);
        }
    }

    /**
     * Sets up summary providers for the preferences.
     *
     * @param p The preference to set up summary provider.
     */
    private void setPreferenceSummary(Preference p) {
        // No need to set up preference summaries for checkbox preferences because
        // they can be set up in xml using summaryOff and summary On
        if (p instanceof ListPreference) {
            p.setSummaryProvider(ListPreference.SimpleSummaryProvider.getInstance());
        } else if (p instanceof EditTextPreference) {
            p.setSummaryProvider(EditTextPreference.SimpleSummaryProvider.getInstance());
        }
    }
}
Razeeman
fonte
3

De acordo com os documentos do Android, você pode usar os app:useSimpleSummaryProvider="true"componentes ListPreference e EditTextPreference.

alishir
fonte
2

Aqui, todos estes são cortados da amostra Eclipse SettingsActivity . Eu tenho que copiar todos esses códigos demais para mostrar como esses desenvolvedores do Android escolhem perfeitamente o estilo de codificação mais generalizado e estável.

Deixei os códigos para adaptar PreferenceActivityao tablet e à API maior.

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: Na verdade, eu só quero comentar como "A amostra do Google para PreferenceActivity também é interessante". Mas eu não tenho pontos de reputação suficientes. Então, por favor, não me culpe.

(Desculpe pelo mau inglês)

johnkarka
fonte
2

Você precisa usar a função bindPreferenceSummaryToValue no método onCreate.

Exemplo:

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

Consulte a lição 3 no curso Udacity Android: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601

Pablo
fonte
2

Para EditTextPreference :

Cheguei a esta solução, é claro, apenas se você precisar de uma preferência específica por edittext, mas poderá fazer isso com todas as preferências:

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

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

            }
}

Em seguida, em 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);
        }

No:

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

Minha solução é criar um personalizado EditTextPreference, usado em XML como este:<com.example.EditTextPreference android:title="Example Title" />

EditTextPreference.java : -

package com.example;

import android.content.Context;
import android.util.AttributeSet;

public class EditTextPreference extends android.preference.EditTextPreference
{
    public EditTextPreference(Context context, AttributeSet attrs, int defStyle)
    {
        super(context, attrs, defStyle);
    }

    public EditTextPreference(Context context, AttributeSet attrs)
    {
        super(context, attrs);
    }

    public EditTextPreference(Context context)
    {
        super(context, null);
    }

    @Override
    protected void onDialogClosed(boolean positiveResult)
    {
        super.onDialogClosed(positiveResult);

        setSummary(getSummary());
    }

    @Override
    public CharSequence getSummary()
    {
        return getText();
    }
}
Salman von Abbas
fonte
1

Para definir o resumo de a ListPreferencecomo o valor selecionado em uma caixa de diálogo, você pode usar este código:

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 faça referência ao yourpackage.ListPreferenceobjeto em sua preferences.xmllembrança para especificar lá o seu, android:defaultValuepois isso aciona a chamada paraonSetInitialValue() .

Se desejar, você pode modificar o texto antes de ligar setSummary()para o que melhor se adequar ao seu aplicativo.

gicci
fonte
1

Como estou usando um costume PreferenceDataStore, não consigo adicionar um ouvinte a alguns, SharedPreferenceentão tive que escrever uma solução um tanto hacky que escutasse cada preferência:

class SettingsFragment : PreferenceFragmentCompat(), Preference.OnPreferenceChangeListener {
    private val handler: Handler by lazy { Handler(Looper.getMainLooper()) }

    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        preferenceManager.preferenceDataStore = prefs
        addPreferencesFromResource(R.xml.app_preferences)
        onPreferenceChange(preferenceScreen, null)
    }

    override fun onPreferenceChange(preference: Preference, newValue: Any?): Boolean {
        preference.onPreferenceChangeListener = this

        when (preference) {
            is PreferenceGroup -> for (i in 0 until preference.preferenceCount) {
                onPreferenceChange(preference.getPreference(i), null)
            }
            is ListPreference -> {
                if (preference.value == null) {
                    preference.isPersistent = false
                    preference.value = Preference::class.java.getDeclaredField("mDefaultValue")
                            .apply { isAccessible = true }
                            .get(preference).toString()
                    preference.isPersistent = true
                }

                postPreferenceUpdate(Runnable { preference.summary = preference.entry })
            }
        }
        return true
    }

    /**
     * We can't directly update the preference summary update because [onPreferenceChange]'s result
     * is used to decide whether or not to update the pref value.
     */
    private fun postPreferenceUpdate(r: Runnable) = handler.post(r)
}
SUPERCILEX
fonte
1

Se você estiver usando o AndroidX, poderá usar um costumeSummaryProvider . Essa abordagem pode ser usada para qualquerPreference .

Exemplo da documentação (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();
    }
});

Exemplo da documentação (Kotlin):

val countingPreference = findPreference("counting") as EditTextPreference

countingPreference.summaryProvider = SummaryProvider<EditTextPreference> { preference ->
    val text = preference.text
    if (TextUtils.isEmpty(text)) {
        "Not set"
    } else {
        "Length of saved value: " + text.length
    }
}
Andrew Churilo
fonte