9

我有一个带有一堆(子)PreferenceScreens 的 PreferenceActivity。每个这样的 (Sub)PreferenceScreen 代表一个帐户,并以帐户用户名作为其标题。

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

当用户进入 sub-PreferenceScreen 并编辑帐户用户名时,我希望外部 PreferenceScreen 更新它的 PreferenceScreen-title 为有问题的帐户。

我已经尝试添加...

usernamePref.setOnPreferenceChangeListener(new OnPreferenceChangeListener() {
    public boolean onPreferenceChange(Preference preference, Object newValue) {
        accScreen.setTitle(newValue.toString());
        return true;
    }
});

...但是 accScreen.setTitle 似乎没有在外部 PreferenceScreen 上生效。我注意到调用onContentChanged();实际上使它起作用,但我意识到这可能不是这样做的首选方式。

我怀疑我应该postInvalidate()在某个地方调用一些视图,但我真的不知道什么视图以及何时执行。

PreferenceScreen android:摘要更新!可能遇到和我一样的问题。

任何帮助表示赞赏。

4

8 回答 8

16

我找到了解决方案。我有这样的层次结构,其中每一个都是 PreferenceScreen:

main settings
  -> users list
    -> user1 settings
    -> user2 settings
    ...

在用户列表中,子屏幕的标题取决于用户设置。现在,当我创建用户列表时,我将列表适配器存储到我的 PreferenceActivity 中的一个变量中。

 PreferenceScreen usersListScreen = ...
 userScreenListAdapter = (BaseAdapter)usersListScreen.getRootAdapter();

现在,当编辑 userX-settings 时,我在 usersListScreen 中设置标题,然后调用:

userScreenListAdapter.notifyDataSetChanged();

这会更新列表 UI 并且更改是可见的。

于 2011-02-18T11:41:06.577 回答
3

notifyDataSetChanged()是正确的解决方案。但我想为所有 PreferenceScreens 添加递归迭代器,因为我遇到了找到 Preference 的真正父级的问题。对于 Preferences 的复杂结构,我推荐这个杀手代码:

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());
于 2014-04-04T22:07:44.297 回答
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 );
    }

如文档中所述:

恢复

当片段对用户可见并且正在运行时调用。这通常与包含 Activity 生命周期的 Activity.onResume 相关联。

好的是它当然也适用于FragmentManagerTransactions

希望这会有所帮助,快乐的编码!:)

于 2017-09-01T08:32:26.313 回答
1

遇到同样的问题,但 onContentChanged() 对我不起作用。我的问题是 PreferenceScreens 比根深一层以上。

按照您的示例,如果您首先创建了一个“帐户”PreferenceScreen,然后在其下添加了您的每个单独帐户的 PreferenceScreen 对象。像这样:

根屏幕
  ->“帐户”屏幕
    ->“foo@example.com”屏幕
      -> 编辑用户名
      -> 编辑密码
      -> 等等...
    ->“bar@example.com”屏幕
    ->“baz@example.com”屏幕
    -> 等等...

如果用户编辑了他们的用户名并单击了保存,则调用 PreferenceActivity.onContentChanged() 似乎只会影响根 PreferenceScreen 的直接后代。第三代屏幕的标题和摘要没有重新绘制,仍然反映了旧值。

查看 onContentChanged() 的代码,看起来它只是将根屏幕重新绑定到 ListActivity 的 ListView,尽管我认为后续的 PreferenceScreens 不会绑定到 ListView(是吗?),所以我们无法手动重新绑定任何东西...

我能想到的唯一解决方法是将子菜单创建为独立的 PreferenceActivity 而不是 PreferenceScreens,因此我们可以有意地在我们的直接祖先上调用 onContentChanged()。但这比当前的解决方法更加复杂。有任何想法吗?

于 2010-05-02T05:40:02.310 回答
1

PreferenceActivity#onContentChanged()会刷新整个屏幕,出现一些闪烁效果

但是,您可以使用该方法根据给定的偏好有选择地PreferenceActivity#onPreferenceTreeClick(...)实现相同的目标。

请注意,此方法现在已弃用:考虑使用似乎可以解决许多自定义首选项问题的片段(我还没有测试过自己)。旧版 SDK有一个兼容包

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
}
于 2012-03-23T14:35:47.177 回答
1

我只是把

((BaseAdapter)getPreferenceScreen().getRootAdapter()).notifyDataSetChanged();

在更新我的父母偏好项目的摘要之后。

于 2013-03-07T20:57:22.603 回答
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
    }
}
于 2012-01-24T21:18:25.827 回答
-1

这对我有用,你必须抓住你的 PreferenceScreen 的底层对话框并从那里设置标题,真的很容易。

somePrefScreen.getDialog().setTitle("Whatever you want");
于 2012-01-03T01:39:38.883 回答