在摘要中显示EditTextPreference的值

19

我正在学习如何在Android上进行开发,并想制作一个设置活动。

我的设置活动

public class Main extends Activity  {


    protected SettingsFragment settingsFragment;


    @SuppressLint("NewApi")
    @TargetApi(11)
    public class SettingsFragment extends PreferenceFragment implements
            SharedPreferences.OnSharedPreferenceChangeListener {


        @Override
        public void onCreate(Bundle savedInstanceState) {

            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.preferences);
            setSummaries();


        }


        @Override
        public void onResume() {
            final SharedPreferences sh = getPreferenceManager().getSharedPreferences() ;
            super.onResume();
            sh.registerOnSharedPreferenceChangeListener(this);

        }

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

        @SuppressLint("NewApi")
        public void setSummaries(){

           final SharedPreferences sh = getPreferenceManager().getSharedPreferences() ;


            //Pref1
            Preference stylePref = findPreference("editTextPref");
            stylePref.setSummary(sh.getString("editTextPref", ""));

            //here the other preferences..
        }


        @Override
        public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
            if (key.equals("editTextPref")) {
                Preference pref = settingsFragment.findPreference(key);
                // Set summary to be the user-description for the selected value
                pref.setSummary(sharedPreferences.getString(key, ""));

            }
            //here the others preferences
        }
    }//End fragment

    @SuppressLint("NewApi")
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        settingsFragment = new SettingsFragment();
        getFragmentManager().beginTransaction()
                .replace(android.R.id.content, settingsFragment)
                .commit();


    }


}

我的res/preferences.xml文件

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


        <EditTextPreference
            android:key="editTextPref"
            android:title="Numero de telephone"
            android:summary="This allows you to enter a string"
            android:defaultValue="*"/>

    </PreferenceCategory>

</PreferenceScreen>

现在我有了设置活动的活动。但是我想在android:summary中显示EditTextPref的值。 我找到了很多主题,但所有函数都已被弃用。

编辑:感谢@Ace_McIntosh,我编辑了我的代码供需要的人使用,现在它可以工作了。

9个回答

22

如果您正在使用 AndroidX设置库,则可以使用属性app:useSimpleSummaryProvider。例如:

<EditTextPreference
        app:key="edittext"
        app:title="@string/title_edittext_preference"
        app:useSimpleSummaryProvider="true"
        app:dialogTitle="@string/dialog_title_edittext_preference"/>

您可以在这里阅读一个完整的可工作示例。


2
这也应该被接受为答案。同时在运行时:preference.summaryProvider = EditTextPreference.SimpleSummaryProvider.getInstance() //kotlin - heshuimu

9

只需重写EditTextPreferencegetSummary方法,就可以获得一个将其值显示为摘要的EditTextPreference

public class EditSummaryPreference extends EditTextPreference {
    ...// omit constructor

    @Override
    public CharSequence getSummary() {
        return getText();
    }
}

这实际上是最简单的答案,因为它不需要更改片段或活动中的任何代码,也不需要更改与处理或创建设置相关的任何代码。 - Martin
2
但是如果用户更改了值,那么摘要不会更新,对吧? - tobltobs

5
只需在所需的首选项对象上使用setSummary method。对于您要更新的每个条目(即,在您的情况下,所有EditTextPreference条目),在恢复设置片段时调用它,并在具体的SharedPreferences对象上注册一个OnSharedPreferenceChangeListener(以便在更改摘要时可以更新它),并传递所需的EditTextPreference的值(您可以通过其getText()方法获取该值)。
像这样在您的MyPreferenceFragment中实现它(我不能保证它会立即起作用,它只是为了给您提供一个想法)。
public class MyPreferenceFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {
    SharedPreferences sharedPreferences;

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

        // load the preferences from your XML resource (which I assume you already do anyway)
        addPreferencesFromResource(R.xml.preferences);
    }

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

        sharedPreferences = getPreferenceManager().getSharedPreferences();

        // we want to watch the preference values' changes
        sharedPreferences.registerOnSharedPreferenceChangeListener(this);

        Map<String, ?> preferencesMap = sharedPreferences.getAll();
        // iterate through the preference entries and update their summary if they are an instance of EditTextPreference
        for (Map.Entry<String, ?> preferenceEntry : preferencesMap.entrySet()) {
            if (preferenceEntry instanceof EditTextPreference) {
                updateSummary((EditTextPreference) preferenceEntry);
            }
        }
    }

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

    @Override
    public void onSharedPreferenceChanged(SharedPreferences sharedPreferences,
                                          String key) {
        Map<String, ?> preferencesMap = sharedPreferences.getAll();

        // get the preference that has been changed
        Object changedPreference = preferencesMap.get(key);
        // and if it's an instance of EditTextPreference class, update its summary
        if (preferencesMap.get(key) instanceof EditTextPreference) {
            updateSummary((EditTextPreference) changedPreference);
        }
    }

    private void updateSummary(EditTextPreference preference) {
        // set the EditTextPreference's summary value to its current text
        preference.setSummary(preference.getText());
    }
}

