如何在Android Preference摘要中显示当前值?

476

这种情况经常出现。

当用户在Android应用程序中编辑首选项时,我希望他们能够在首选项摘要中看到当前设置的首选项值。

例如:如果我有一个Preference设置“丢弃旧消息”,指定多少天后需要清理消息。在PreferenceActivity中,我希望用户看到:

“丢弃旧消息” <- 标题

“在x天后清理消息” <- 摘要,其中x是当前首选项值

额外加分:使其可重复使用,以便我可以轻松地将其应用于所有首选项,而不考虑它们的类型(因此它使用最少的编码与EditTextPreference、ListPreference等一起使用)。

36个回答

1
因为我正在使用自定义的PreferenceDataStore,所以无法向某些SharedPreference添加监听器,因此我不得不编写一个有点hacky的解决方案来监听每个偏好设置:
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)
}

0
我发现了一种方法,可以让支持库中的EditTextPreference处理摘要中的"%s"(就像ListPreference已经处理的那样):
public class EditTextPreference extends android.support.v7.preference.EditTextPreference {
    public EditTextPreference(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    @Override
    public void setText(String text) {
        super.setText(text);
        notifyChanged();
    }

    @Override
    public CharSequence getSummary() {
        String text = super.getText();
        String summary = super.getSummary().toString();
        return String.format(summary, text == null ? "" : text);
    }
}

在 XML 中它会看起来像这样:

<com.example.yourapp.EditTextPreference
    android:defaultValue="1"
    android:key="cleanup_period"
    android:summary="Clean up messages after %s days"
    android:title="Clean up period" />

0

这里是一个可行的解决方案,适用于所有在基于PreferenceFragment中的EditTextPreference,基于@tdeveaux的答案:

public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
    private static final String TAG = "SettingsFragment";

    @Override
    public void onCreate (Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        addPreferencesFromResource(R.xml.preferences);
        getPreferenceScreen().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onResume () {
        super.onResume();

        for (int i = 0; i < getPreferenceScreen().getPreferenceCount(); ++i) {
            Preference preference = getPreferenceScreen().getPreference(i);
            updatePreference(preference);
        }
    }

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

    private void updatePreference (Preference preference) {
        if (preference instanceof EditTextPreference) {
            EditTextPreference editTextPreference = (EditTextPreference)preference;
            editTextPreference.setSummary(editTextPreference.getText());
        }
    }
}

你需要注销监听器。 - Style-7

0
@tdevaux提出了一个好的解决方案above,但它只能部分地工作;因为在sharedPreferences中不仅有字符串值,还有错误:

  • android.content.res.Resources$NotFoundException: String resource ID #0xc83
  • java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String

因此,我对updatePreferences方法进行了更改,添加了不同类型的Preferences的switch语句,以避免类型转换错误:

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

switch (key) {
    // integer values assignment
    case "prf_points":
    case "prf_hours":
    case "prf_level":
        preference.setSummary("" + sharedPrefs.getInt(key, 0));
        break;

    // String values assignment
    case "prf_user_name":
    case "prf_user_email":
        preference.setSummary(sharedPrefs.getString(key, "-"));
        break;
    default:
        break;
}

}


-1

一行代码的简洁解决方案:

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.preferences);

    bindPreferenceSummaryToValue(findPreference("mySetting"));

    // initialize summary
    sBindPreferenceSummaryToValueListener.onPreferenceChange(findPreference("mySetting"), 
        ((ListPreference) findPreference("mySetting")).getEntry());
}

好的,bindPreferenceSummaryToValue() 是什么?另外,这不是你所说的一行代码。 - Stealth Rabbi

-1

只需将以下代码添加到您的 XML 规范中即可。

app:useSimpleSummaryProvider="true"

例如:

<your.package.name.MyListPreference

android:key="noteInterval"
android:defaultValue="60"
android:title="Notification Interval"
android:entries="@array/noteInterval"
android:entryValues="@array/noteIntervalValues"
app:useSimpleSummaryProvider="true"

/>


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接