我有一系列(Sub)PreferenceScreens的PreferenceActivity。每个此类(子)首选项屏幕代表一个帐户,并将帐户用户名作为其标题。
PreferenceScreen root = mgr.createPreferenceScreen(this);
for (MyAccountClass account : myAccounts) {
final PreferenceScreen accScreen = mgr.createPreferenceScreen(this);
accScreen.setTitle(account.getUsername());
// add Preferences to the accScreen
// (for instance a "change username"-preference)
...
root.add(accScreen);
}
当用户输入子PreferenceScreen并编辑帐户用户名时,我希望外部PreferenceScreen更新它的相关帐户的PreferenceScreen标题。
我试图添加......
usernamePref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
public boolean onPreferenceChange(Preference preference, Object newValue) {
accScreen.setTitle(newValue.toString());
return true;
}
});
...但是accScreen.setTitle似乎对外部PreferenceScreen没有生效。我注意到调用onContentChanged();
实际上使它工作,但我意识到这可能不是这样做的首选方式。
我怀疑我应该在某个地方调用postInvalidate()
,但我真的无法弄清楚什么视图以及何时进行操作。
PreferenceScreen android:summary update !可能遇到与我相同的问题。
任何帮助表示感谢。
答案 0 :(得分:16)
我找到了解决方法。我有这样的层次结构,每个都是一个PreferenceScreen:
main settings
-> users list
-> user1 settings
-> user2 settings
...
在用户列表中,子屏幕的标题取决于用户设置。现在,当我创建用户列表时,我将列表适配器存储到PreferenceActivity中的变量。
PreferenceScreen usersListScreen = ...
userScreenListAdapter = (BaseAdapter)usersListScreen.getRootAdapter();
现在编辑userX-settings时,我在usersListScreen中设置了标题,然后在该调用之后:
userScreenListAdapter.notifyDataSetChanged();
更新列表UI,更改可见。
答案 1 :(得分:3)
notifyDataSetChanged()是正确的解决方案。但是我想为所有PreferenceScreens添加递归迭代器,只要我遇到问题就找到Preference的真正父级。对于复杂的首选项结构,我推荐这个杀手级代码:
private void updateAll_PrefereneScreens(PreferenceGroup group) {
if (group instanceof PreferenceScreen) {
BaseAdapter adapter = (BaseAdapter) ((PreferenceScreen) group).getRootAdapter();
adapter.notifyDataSetChanged();
}
for (int i=0; i<group.getPreferenceCount(); i++) {
Preference pref = group.getPreference(i);
if (pref instanceof PreferenceGroup) {
updateAll_PrefereneScreens((PreferenceGroup) pref);
}
}
}
我在每个 setSummary()之后调用它以确保它正常工作:
findPreference("KEY").setSummary(str);
updateAll_PrefereneScreens(getPreferenceScreen());
答案 2 :(得分:2)
这可能是一个迟到的答案,但仍然......我现在正在谈论它:)
我实现它的方式是,您可以使用其生命周期的 PreferenceFragmentCompat 的 onResume()方法,并通过重置其值来手动更新所需字段
注意:在此示例中,我还会跟踪已编辑的首选项的索引,以避免重置每个首选项。
// let's say you need to update title of the parent screen
// when back from sub-screen(s) edition
private int edited = -1;
// this gets called everytime you get back to the parent screen
@Override
public void onResume ()
{
super.onResume();
if ( edited != -1 )
{
PreferenceScreen root = getPreferenceScreen();
Preference preference = root.getPreference( edited );
if ( preference != null )
{
String updatedValue = getPreferenceManager()
.getSharedPreferences()
.getString( "your-preference-key", "your-default-value" );
preference.setTitle( updatedValue );
}
edited = -1;
}
}
// everytime you are about to navigate to a sub-screen
@Override
public boolean onPreferenceTreeClick ( Preference preference )
{
// beware to save it first
if ( preference instanceof MySubScreenPreference )
{
edited = preference.getOrder();
}
return super.onPreferenceTreeClick( preference );
}
如文档中所述:
的onResume
当片段对用户可见并且正在运行时调用。这通常与包含Activity的生命周期的Activity.onResume相关联。
当然,它也适用于 FragmentManager 的交易。
希望这有帮助,快乐编码! :)
答案 3 :(得分:1)
遇到同样的问题,但onContentChanged()对我不起作用。我的问题是PreferenceScreens从根目录深度超过一级。
要按照您的示例,如果您首先创建了“帐户”首选项屏幕,然后在其下添加了每个单独的帐户PreferenceScreen对象。像这样:
Root Screen -> "Accounts" screen -> "foo@example.com" screen -> edit username -> edit password -> etc... -> "bar@example.com" screen -> "baz@example.com" screen -> etc...
如果用户编辑了他们的用户名并单击了save,则调用PreferenceActivity.onContentChanged()似乎只会影响根PreferenceScreen的直接后代。第三代屏幕的标题和摘要没有重新绘制,仍然反映了旧的价值观。
查看onContentChanged()的代码,看起来它只是将根屏幕重新绑定()到ListActivity的ListView,虽然我不认为后续的PreferenceScreens曾经绑定到ListView(是吗?) ,所以我们不能手动重新绑定任何东西......
我能想到的唯一解决方法是将子菜单创建为独立的PreferenceActivity而不是PreferenceScreens,因此我们可以故意在我们的直接祖先上调用onContentChanged()。但这比目前的解决方案更像是一个混乱。有什么想法吗?
答案 4 :(得分:1)
PreferenceActivity#onContentChanged()
将刷新整个屏幕,发生一些 闪烁效果 。
但是,您可以使用PreferenceActivity#onPreferenceTreeClick(...)
方法在给定的偏好设置上实现相同的目标选择性。
请注意,此方法现已弃用:请考虑使用fragments,这似乎解决了自定义首选项的许多问题(我还没有测试过自己)。旧版SDK有a compatibility package。
public void onSharedPreferenceChanged(SharedPreferences preferences, String key) {
Log.v(TAG, "onSharedPreferenceChanged(...," + key + ")");
if (key.equals("myPref")) {
onPreferenceTreeClick(getPreferenceScreen(), getPreferenceManager().findPreference("myPref"));
Log.v(TAG, "Do whatever else you need...");
}
//onContentChanged(); // this could be used but occurs screen flickering
}
答案 5 :(得分:1)
我只是把
((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();
在更新我的父偏好项目的摘要后立即。
答案 6 :(得分:0)
// Import required classes (Win: CTRL+SHIFT+O & Mac: CMD+SHIFT+O)
public class YourCustomPreference extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// Load the preferences from an XML resource
addPreferencesFromResource(R.xml.preferences);
}
// some logic goes above, when you want to reset value and update
// EditTextPreference value. For convenience, I am going to wrap two
// different task in different methods
private void resetPreferenceValue() {
SharedPreferences sharedPref = PreferenceManager
.getDefaultSharedPreferences(this.getApplicationContext());
// Get preference in editor mode
SharedPreferences.Editor prefEditor = sharedPref.edit();
// set your default value here (could be empty as well)
prefEditor.putString("your_edit_text_pref_key", "DEFAULT-VALUE");
prefEditor.commit(); // finally save changes
// Now we have updated shared preference value, but in activity it
// still hold the old value
this.resetElementValue();
}
private void resetElementValue() {
// First get reference to edit-text view elements
EditTextPreference myPrefText = (EditTextPreference) super
.findPreference("your_edit_text_pref_key");
// Now, manually update it's value to default/empty
myPrefText.setText("DEFAULT-VALUE");
// Now, if you click on the item, you'll see the value you've just
// set here
}
}
答案 7 :(得分:-1)
这对我有用,你必须抓住PreferenceScreen的底层对话框并从那里设置标题,非常简单。
somePrefScreen.getDialog().setTitle("Whatever you want");