3
问题在于addPreferencesFromResource已经过时。 - user3130417
3
addPreferencesFromResource() 方法仅在 PreferenceActivity 类中已被弃用,您需要在 PreferenceFragment 类中调用它(在该类中它没有被弃用,您可以在文档中看到)。确保使用片段(您并没有发布它的代码,我只看到您在活动类中创建了一个 MyPreferenceFragment 的新实例)。另请注意,PreferenceFragment 的父活动不必扩展 PreferenceActivity,它可以是普通的活动。 - Ace_McIntosh
4
你需要通过SharedPreferences对象的registerOnSharedPreferenceChangeListener方法注册一个偏好设置更改监听器,并在监听器中处理更新。在我发布给你的代码示例中,有一个如何执行此操作的示例,该监听器就是MyPreferenceFragment类本身(它必须实现适当的接口),并且正如你所看到的,它包含onSharedPreferenceChanged回调函数,在其中你应该更新正在更改的偏好设置的摘要。如果你这样做,每当首选项的值更改时,摘要都会被更新。 - Ace_McIntosh
3
你应该将那段代码放在onResume()生命周期方法中,因为你需要每次片段进入前台时都调用它。我建议你将sh变量作为类字段引入,在你的onResume()中调用这个:sh.registerOnSharedPreferenceChangeListener(Main.this)。同时,别忘了在onPause()方法中注销回调,使用sh.unregisterOnSharedPreferenceChangeListener(Main.this)(如果不这样做,当放弃并返回设置片段并调用监听器时,你可能会遇到空指针异常)。 - Ace_McIntosh
3
是的,将您的SettingsFragment类实例化,而不是静态的,否则您将无法访问父对象。为了方便起见,我建议您使父Activity类干净,并使片段实现SharedPreferences.OnSharedPreferenceChangeListener - 这样,您将能够重用SharedPreferences类字段(在引入它之后,前提是您会这样做)。 - Ace_McIntosh
显示剩余4条评论

5
(在Kotlin中)我更喜欢做一些更简单的事情,只需创建一个扩展EditTextPreference的类:
import android.content.Context
import android.support.v7.preference.EditTextPreference
import android.util.AttributeSet

/**
 * This class was created by Anthony M Cannon on 17/04/2018.
 */
class SummarisedEditTextPreference @JvmOverloads constructor(context: Context,
    attrs: AttributeSet? = null) : EditTextPreference(context, attrs) {

    private var mOnChangeListener: OnPreferenceChangeListener? = null

    init {
        super.setOnPreferenceChangeListener { preference, newValue ->
            summary = newValue as String
            mOnChangeListener?.onPreferenceChange(preference, newValue) ?: true
        }
    }

    /**
    * Called when this Preference has been attached to a Preference hierarchy.
    * Make sure to call the super implementation.
    *
    * @param preferenceManager The PreferenceManager of the hierarchy.
    */
    override fun onAttachedToHierarchy(preferenceManager: PreferenceManager) {
        super.onAttachedToHierarchy(preferenceManager)
        summary = sharedPreferences.getString(key, null)
    }


    /**
     * Sets the callback to be invoked when this Preference is changed by the
     * user (but before the internal state has been updated).
     *
     * @param onPreferenceChangeListener The callback to be invoked.
     */
    override fun setOnPreferenceChangeListener(
        onPreferenceChangeListener: OnPreferenceChangeListener) {
        mOnChangeListener = onPreferenceChangeListener
    }
}

你可以按以下方式使用它: <<你的包名>.SummarisedEditTextPreference/>

1
在这种情况下,构造函数的'@JvmOverloads'不起作用,因为您没有以这种方式调用'super'构造函数,因此'EditTextPreferences'的样式将不会应用。请尝试使用以下构造函数代替:'constructor(context: Context) : super(context)'、'constructor(context: Context, attrs: AttributeSet?) : super(context, attrs)'和'constructor(context: Context, attrs: AttributeSet?, defStyleAttr: Int) : super(context, attrs, defStyleAttr)'。 - tobltobs

5

1
请不要发布解决方案的链接。仅使用它们来支持您的解决方案。 - Urosh T.
1
太棒了!不需要更改任何代码。实际的 XML 是 app:useSimpleSummaryProvider="true",并且它是在 preference:1.1.0-alpha01 中添加的。 - ronginat

