Як відобразити поточне значення налаштування Android у резюме налаштування?


457

Це потрібно придумати дуже часто.

Коли користувач редагує налаштування в додатку для Android, я хотів би, щоб вони могли бачити в Preferenceрезюме задане на даний момент значення .

Приклад: якщо у мене є налаштування налаштування для "Відхилити старі повідомлення", яке вказує кількість днів, після яких повідомлення потрібно очистити. В PreferenceActivityЯ хотів би користувачеві бачити:

"Відхилити старі повідомлення" <- назва

"Очистити повідомлення через х днів" <- підсумок, де x - поточне значення налаштування

Додатковий кредит: зробіть це багаторазовим використанням, тому я можу легко застосувати його до всіх моїх переваг незалежно від їх типу (щоб він працював з EditTextPreference, ListPreference тощо з мінімальною кількістю кодування).

Відповіді:


151

Є способи зробити це більш загальним рішенням, якщо це відповідає вашим потребам.

Наприклад, якщо ви хочете, щоб усі параметри списку показували їх вибір як резюме, ви можете мати це для своєї onSharedPreferenceChangedреалізації:

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

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

Це легко поширюється на інші класи переваг.

І, використовуючи getPreferenceCountі getPreferenceфункціональність PreferenceScreenі PreferenceCategory, ви могли б легко написати спільну функцію , щоб йти перевагу встановлює резюме всіх переваг типів ви бажаєте їх дерева toStringуявлення


6
приємне рішення справді. лише бракує ініціалізації
njzk2

9
@ njzk2, все, що вам потрібно зробити, це переконатися в активностіimplements OnSharedPreferenceChangeListener

4
NB: Є більш простий спосіб, див. Відповідь @ Робертаса .
Салман фон Аббас

6
Насправді ви можете встановити підсумок "%s"для ListPreferenceі ListPreference.getSummary()буде відформатувати підсумок із поточним вибраним записом (або ""якщо його не вибрано).
SOFe

findPreference (ключ) застарілий, чи є інший спосіб отримати доступ до цього?
Ніколи більше

144

Ось моє рішення ... 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 ... за винятком того, що в мене є екран налаштувань на екрані налаштувань. Будь-яка ідея, як дістатися до внутрішнього екрана налаштувань і заповнити їх підсумком?
taraloca

