简体   繁体   English

使用新值更改 ListPreference 的摘要 (Android)

[英]Change the summary of a ListPreference with the new value (Android)

How can I modify the summary of a ListPreference to the new "Entry" string selected by the user (not the entry value)如何将 ListPreference 的摘要修改为用户选择的新“条目”字符串(不是条目值)

I suppouse its with setOnPreferenceChangeListener() but in我认为它与 setOnPreferenceChangeListener() 但在

new OnPreferenceChangeListener() {

        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            return true;
        }
    }

using ((ListPreference)preference).getEntry() I get the old value (because it isn't changed yet) and newValue.toString() returns the entry value (not the entry text displayed to the user)使用 ((ListPreference)preference).getEntry() 我得到旧值(因为它尚未更改)并且 newValue.toString() 返回条目值(不是显示给用户的条目文本)

How can I do it?我该怎么做? Thanks in advance提前致谢

Just set the summary value to %s in the xml description.只需在 xml 描述中将汇总值设置为%s即可。

EDIT : I've tested it on several devices and it doesn't work really.编辑:我已经在几台设备上对其进行了测试,但它并没有真正起作用。 That's strange because according to docs it must work: ListPreference.getSummary() .这很奇怪,因为根据文档它必须工作: ListPreference.getSummary()

But it's possible to implement this functionality by oneself.但是可以自己实现这个功能。 The implementation requires to inherit from the ListPreference class:该实现需要从ListPreference class 继承:

public class MyListPreference extends ListPreference {
    public MyListPreference(final Context context) {
        this(context, null);
    }

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

    @Override
    public CharSequence getSummary() {
        final CharSequence entry = getEntry();
        final CharSequence summary = super.getSummary();
        if (summary == null || entry == null) {
             return null;
        } else {
            return String.format(summary.toString(), entry);
        }
    }

    @Override
    public void setValue(final String value) {
        super.setValue(value);
        notifyChanged();
    }
}

As you can see MyListPreference has its own summary field which can contain formatting markers.如您所见MyListPreference有自己的汇总字段,可以包含格式标记。 And when a preference's value changes, Preference.notifyChanged() method is called and it causes MyListPreference.getSummary() method to be called from Preference.onBindView() .当首选项的值发生变化时,会调用Preference.notifyChanged()方法,并导致从Preference.onBindView()调用MyListPreference.getSummary()方法。

PS: This approach hasn't been tested sufficiently so it may contain errors. PS:此方法尚未经过充分测试,因此可能包含错误。

Nauman Zubair is right.瑙曼祖拜尔是对的。

The %s implementation is buggy. %s实现是错误的。 The view shows the correct value on first load (if a default list value is set), but the view does not update when selecting a list item.视图在首次加载时显示正确的值(如果设置了默认列表值),但在选择列表项时视图不会更新。 You have to toggle a checkbox or some other preference to update the view.您必须切换复选框或其他一些偏好来更新视图。

As a workaround, implement OnSharedPreferenceChangeListener to override the summary for the list preference.作为一种解决方法,实施OnSharedPreferenceChangeListener以覆盖列表首选项的摘要。

/src/apps/app_settings/SettingsActivity.java /src/apps/app_settings/SettingsActivity.java

package apps.app_settings;

import android.os.Bundle;
import android.preference.PreferenceActivity;

public class SettingsActivity extends PreferenceActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /* set fragment */
        getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
    }
}

/src/apps/app_settings/SettingsFragment.java /src/apps/app_settings/SettingsFragment.java

package apps.app_settings;

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

public class SettingsFragment extends PreferenceFragment implements OnSharedPreferenceChangeListener {
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        /* set preferences */
        addPreferencesFromResource(R.xml.preferences);
    }

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
        /* get preference */
        Preference preference = findPreference(key);

        /* update summary */
        if (key.equals("list_0")) {
            preference.setSummary(((ListPreference) preference).getEntry());
        }
    }

    @Override
    public void onResume() {
        super.onResume();
        getPreferenceManager().getSharedPreferences().registerOnSharedPreferenceChangeListener(this);
    }

    @Override
    public void onPause() {
        getPreferenceManager().getSharedPreferences().unregisterOnSharedPreferenceChangeListener(this);
        super.onPause();
    }
}