3

上面发布的示例中存在一些错误,因此我认为我应该发布一个可行的解决方案(还支持ListPreference和MultiSelectListPreference)

public class SettingsFragment extends PreferenceFragment implements SharedPreferences.OnSharedPreferenceChangeListener {

private SharedPreferences sharedPreferences;

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

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

    sharedPreferences = getPreferenceManager().getSharedPreferences();
    sharedPreferences.registerOnSharedPreferenceChangeListener(this);

    PreferenceScreen preferenceScreen = getPreferenceScreen();
    for(int i = 0; i < preferenceScreen.getPreferenceCount(); i++) {
        setSummary(getPreferenceScreen().getPreference(i));
    }
}

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

@Override
public void onSharedPreferenceChanged(SharedPreferences sharedPreferences, String key) {
    Preference pref = getPreferenceScreen().findPreference(key);
    setSummary(pref);
}

private void setSummary(Preference pref) {
    if (pref instanceof EditTextPreference) {
        updateSummary((EditTextPreference) pref);
    } else if (pref instanceof ListPreference) {
        updateSummary((ListPreference) pref);
    } else if (pref instanceof MultiSelectListPreference) {
        updateSummary((MultiSelectListPreference) pref);
    }
}

private void updateSummary(MultiSelectListPreference pref) {
    pref.setSummary(Arrays.toString(pref.getValues().toArray()));
}

private void updateSummary(ListPreference pref) {
    pref.setSummary(pref.getValue());
}

private void updateSummary(EditTextPreference preference) {
    preference.setSummary(preference.getText());
}
}

对于ListPreferences,您可以使用'android:summary="%s"'来将值显示为摘要。 - tobltobs

1
在Brett Cherrington的答案基础上,这是Kotlin的实现。存在一个错误,即不支持PreferenceCategories,这个问题通过在setSummary中添加一个递归循环得到解决。
class SettingsFragment : PreferenceFragment(), SharedPreferences.OnSharedPreferenceChangeListener {

    private lateinit var sharedPreferences: SharedPreferences

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        addPreferencesFromResource(R.xml.preferences)
    }

    override fun onResume() {
        super.onResume()

        sharedPreferences = preferenceManager.sharedPreferences
        sharedPreferences.registerOnSharedPreferenceChangeListener(this)

        val preferenceScreen = preferenceScreen
        for (i in 0 until preferenceScreen.preferenceCount) {
            setSummary(getPreferenceScreen().getPreference(i))
        }
    }

    override fun onPause() {
        sharedPreferences.unregisterOnSharedPreferenceChangeListener(this)
        super.onPause()
    }

    override fun onSharedPreferenceChanged(sharedPreferences: SharedPreferences, key: String) {
        val pref = preferenceScreen.findPreference(key)
        pref?.let { setSummary(it) }
    }

    private fun setSummary(pref: Preference) {
        if (pref is EditTextPreference) {
            updateSummary(pref)
        } else if (pref is ListPreference) {
            updateSummary(pref)
        } else if (pref is MultiSelectListPreference) {
            updateSummary(pref)
        } else if (pref is PreferenceCategory){
            // needs to loop through child preferences
            for (i in 0 until pref.preferenceCount) {
                setSummary(pref.getPreference(i))
            }
        }
    }

    private fun updateSummary(pref: MultiSelectListPreference) {
        pref.setSummary(Arrays.toString(pref.values.toTypedArray()))
    }

    private fun updateSummary(pref: ListPreference) {
        pref.summary = pref.value
    }

    private fun updateSummary(preference: EditTextPreference) {
        preference.summary = preference.text
    }
}

1

@serv-inc的答案对我有用。不知为什么其他答案只在值更改时才起作用。

但在它起作用之前,我需要进行以下更改:

@Override
public CharSequence getSummary() {
    return getText();
}

当它最初显示值时,显示值更改时以及恢复后都会显示该值。


你必须更改getSummary(),因为@serv-inc的答案将android:summary="Actual value: %s"字段设置为用于字符串格式。 - Marshall Asch

0
除了 @Eke Koseoglu 的回答外。 如果您使用 AndroidX preference 库,您可以在下面的 Kotlin 代码中设置 summaryProvider。
val editTextPreference = EditTextPreference(context)
editTextPreference.summaryProvider = EditTextPreference.SimpleSummaryProvider.getInstance()

根据 EditTextPreference.SimpleSummaryProvider 的文档;
如果没有设置任何值,显示的摘要将为“未设置”,否则将显示为此首选项设置的值。

如何从键中获取值,例如 app:key="city" - CoolMind

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