@taraloca - змінити if (p instanceof PreferenceCategory) {PreferenceCategory pCat = (PreferenceCategory) p; to if (p instanceof PreferenceGroup) {final PreferenceGroup pCat = (PreferenceGroup) p;
Мартін Жділа

це працює прекрасно , що , якщо EditTextPreferenceце android:password="true" він показує значення
Chathura Wijesinghe

1
Як я можу змінити код для відображення резюме з файлу ресурсу (xml), якщо значення не визначено (тобто if editTextPref.getText() == "")? Як отримати підсумкове значення updatePrefSummary? p.getSummary()і editTextPref.getSummary()повернути вже змінені значення.
LA_

Так як PreferenceCategoryі PreferenceScreenуспадковуватися від PreferenceGroup, я змінив , initSummaryщоб звертатися з PreferenceGroupзамість цього. Це дозволяє уникнути необхідності іншого циклу onCreate(). Зміна поведінки: вкладені PreferenceScreens тепер також обробляються рекурсивно.
Лекенштейн

96

Документація на Android говорить, що маркер форматування String можна використовувати в getSummary():

Якщо в резюме є маркер форматування рядка в ньому (тобто "% s" або "% 1 $ s"), то поточне значення введення буде замінено на його місці.

Просто вказавши android:summary="Clean up messages after %s days"в ListPreference XML-декларацію, яка працювала на мене.

Примітка. Це працює лише для ListPreference.


Хтось мене виправить, якщо я помиляюся, але в документації для getSummary () зазначено, що він був доданий на рівні API 1. Чи ви маєте на увазі, що поведінка була іншою при першому звільненні?
THEIT

10
На жаль, це працює лише для ListPreference. Я хочу те саме, що і для EditTextPreference. Дивно, що Google додав це не для всіх DialogPreferences.
Вікі

2
Плюс, я не працюю до тих пір, поки значення не встановлено - під час першого виклику функції "Налаштування" він відображає лише% s, що є дійсно німим.
Зордід

3
@ Zordid Це можна виправити, вказавши значення за замовчуванням у вашому xml, як android:defaultValue="0"у вашому ListPreference. Це найрозумніша відповідь і працює для мене.
Мохіт Сінгх

@Mohit Singh / @Zordid, в API Lollipop 22, defaultValueі %sне працюють. В інших версіях, як правило, він працює. Будь-яке рішення, будь ласка? Я впевнений, що не хочу писати для цього спеціальний клас. Неймовірно, що Google завдає найбільш тривіальних завдань таким болем.
Нараяна J

81

Якщо ви використовуєте PreferenceFragment, це я вирішив. Це само собою пояснюється.

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
За це рішення потрібно більше голосів ... Мене помиляє, що приклади на веб-сайті розробника ПОКАЗУють це, але пропускають його повністю.
Джастін Сміт

3
Щоб оновити EditTextPreferences, також оновіть додайте це до updatePreferenceCODE if (preference instanceof EditTextPreference) { EditTextPreference editTextPref = (EditTextPreference) preference; preference.setSummary(editTextPref.getText()); }завдяки @EddieB
Євген ван дер Мерве

6
Куди дзвонить 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 Я добре знаю, що ви цитуєте. Це говорить про те, що ви не використовуєте PreferenceActivity.findPreference(та кілька інших методів), тому що Google хоче, щоб ви перейшли на техніку, показану в цій відповіді, яка використовує PreferenceFragment.findPreferenceнатомість.
Dan Hulme

33

Мій варіант - розширити ListPreference і це чисто:

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

Потім ви додасте у ваші налаштування.xml:

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

Я прийняв рішення на основі цього. У своєму рішенні я маю метод встановити масив entrySummaries замість використання рядків записів як у меню, так і в підсумках. Тут є одна проблема: getEntry () повертає попереднє значення, а не нове.
pzulw

1
Насправді init () навіть необхідний? Я щойно переоцінив getSummary () і, здається, працює префектно!
Енді

4
Здається, набагато простішим та чистішим рішенням, ніж той, хто голосував вище!
muslidrikk

2
init()Функція необхідна для поновлення , summaryколи користувач змінює це перевагу. Без цього воно просто залишиться незалежно від того, наскільки це було спочатку.
anthonylawson

23

Ви можете замінити класи налаштувань за замовчуванням та реалізувати функцію.

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

Пізніше у вашому xml ви можете скористатись налаштованими налаштуваннями

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

Відмінний простий метод. Просто слідкуйте за такими речами, як% у рядку getEntry, оскільки вони можуть спричинити проблеми (або вони зробили для мене)
Ендрю

21

Через кілька годин, які мені витратили на вирішення такої проблеми, я реалізував цей код:

[ОНОВЛЕННЯ: остаточний список версій]

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

Це було єдине рішення, яке працювало для мене чудово. Перш ніж я спробував підклас з ListPreferences та реалізувати android: Summary = "bla bla bla% s". Жоден не працював.


Ваш спосіб більш зрозумілий і використовує менше коду, ніж інші. Верхня відповідь працює за допомогою "проксі" - менеджера налаштувань. Це не так зрозуміло, як прослуховування прямих змін у списку.
Павло Аннеков

@Subtle Fox, акуратне рішення. просто цікаво, якщо ви зробили "setDefaultValue ()", то навіщо перевіряти (ss == null)
Самуїл

Оскільки setDefaultValue () не повинно бути там :) Я поставив цей код перед рефакторингом
Subtle Fox

20

Можливо, як ListPreference: Змініть getSummary, щоб отримати те, що ви хочете:

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

І використовуйте це у своєму xml:

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

Таким чином, ви можете написати резюме %sзамість фактичного значення.


1
@Eruvanos @ serv-inc Принаймні з підкласом android.support.v7.preference.EditTextPreference, це не оновлює підсумок, коли змінюється налаштування, лише тоді, коли створена активність уподобань. OnSharedPreferenceChangeListener.onSharedPreferenceChangedandroid.support.v7.preference.EditTextPreference.setText(String text)@Override public void setText(String text) { super.setText(text); this.setSummary(this.getText()); }
Обхід

@PointedEars: зроблено. Але це також здається копією stackoverflow.com/a/21906829/1587329
serv-inc

18

Це код, необхідний для встановлення підсумків до обраного значення. Він також встановлює значення при запуску і поважає значення за замовчуванням, а не лише при зміні. Просто змініть "R.layout.prefs" на свій xml-файл і розширіть метод setSummary до ваших потреб. Він насправді обробляє лише ListPreferences, але його легко налаштувати, щоб поважати інші налаштування.

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


Дуже дякую! Я створив з цього клас, давши ідентифікатор ресурсу як аргумент onCreate () - таким чином, це змінило один рядок на екранах моїх налаштувань, щоб вони відображали підсумки значень.
Asmo Soinio

2
BTW: Зауважте, що непостійні налаштування не оновлюються за допомогою цієї системи. Зміни до них потрібно прослуховувати, використовуючи setOnPreferenceChangeListener(Preference.OnPreferenceChangeListener onPreferenceChangeListener)-метод індивідуальних налаштувань.
Asmo Soinio

11

Насправді CheckBoxPreference має можливість вказати інший підсумок на основі значення прапорця. Дивіться андроїд: SummaryOff та android: атрибути SumOO (а також відповідні методи CheckBoxPreference).


11

Для 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

Якщо хтось все ще шукає відповіді на це, вам слід ознайомитися з відповіддю тридцятирічного віку .

<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 замінить% s поточним значенням рядка в налаштуваннях, як відображається засобом вибору ListPreference.


Працює. Це найпростіше і найкраще рішення сьогодні.
davidgyoung

1
Зауважте, що "% s" може бути розміщено будь-де у вашому підсумковому рядку. І так, це включає рядки ресурсів!
Скотт Біггс

7

Дякую за цю пораду!

У мене є один екран налаштувань і я хочу відобразити значення для кожного списку як резюме.

Зараз це мій шлях:

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

Це працює для мене, але мені цікаво, що найкраще рішення (продуктивність, стабільність, масштабованість): те, що показує Коем чи це?


6

Дякую, Рето, за детальне пояснення!

Якщо це комусь допоможе, мені довелося змінити код, запропонований Рето Меєром, щоб він працював із SDK для 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            
    ...
}