/res/xml/preferences.xml /res/xml/preferences.xml

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen
  xmlns:android="http://schemas.android.com/apk/res/android">
  <ListPreference
    android:key="list_0"
    android:title="@string/settings_list_0_title"
    android:summary="%s"
    android:entries="@array/settings_list_0_entries"
    android:entryValues="@array/settings_list_0_entry_values"
    android:defaultValue="@string/settings_list_0_default_value"/>
</PreferenceScreen>

/res/values/strings.xml /res/values/strings.xml

<?xml version="1.0" encoding="utf-8"?>
<resources>
  <string name="settings_list_0_title">list 0</string>
  <string-array name="settings_list_0_entries">
    <item>item 0</item>
    <item>item 1</item>
    <item>item 2</item>
  </string-array>
  <string-array name="settings_list_0_entry_values">
    <item>0</item>
    <item>1</item>
    <item>2</item>
  </string-array>
  <string name="settings_list_0_default_value">0</string>
</resources>

i solved this problem with another and simple solution (https://gist.github.com/brunomateus/5617025) :我用另一个简单的解决方案解决了这个问题(https://gist.github.com/brunomateus/5617025)

public class ListPreferenceWithSummary extends ListPreference{

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

public ListPreferenceWithSummary(Context context) {
    super(context);
}

@Override
public void setValue(String value) {
    super.setValue(value);
    setSummary(value);
}

@Override
public void setSummary(CharSequence summary) {
    super.setSummary(getEntry());
}
}

This worked very fine on my GirgerBeard device.这在我的 GirgerBeard 设备上运行良好。 Even when is the first time running your app.即使是第一次运行您的应用程序。 Don't forget to provide default value on your xml prefence:不要忘记在您的 xml 偏好设置上提供默认值:

android:defaultValue="default value"

and set default values on your PreferenceActivity or PrefenceFragment :并在您的PreferenceActivityPrefenceFragment上设置默认值:

 PreferenceManager.setDefaultValues(this, R.xml.you pref file, false);

I recommend to implement the OnSharedPreferenceChangeListener in your PreferenceFragment or PreferenceActivity instead of Preference.setOnPreferenceChangeListner.我建议在您的 PreferenceFragment 或 PreferenceActivity 中实现 OnSharedPreferenceChangeListener 而不是 Preference.setOnPreferenceChangeListner。 Use setSummay to set the new changes.使用 setSummay 设置新的更改。 (Do not forget to register and unregister the listener.) This listener is called after the change to the preference has been completed. (不要忘记注册和取消注册监听器。)在对首选项的更改完成后调用此监听器。 You should also set a default value in the XML for the preferences.您还应该在 XML 中为首选项设置默认值。

The "%s" solution works for me on android 4.0.3, by writting %s directly in the XML file.通过将 %s 直接写入 XML 文件,“%s”解决方案适用于 android 4.0.3。 The problem is the text is not updated after I changed the value of the preference but it is when I modify another preference of my PreferenceScreen.问题是在我更改了首选项的值后文本没有更新,但是当我修改了我的 PreferenceScreen 的另一个首选项时。 Maybe some refresh is missing here.也许这里缺少一些刷新。

This is the most simplified way I have implemented.这是我实现的最简化的方式。 Just take the values given by the onPreferenceChange listener只需取 onPreferenceChange 监听器给出的值

    ListPreference preference;        
    @Override
    protected void onCreate(Bundle savedInstanceState) {
    preference = (ListPreference)findPreference("myKey");
    preference.setSummary(preferenceColorButtons.getEntry());
    preference.setOnPreferenceChangeListener(new        OnPreferenceChangeListener() {

        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            ListPreference listPreference = (ListPreference)preference;
            int id = 0;
            for (int i = 0; i < listPreference.getEntryValues().length; i++)
            {
                if(listPreference.getEntryValues()[i].equals(newValue.toString())){
                    id = i;
                    break;
                }
            }
            preference.setSummary(listPreference.getEntries()[id]);
            return true;
        }
    });

} }

