内部首选项屏幕无法使用PreferenceFragmentCompat打开

我的PreferenceFragmentCompat的内部PreferenceScreen没有显示,或者似乎忽略了点击事件。

我创建了extends PreferenceFragmentCompat MyPreferenceFragment

 public class MyPreferenceFragment extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); } } 

然后我在styles.xml更改了我的主题

  @style/PreferenceThemeOverlay  

最后创建我的preferences.xml文件

        

build.gradle我添加了两个:

 compile 'com.android.support:appcompat-v7:23.0.1' compile 'com.android.support:preference-v7:23.0.1' 

活动的代码

 public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } } 

activity_main.xml中

  

测试上面的代码我无法打开/进入首选项屏幕。 我错过了什么吗? 为什么这不起作用?

    花了很多时间尝试,搜索并谢天谢地,在支持库的创建者的帮助下。 我成功地使它成功了。

    第1步。 Activity

     public class MyActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); if (savedInstanceState == null) { // Create the fragment only when the activity is created for the first time. // ie. not after orientation changes Fragment fragment = getSupportFragmentManager().findFragmentByTag(MyPreferenceFragment.FRAGMENT_TAG); if (fragment == null) { fragment = new MyPreferenceFragment(); } FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); ft.replace(R.id.fragment_container, fragment, MyPreferenceFragment.FRAGMENT_TAG); ft.commit(); } } @Override public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) { FragmentTransaction ft = getSupportFragmentManager().beginTransaction(); MyPreferenceFragment fragment = new MyPreferenceFragment(); Bundle args = new Bundle(); args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey()); fragment.setArguments(args); ft.replace(R.id.fragment_container, fragment, preferenceScreen.getKey()); ft.addToBackStack(preferenceScreen.getKey()); ft.commit(); return true; } } 

    提示。

    • 不要通过xml添加片段,您将在方向更改时崩溃。
    • 处理onCreate的活动/片段添加的重新创建,以避免在首选项屏幕内丢失您的片段。
    • 片段的主机活动应实现PreferenceFragmentCompat.OnPreferenceStartScreenCallback并重新创建同一实例的片段。

    第2步 PreferenceFragment

     public class MyPreferenceFragment extends PreferenceFragmentCompat { public static final String FRAGMENT_TAG = "my_preference_fragment"; public MyPreferenceFragment() { } @Override public void onCreatePreferences(Bundle bundle, String rootKey) { setPreferencesFromResource(R.xml.preferences, rootKey); } } 

    提示。

    • 使用方法setPreferencesFromResource并利用每个屏幕的rootKey 。 这样您的代码将被正确重用。
    • 请记住,如果您的片段中有像findPreference这样的代码,那么它应该具有null检查,就像您在内部屏幕中一样,这将不会给您任何信息。

    现在缺少的是在动作栏中执行后退箭头(主动作),但这本身并不起作用;-)

    我还创建了一个包含所有这些代码的演示应用程序,您可以在github上find它。

    我做的略有不同,我正在为每个屏幕启动一个新活动。 这似乎需要更少的黑客攻击:无需混淆交换片段和背景颜色。 您还可以获得活动更改animation作为奖励!

     public class PreferencesActivity extends AppCompatActivity implements PreferenceFragmentCompat.OnPreferenceStartScreenCallback { final static private String KEY = "key"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.preferences); setSupportActionBar((Toolbar) findViewById(R.id.toolbar)); ActionBar actionBar = getSupportActionBar(); if (actionBar != null) actionBar.setDisplayHomeAsUpEnabled(true); if (savedInstanceState != null) return; Fragment p = new PreferencesFragment(); String key = getIntent().getStringExtra(KEY); if (key != null) { Bundle args = new Bundle(); args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, key); p.setArguments(args); } getSupportFragmentManager().beginTransaction() .add(R.id.preferences, p, null) .commit(); } @Override public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) { Intent intent = new Intent(PreferencesActivity.this, PreferencesActivity.class); intent.putExtra(KEY, preferenceScreen.getKey()); startActivity(intent); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { if (item.getItemId() == android.R.id.home) { onBackPressed(); return true; } return super.onOptionsItemSelected(item); } public static class PreferencesFragment extends PreferenceFragmentCompat implements ... { private static final String FRAGMENT_DIALOG_TAG = "android.support.v7.preference.PreferenceFragment.DIALOG"; private String key; @Override public void onCreatePreferences(Bundle bundle, String key) { setPreferencesFromResource(R.xml.preferences, this.key = key); } // this only sets the title of the action bar @Override public void onActivityCreated(Bundle savedInstanceState) { ActionBar actionBar = ((AppCompatActivity) getActivity()).getSupportActionBar(); if (actionBar != null) actionBar.setTitle((key == null) ? "Settings" : findPreference(key).getTitle()); super.onActivityCreated(savedInstanceState); } } } 

    XML:

     < ?xml version="1.0" encoding="utf-8"?>     

    解决方案是启动同一类但具有不同根密钥的另一个片段。 不涉及活动操作。

     @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey){ if(getArguments() != null){ String key = getArguments().getString("rootKey"); setPreferencesFromResource(R.xml.preferences, key); }else{ setPreferencesFromResource(R.xml.preferences, rootKey); } } @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen){ ApplicationPreferencesFragment applicationPreferencesFragment = new ApplicationPreferencesFragment(); Bundle args = new Bundle(); args.putString("rootKey", preferenceScreen.getKey()); applicationPreferencesFragment.setArguments(args); getFragmentManager() .beginTransaction() .replace(getId(), applicationPreferencesFragment) .addToBackStack(null) .commit(); } 

    基于@squirrel Intent解决方案,我以这种方式工作。 它需要更少的黑客攻击。
    活动:

     import android.support.v7.app.AppCompatActivity; public class SettingsActivity extends AppCompatActivity { public static final String TARGET_SETTING_PAGE = "target"; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); SettingsFragment settingsFragment = new SettingsFragment(); Intent intent = getIntent(); if (intent != null) { String rootKey = intent.getStringExtra(TARGET_SETTING_PAGE); if (rootKey != null) { settingsFragment.setArguments(Bundler.single(TARGET_SETTING_PAGE, rootKey)); } } getFragmentManager().beginTransaction() .replace(android.R.id.content, settingsFragment) .commit(); } } 

    分段:

     import android.support.v14.preference.PreferenceFragment; public class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Bundle arguments = getArguments(); if (arguments != null && arguments.getString(TARGET_SETTING_PAGE) != null) { setPreferencesFromResource(R.xml.preferences, arguments.getString(TARGET_SETTING_PAGE)); } else { addPreferencesFromResource(R.xml.preferences); } } @Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) { Intent intent = new Intent(getActivity(), SettingsActivity.class) .putExtra(TARGET_SETTING_PAGE, preferenceScreen.getKey()); startActivity(intent); super.onNavigateToScreen(preferenceScreen); } } 

    很遗憾你在支持appcompat库中需要这么多hacks,因为它可以在标准android中完美无缺地运行。