Ця ж зміна стосується і функції зворотного виклику onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key)

Ура,

Кріс


4

Я вирішив проблему з наступним нащадком 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;
        }
    }
}

Мені здається, що це працює чудово для мене в 1.6 до 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

Я бачив, як усі відповіді, що проголосували, показують, як встановити резюме з точним поточним значенням, але ОП хотів також щось подібне:

"Очистити повідомлення через х днів" * <- підсумок, де x - поточне значення налаштування

Ось моя відповідь за досягнення цього

Як свідчить документація про ListPreference.getSummary():

Повертає резюме цього списку. Якщо в резюме є маркер форматування рядка в ньому (тобто "% s" або "% 1 $ s"), то поточне значення введення буде замінено на його місці.

Однак я спробував на декількох пристроях, і, схоже, це не працює. За допомогою деяких досліджень я знайшов вдале рішення у цій відповіді . Він просто полягає у розширенні кожного Preferenceвикористання та переходу getSummary()на роботу, як визначено документацією на Android.


1
Це, здається, працює спочатку, але коли ви вибираєте нове значення, воно не оновлюється автоматично, поки ви не зробите щось для того, щоб визначити недійсним всю активність і призвести до її перемальовування. Я на Android 4.0.4.
ейдилон

Було б добре, якби Google міг додати рядок форматування до об’єкта уподобань.
Джастін Сміт

3

Якщо ви хочете лише відобразити звичайне текстове значення кожного поля як його підсумок, наступний код повинен бути найпростішим у обслуговуванні. Для цього потрібно лише дві зміни (рядки 13 та 21, позначені "змінити тут"):

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

Ось моє рішення:

Побудувати метод "тип" вподобання типу вподобання.

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

Побудувати метод '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()");
    }

Ініціалізуйте

Створіть публічний клас, що PreferenceActivity та реалізує 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.

Все більше підстав дивитися на самому плямі Answerз @ASD вище ( тут джерело ) , що говорить використовувати %sв android:summaryдля кожного поля preferences.xml. (Поточне значення переваги замінено %s.)

введіть тут опис зображення

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

3

Оскільки в класі Preference androidx є інтерфейс SummaryProvider , це можна зробити без OnSharedPreferenceChangeListener. Прості реалізації передбачені для EditTextPreference та ListPreference. Спираючись на відповідь Едді, це може виглядати приблизно так. Тестовано на androidx.preference: перевагу: 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

Тут все це вирізано із зразка Eclipse SettingsActivity. Мені доведеться скопіювати всі ці занадто багато кодів, щоб показати, як ці розробники Android вибирають ідеально для більш узагальненого та стабільного стилю кодування.

Я залишив коди адаптації PreferenceActivityпланшетного ПК та більшого 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>

ПРИМІТКА: Насправді я просто хочу прокоментувати на зразок "зразок Google для PreferenceActivity також цікавий". Але у мене недостатньо репутаційних очок. Тож, будь ласка, не звинувачуйте мене.

(Вибачте за погану англійську)


2

Ви повинні використовувати функцію bindPreferenceSummaryToValue у методі onCreate.

Приклад:

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

Дивіться урок 3 з курсу Android Udacity: https://www.udacity.com/course/viewer#!/c-ud853/l-1474559101/e-1643578599/m-1643578601


2

Для EditTextPreference :

Я, звичайно, прийшов до цього рішення, просто якщо вам потрібна певна редагування текстових налаштувань, але ви можете це робити з усіма налаштуваннями:

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

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

            }
}

Потім у 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);
        }

В:

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

2

Моє рішення - створити користувацький EditTextPreference, який використовується в XML, як це:<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

Щоб встановити підсумок а ListPreferenceдо значення, вибраного в діалоговому вікні, ви можете використовувати цей код:

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

і посилайтеся на yourpackage.ListPreferenceоб'єкт в preferences.xmlзапам'ятовуванні, щоб вказати там свій, android:defaultValueоскільки це викликає виклик onSetInitialValue().

Якщо ви хочете, ви можете змінити текст перед тим, як зателефонувати setSummary()на те, що підходить для вашої програми.


1

Оскільки я використовую нестандартний PreferenceDataStore, я не можу додати слухача до деяких, SharedPreferenceтому мені довелося написати дещо хакітне рішення, яке прислухається до кожного параметра:

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

Якщо ви використовуєте AndroidX, ви можете скористатися користувацькимSummaryProvider . Цей підхід можна використовувати для будь-якого Preference.

Приклад з документації (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();
    }
});

Приклад з документації (Котлін):

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
    }
}
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.