For all I know:据我所知:

a) The %s does work on android 4, but not on 2.x. a) %s 确实适用于 android 4,但不适用于 2.x。

b) The update is achieved if you set a dummy value in between, see here: https://stackoverflow.com/a/16397539/1854563 b)如果您在两者之间设置一个虚拟值,则可以实现更新,请参见此处: https://stackoverflow.com/a/16397539/1854563

There is no need to extend ListPreference or to loop over the entryValues etc无需扩展 ListPreference 或遍历 entryValues 等

public boolean onPreferenceChange(Preference preference, Object newValue) {
    int i = ((ListPreference)preference).findIndexOfValue(newValue.toString());
    CharSequence[] entries = ((ListPreference)preference).getEntries();
    preference.setSummary(entries[i]);

    return true;
}

I know that it's a very old question, but it's still actual.我知道这是一个非常古老的问题,但它仍然是实际的。 To have the summary automatically updated you have to call the original preferenceChangeListener:要自动更新摘要,您必须调用原始的preferenceChangeListener:

final OnPreferenceChangeListener listener = preference.getOnPreferenceChangeListener();
preference.setOnPreferenceChangeListener(new Preference.OnPreferenceChangeListener()
        {
            @Override
            public boolean onPreferenceChange(Preference preference, Object o)
            {
                if (listener !=null)
                    listener .onPreferenceChange(preference, o);

                return true;
            }
        });

I also faced this problem and I finally found a solution by using the value coming from the listener.我也遇到了这个问题,我终于通过使用来自侦听器的值找到了解决方案。 In my example below (for a ListPreference), I first get the index of the value in the ListPreference array, then I retrieve the label of the value using this index:在下面的示例中(对于 ListPreference),我首先获取 ListPreference 数组中值的索引,然后使用该索引检索该值的 label:

passwordFrequencyLP.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
        @Override
        public boolean onPreferenceChange(Preference preference, Object newValue) {
            int newFrequency = Integer.valueOf(newValue.toString());

            prefs.edit().putInt("settings_key_password_frequency", newFrequency).commit();

            //get the index of the new value selected in the ListPreference array
            int index = passwordFrequencyLP.findIndexOfValue(String.valueOf(newValue));
            //get the label of the new value selected
            String label = (String) passwordFrequencyLP.getEntries()[index];

            passwordFrequencyLP.setSummary(label);

            makeToast(getResources().getString(R.string.password_frequency_saved));
            return true;
        }
    });

This little trick works well, I found many different possible solutions to this problem but only this one worked for me.这个小技巧效果很好,我找到了许多不同的可能解决方案,但只有这个对我有用。

Hi edited the above for EditText if that helps:)如果有帮助,您好为 EditText 编辑了上述内容:)

package fr.bmigette.crocoschedulerconsoleandroid;
import android.content.Context;
import android.preference.EditTextPreference;
import android.util.AttributeSet;

/**
 * Created by bastien on 28/07/2015.
 */
public class EditTextPreferenceWithSummary extends EditTextPreference{
    public EditTextPreferenceWithSummary(Context context, AttributeSet attrs) {
        super(context, attrs);
    }

    public EditTextPreferenceWithSummary(Context context) {
        super(context);
    }

    @Override
    public void setText(String value) {
        super.setText(value);
        setSummary(value);
    }

    @Override
    public void setSummary(CharSequence summary) {
        super.setSummary(getText());
    }
}

And creates the preference.xml like this:并像这样创建preference.xml:

<?xml version="1.0" encoding="utf-8"?>
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android" >

    <PreferenceCategory
        android:key="pref_key_category_host"
        android:title="@string/title_category_host" >
        <fr.bmigette.crocoschedulerconsoleandroid.EditTextPreferenceWithSummary
            android:defaultValue="@string/default_pref_host_1"
            android:key="pref_key_host_1"
            android:summary="@string/default_pref_host_1"
            android:title="@string/title_pref_host_1" />

        <fr.bmigette.crocoschedulerconsoleandroid.EditTextPreferenceWithSummary
            android:defaultValue="@string/default_pref_port_1"
            android:key="pref_key_port_1"
            android:summary="@string/default_pref_port_1"
            android:title="@string/title_pref_port_1" />

        <fr.bmigette.crocoschedulerconsoleandroid.EditTextPreferenceWithSummary
            android:defaultValue="@string/default_pref_pass_1"
            android:key="pref_key_pass_1"
            android:summary="@string/default_pref_pass_1"
            android:title="@string/title_pref_pass_1" />

    </PreferenceCategory>
</PreferenceScreen>

There is no need to do those extra coding, i have faced this problem and solved it by a single line.无需进行那些额外的编码,我已经遇到了这个问题并通过一行解决了它。

After many hours looking on all the answers in this and other similar questions, i found out very easiest way to do this without extending ListPreference , you can do it in common extends PreferenceActivity , see the code bellow.经过数小时查看此问题和其他类似问题的所有答案后,我发现了无需扩展ListPreference的最简单方法,您可以共同extends PreferenceActivity ,请参见下面的代码。

public class UserSettingsActivity extends PreferenceActivity 
{
    ListPreference listpref;

    @Override
    public void onCreate(Bundle savedInstenceState)
    {
        super.onCreate(savedInstenceState);
        addPreferencesFromResource(R.xml.settings);
        listpref = (ListPreference)findPreference("prefDefaultCurrency");

        listpref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() 
        {           
            @Override
            public boolean onPreferenceChange(Preference preference, Object value) {
            // TODO Auto-generated method stub

            listpref.setSummary(listpref.getEntries()[Integer.parseInt(value.toString())]);
            return true;
        }
    });

Thats it, with a single line, all you have to do is get value passed from the onPreferenceChange(Preference preference, Object value) parse it to integer and pass it to listpref.setSummary(listpref.getEntries()[Integer.parseInt(value.toString())]);就是这样,只需一行,您所要做的就是获取从onPreferenceChange(Preference preference, Object value)传递的值,将其解析为 integer 并将其传递给listpref.setSummary(listpref.getEntries()[Integer.parseInt(value.toString())]);

Referring to the accepted answer ( @Michael ), if you modify the MyListPreference to add an onPreferenceChangeListener:参考接受的答案 (@Michael),如果您修改 MyListPreference 以添加 onPreferenceChangeListener:

public MyListPreference(final Context context, final AttributeSet attrs) {
    super(context, attrs);
    setOnPreferenceChangeListener(this);
}

and have the listener implementation return true:并让监听器实现返回 true:

public boolean onPreferenceChange(Preference preference, Object newValue) {
    // Do other stuff as needed, e.g. setTitle()
    return true;
}

the summary '%s' always resolves to the latest setting.摘要“%s”始终解析为最新设置。 Otherwise, it always has the default setting.否则,它始终具有默认设置。

Don't forget to add implements:不要忘记添加工具:

public class MyListPreference extends ListPreference implements Preference.OnPreferenceChangeListener

Simplest way in Kotlin Kotlin 中最简单的方法

findPreference<ListPreference>(getString(R.string.pref_some_key)).apply {
    summary = entry
    setOnPreferenceChangeListener { _, newValue ->
        summary = entries[entryValues.indexOf(newValue)]
        return@setOnPreferenceChangeListener true
    }
}

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM