使用支持(v21)工具栏创build首选项屏幕

在“首选项”屏幕上使用支持库中的新材料devise工具栏时遇到问题。

我有一个settings.xml文件,如下所示:

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="@string/AddingItems" android:key="pref_key_storage_settings"> <ListPreference android:key="pref_key_new_items" android:title="@string/LocationOfNewItems" android:summary="@string/LocationOfNewItemsSummary" android:entries="@array/new_items_entry" android:entryValues="@array/new_item_entry_value" android:defaultValue="1"/> </PreferenceCategory> </PreferenceScreen> 

string在别处定义。

您可以使用PreferenceFragment作为PreferenceFragment的替代方法。 所以,这里是包装Activity例子:

 public class MyPreferenceActivity extends ActionBarActivity { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.pref_with_actionbar); android.support.v7.widget.Toolbar toolbar = (android.support.v7.widget.Toolbar) findViewById(uk.japplications.jcommon.R.id.toolbar); setSupportActionBar(toolbar); getFragmentManager().beginTransaction().replace(R.id.content_frame, new MyPreferenceFragment()).commit(); } } 

这里是布局文件(pref_with_actionbar):

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_height="@dimen/action_bar_height" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" app:theme="@style/ToolbarTheme.Base" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> <FrameLayout android:id="@+id/content_frame" android:layout_below="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> 

最后是PreferenceFragment

 public static class MyPreferenceFragment extends PreferenceFragment{ @Override public void onCreate(final Bundle savedInstanceState){ super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.settings); } } 

我希望这可以帮助别人。

请findGitHub回购: 在这里


晚会有点晚,但这是我用来解决继续使用PreferenceActivity解决scheme:

settings_toolbar.xml :

 <?xml version="1.0" encoding="utf-8"?> <android.support.v7.widget.Toolbar xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:id="@+id/toolbar" app:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" android:layout_width="match_parent" android:layout_height="wrap_content" android:minHeight="?attr/actionBarSize" app:navigationContentDescription="@string/abc_action_bar_up_description" android:background="?attr/colorPrimary" app:navigationIcon="?attr/homeAsUpIndicator" app:title="@string/action_settings" /> 

SettingsActivity.java :

 public class SettingsActivity extends PreferenceActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent(); Toolbar bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } } 

Result :

例


更新(姜饼兼容性):

根据评论,姜饼设备在这一行返回NullPointerException:

 LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent(); 

固定:

SettingsActivity.java :

 public class SettingsActivity extends PreferenceActivity { @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); Toolbar bar; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { LinearLayout root = (LinearLayout) findViewById(android.R.id.list).getParent().getParent().getParent(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top } else { ViewGroup root = (ViewGroup) findViewById(android.R.id.content); ListView content = (ListView) root.getChildAt(0); root.removeAllViews(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); int height; TypedValue tv = new TypedValue(); if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) { height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); }else{ height = bar.getHeight(); } content.setPadding(0, height, 0, 0); root.addView(content); root.addView(bar); } bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } } 

任何与上述问题让我知道!


更新2:debugging替代方法

正如许多开发人员指出的, PreferenceActivity不支持对元素进行着色,但是通过使用一些内部类可以实现这一点。 直到这些类被删除。 (使用appCompat support-v7 v21.0.3工作)。

添加以下导入:

 import android.support.v7.internal.widget.TintCheckBox; import android.support.v7.internal.widget.TintCheckedTextView; import android.support.v7.internal.widget.TintEditText; import android.support.v7.internal.widget.TintRadioButton; import android.support.v7.internal.widget.TintSpinner; 

然后重写onCreateView方法:

 @Override public View onCreateView(String name, Context context, AttributeSet attrs) { // Allow super to try and create a view first final View result = super.onCreateView(name, context, attrs); if (result != null) { return result; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // If we're running pre-L, we need to 'inject' our tint aware Views in place of the // standard framework versions switch (name) { case "EditText": return new TintEditText(this, attrs); case "Spinner": return new TintSpinner(this, attrs); case "CheckBox": return new TintCheckBox(this, attrs); case "RadioButton": return new TintRadioButton(this, attrs); case "CheckedTextView": return new TintCheckedTextView(this, attrs); } } return null; } 

Result:

例2


AppCompat 22.1

AppCompat 22.1引入了新的有色元素,这意味着不再需要利用内部类来达到与上次更新相同的效果。 而是按照这个(仍然覆盖onCreateView ):

 @Override public View onCreateView(String name, Context context, AttributeSet attrs) { // Allow super to try and create a view first final View result = super.onCreateView(name, context, attrs); if (result != null) { return result; } if (Build.VERSION.SDK_INT < Build.VERSION_CODES.LOLLIPOP) { // If we're running pre-L, we need to 'inject' our tint aware Views in place of the // standard framework versions switch (name) { case "EditText": return new AppCompatEditText(this, attrs); case "Spinner": return new AppCompatSpinner(this, attrs); case "CheckBox": return new AppCompatCheckBox(this, attrs); case "RadioButton": return new AppCompatRadioButton(this, attrs); case "CheckedTextView": return new AppCompatCheckedTextView(this, attrs); } } return null; } 

巢的偏好屏幕

很多人遇到的问题包括工具栏嵌套<PreferenceScreen />但是,我已经find了一个解决scheme! – 经过大量的试验和错误!

将以下内容添加到SettingsActivity

 @SuppressWarnings("deprecation") @Override public boolean onPreferenceTreeClick(PreferenceScreen preferenceScreen, Preference preference) { super.onPreferenceTreeClick(preferenceScreen, preference); // If the user has clicked on a preference screen, set up the screen if (preference instanceof PreferenceScreen) { setUpNestedScreen((PreferenceScreen) preference); } return false; } public void setUpNestedScreen(PreferenceScreen preferenceScreen) { final Dialog dialog = preferenceScreen.getDialog(); Toolbar bar; if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.ICE_CREAM_SANDWICH) { LinearLayout root = (LinearLayout) dialog.findViewById(android.R.id.list).getParent(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); root.addView(bar, 0); // insert at top } else { ViewGroup root = (ViewGroup) dialog.findViewById(android.R.id.content); ListView content = (ListView) root.getChildAt(0); root.removeAllViews(); bar = (Toolbar) LayoutInflater.from(this).inflate(R.layout.settings_toolbar, root, false); int height; TypedValue tv = new TypedValue(); if (getTheme().resolveAttribute(R.attr.actionBarSize, tv, true)) { height = TypedValue.complexToDimensionPixelSize(tv.data, getResources().getDisplayMetrics()); }else{ height = bar.getHeight(); } content.setPadding(0, height, 0, 0); root.addView(content); root.addView(bar); } bar.setTitle(preferenceScreen.getTitle()); bar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { dialog.dismiss(); } }); } 

PreferenceScreen的原因是因为它们基于一个包装对话框,所以我们需要捕获对话框的布局来添加工具栏。


工具栏阴影

通过devise导入Toolbar不允许在v21之前的设备中进行提升和遮蔽,所以如果您想在Toolbar上提升,您需要将其包装在AppBarLayout

settings_toolbar.xml

 <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content"> <android.support.v7.widget.Toolbar .../> </android.support.design.widget.AppBarLayout> 

不要忘记添加devise支持库作为build.gradle文件中的依赖关系:

 compile 'com.android.support:support-v4:22.2.0' compile 'com.android.support:appcompat-v7:22.2.0' compile 'com.android.support:design:22.2.0' 

Android 6.0

我调查了报道的重叠问题,我不能重现这个问题。

上面使用的完整代码产生以下内容:

在这里输入图像描述

如果我失去了一些东西,请通过这个回购让我知道,我会调查。

全新的更新。

通过一些实验,我似乎find了适用于嵌套首选项屏幕的AppCompat 22.1+解决scheme。

首先,正如许多答案中提到的(这里包括一个答案),您将需要使用新的AppCompatDelegate 。 请使用支持演示中的AppCompatPreferenceActivity.java文件( https://android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java )并简单地从它扩展,或者将相关函数复制到您自己的PreferenceActivity 。 我将在这里展示第一种方法:

 public class SettingsActivity extends AppCompatPreferenceActivity { @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.settings, target); setContentView(R.layout.settings_page); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); setSupportActionBar(toolbar); ActionBar bar = getSupportActionBar(); bar.setHomeButtonEnabled(true); bar.setDisplayHomeAsUpEnabled(true); bar.setDisplayShowTitleEnabled(true); bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha); bar.setTitle(...); } @Override protected boolean isValidFragment(String fragmentName) { return SettingsFragment.class.getName().equals(fragmentName); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); break; } return super.onOptionsItemSelected(item); } } 

伴随的布局是相当简单和平常的( layout/settings_page.xml ):

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:layout_width="match_parent" android:layout_height="match_parent" android:layout_margin="0dp" android:orientation="vertical" android:padding="0dp"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:elevation="4dp" android:theme="@style/..."/> <ListView android:id="@id/android:list" android:layout_width="match_parent" android:layout_height="match_parent"/> </LinearLayout> 

首选项本身是按照惯例定义的( xml/settings.xml ):

 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="com.example.SettingsFragment" android:summary="@string/..." android:title="@string/..."> <extra android:name="page" android:value="page1"/> </header> <header android:fragment="com.example.SettingsFragment" android:summary="@string/..." android:title="@string/..."> <extra android:name="page" android:value="page2"/> </header> ... </preference-headers> 

直到这一点,networking上的解决scheme没有真正的区别。 实际上,即使你没有嵌套的屏幕,没有标题,只有一个屏幕,你也可以使用它。

我们对所有更深的页面使用通用的PreferenceFragment ,通过标题中的extra参数进行区分。 每个页面都会有一个单独的XML,里面有一个通用的PreferenceScreenxml/settings_page1.xml等)。 该片段使用与活动相同的布局,包括工具栏。

 public class SettingsFragment extends PreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getActivity().setTheme(R.style...); if (getArguments() != null) { String page = getArguments().getString("page"); if (page != null) switch (page) { case "page1": addPreferencesFromResource(R.xml.settings_page1); break; case "page2": addPreferencesFromResource(R.xml.settings_page2); break; ... } } } @Override public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View layout = inflater.inflate(R.layout.settings_page, container, false); if (layout != null) { AppCompatPreferenceActivity activity = (AppCompatPreferenceActivity) getActivity(); Toolbar toolbar = (Toolbar) layout.findViewById(R.id.toolbar); activity.setSupportActionBar(toolbar); ActionBar bar = activity.getSupportActionBar(); bar.setHomeButtonEnabled(true); bar.setDisplayHomeAsUpEnabled(true); bar.setDisplayShowTitleEnabled(true); bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha); bar.setTitle(getPreferenceScreen().getTitle()); } return layout; } @Override public void onResume() { super.onResume(); if (getView() != null) { View frame = (View) getView().getParent(); if (frame != null) frame.setPadding(0, 0, 0, 0); } } } 

最后,快速总结这个实际工作。 新的AppCompatDelegate允许我们使用任何具有AppCompat特性的活动,而不仅仅是那些从AppCompat实际活动中扩展的活动。 这意味着我们可以把旧的PreferenceActivity变成一个新的,像往常一样添加工具栏。 从这一点上,我们可以坚持旧的解决scheme有关偏好屏幕和标题,没有任何偏离现有的文件。 只有一点重要:在活动中不要使用onCreate() ,因为这会导致错误。 使用onBuildHeaders()进行所有操作,如添加工具栏。

唯一真正的区别是,这就是使用嵌套屏幕工作的原因是您可以对碎片使用相同的方法。 你可以用同样的方法使用他们的onCreateView() ,膨胀你自己的布局而不是系统的布局,像在活动中一样添加工具栏。

如果你想使用PreferenceHeaders你可以使用下面的方法:

 import android.support.v7.widget.Toolbar; public class MyPreferenceActivity extends PreferenceActivity Toolbar mToolbar; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); ViewGroup root = (ViewGroup) findViewById(android.R.id.content); LinearLayout content = (LinearLayout) root.getChildAt(0); LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.activity_settings, null); root.removeAllViews(); toolbarContainer.addView(content); root.addView(toolbarContainer); mToolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar); } @Override public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.pref_headers, target); } // Other methods } 

布局/ activity_settings.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_height="?attr/actionBarSize" android:layout_width="match_parent" android:minHeight="?attr/actionBarSize" android:background="?attr/colorPrimary" app:theme="@style/AppTheme" app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/> </LinearLayout> 

你可以使用你喜欢的任何布局,只要确保你在Java代码中调整它。

最后,你的头文件(xml / pref_headers.xml)

 <preference-headers xmlns:android="http://schemas.android.com/apk/res/android"> <header android:fragment="com.example.FirstFragment" android:title="@string/pref_header_first" /> <header android:fragment="com.example.SecondFragment" android:title="@string/pref_header_second" /> </preference-headers> 

随着Android支持库22.1.0和新的AppCompatDelegate的发布,在这里你可以find一个PreferenceActivity实现的很好的例子,具有向后兼容性的材料支持。

更新它也适用于嵌套的屏幕。

https://android.googlesource.com/platform/development/+/marshmallow-mr3-release/samples/Support7Demos/src/com/example/android/supportv7/app/AppCompatPreferenceActivity.java

虽然上面的答案看起来很详细,但如果您希望快速修复解决scheme以使用支持API 7的工具栏,并且一直延伸PreferenceActivity ,那么我可以从下面的这个项目中获得帮助。

https://github.com/AndroidDeveloperLB/ActionBarPreferenceActivity

activity_settings.xml

 <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" xmlns:app="http://schemas.android.com/apk/res-auto" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" > <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:background="@color/app_theme_light" app:popupTheme="@style/Theme.AppCompat.Light" app:theme="@style/Theme.AppCompat" /> <FrameLayout android:layout_width="match_parent" android:layout_height="match_parent" android:padding="@dimen/padding_medium" > <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="match_parent" /> </FrameLayout> 

SettingsActivity.java

 public class SettingsActivity extends PreferenceActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar); addPreferencesFromResource(R.xml.preferences); toolbar.setClickable(true); toolbar.setNavigationIcon(getResIdFromAttribute(this, R.attr.homeAsUpIndicator)); toolbar.setTitle(R.string.menu_settings); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } private static int getResIdFromAttribute(final Activity activity, final int attr) { if (attr == 0) { return 0; } final TypedValue typedvalueattr = new TypedValue(); activity.getTheme().resolveAttribute(attr, typedvalueattr, true); return typedvalueattr.resourceId; } } 

我也一直在寻找解决scheme,将v7支持工具栏( API 25 )添加到AppCompatPreferenceActivity(在添加SettingsActivity时由AndroidStudio自动创build)。 在阅读了几个解决scheme并尝试了每个解决scheme之后,我努力使生成的PreferenceFragment示例也显示在工具栏中。

一种经过修改的解决scheme来自“ Gabor ”。

我面临的一个警告是“onBuildHeaders”只会触发一次。 如果您侧身转动设备(如电话),将重新创build视图,而PreferenceActivity不会再次显示工具栏,但PreferenceFragments将保留它们。

我尝试使用'onPostCreate'来调用'setContentView',而这个工作方式改变时重新创build工具栏,PreferenceFragments然后将呈现为空白。

我所提出的几乎每一个提示和答案,我可以读到关于这个问题。 我希望别人也觉得它有用。

我们将从Java开始

首先在(生成的) AppCompatPreferenceActivity.java中,我修改了“setSupportActionBar”,如下所示:

 public void setSupportActionBar(@Nullable Toolbar toolbar) { getDelegate().setSupportActionBar(toolbar); ActionBar bar = getDelegate().getSupportActionBar(); bar.setHomeButtonEnabled(true); bar.setDisplayHomeAsUpEnabled(true); } 

其次 ,我创build了一个名为AppCompatPreferenceFragment.java的新类(它目前是一个未使用的名称,尽pipe它可能不会这样)!

 abstract class AppCompatPreferenceFragment extends PreferenceFragment { @Override public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) { View view = inflater.inflate(R.layout.activity_settings, container, false); if (view != null) { Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar_settings); ((AppCompatPreferenceActivity) getActivity()).setSupportActionBar(toolbar); } return view; } @Override public void onResume() { super.onResume(); View frame = (View) getView().getParent(); if (frame != null) frame.setPadding(0, 0, 0, 0); } } 

这是Gabor回答的一部分。

最后 ,为了获得一致性,我们需要对SettingsActivity.java进行一些更改:

 public class SettingsActivity extends AppCompatPreferenceActivity { boolean mAttachedFragment; @Override protected void onCreate(Bundle savedInstanceState) { mAttachedFragment = false; super.onCreate(savedInstanceState); } @Override @TargetApi(Build.VERSION_CODES.HONEYCOMB) public void onBuildHeaders(List<Header> target) { loadHeadersFromResource(R.xml.pref_headers, target); } @Override public void onAttachFragment(Fragment fragment) { mAttachedFragment = true; super.onAttachFragment(fragment); } @Override protected void onPostCreate(Bundle savedInstanceState) { super.onPostCreate(savedInstanceState); //if we didn't attach a fragment, go ahead and apply the layout if (!mAttachedFragment) { setContentView(R.layout.activity_settings); setSupportActionBar((Toolbar)findViewById(R.id.toolbar_settings)); } } /** * This fragment shows general preferences only. It is used when the * activity is showing a two-pane settings UI. */ @TargetApi(Build.VERSION_CODES.HONEYCOMB) public static class GeneralPreferenceFragment extends AppCompatPreferenceFragment { @Override public void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); addPreferencesFromResource(R.xml.pref_general); setHasOptionsMenu(true); bindPreferenceSummaryToValue(findPreference("example_text")); bindPreferenceSummaryToValue(findPreference("example_list")); } @Override public boolean onOptionsItemSelected(MenuItem item) { int id = item.getItemId(); if (id == android.R.id.home) { startActivity(new Intent(getActivity(), SettingsActivity.class)); return true; } return super.onOptionsItemSelected(item); } } } 

为简洁起见,一些代码已被排除在活动之外。 这里的关键组件是' onAttachedFragment ',' onPostCreate ','GeneralPreferenceFragment'现在扩展了自定义的' AppCompatPreferenceFragment '而不是PreferenceFragment。

代码摘要 :如果存在片段,片段将注入新的布局,并调用修改过的“setSupportActionBar”函数。 如果片段不存在,则SettingsActivity将在“onPostCreate”上注入新布局

现在到XML (非常简单):

activity_settings.xml

 <?xml version="1.0" encoding="utf-8"?> <LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" android:orientation="vertical" android:layout_width="match_parent" android:layout_height="match_parent"> <include layout="@layout/app_bar_settings" android:layout_width="match_parent" android:layout_height="match_parent" /> </LinearLayout> 

app_bar_settings.xml

 <?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/content_frame" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context=".SettingsActivity"> <android.support.design.widget.AppBarLayout android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.NoActionBar.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar_settings" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay" /> </android.support.design.widget.AppBarLayout> <include layout="@layout/content_settings" /> </android.support.design.widget.CoordinatorLayout> 

content_settings.xml

 <?xml version="1.0" encoding="utf-8"?> <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent" android:paddingBottom="@dimen/activity_vertical_margin" android:paddingLeft="@dimen/activity_horizontal_margin" android:paddingRight="@dimen/activity_horizontal_margin" android:paddingTop="@dimen/activity_vertical_margin" app:layout_behavior="@string/appbar_scrolling_view_behavior" tools:context=".SettingsActivity" tools:showIn="@layout/app_bar_settings"> <ListView android:id="@android:id/list" android:layout_width="match_parent" android:layout_height="wrap_content" /> </RelativeLayout> 

最终结果

SettingsActivity

GeneralPreferenceFragment

让我们在这里保持简单和干净,而不会破坏任何内置的布局

 import android.support.design.widget.AppBarLayout; import android.support.v4.app.NavUtils; import android.support.v7.widget.Toolbar; private void setupActionBar() { Toolbar toolbar = new Toolbar(this); AppBarLayout appBarLayout = new AppBarLayout(this); appBarLayout.addView(toolbar); final ViewGroup root = (ViewGroup) findViewById(android.R.id.content); final ViewGroup window = (ViewGroup) root.getChildAt(0); window.addView(appBarLayout, 0); setSupportActionBar(toolbar); // Show the Up button in the action bar. getSupportActionBar().setDisplayHomeAsUpEnabled(true); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { onBackPressed(); } }); } 

我在这个过程中发现了这个简单的解决scheme。 首先,我们需要为设置活动创build一个布局。

activity_settings.xml

 <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.my.package"> <android.support.v7.widget.Toolbar android:id="@+id/tool_bar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar" app:elevation="@dimen/appbar_elevation" app:navigationIcon="?attr/homeAsUpIndicator" app:navigationContentDescription="@string/abc_action_bar_up_description" app:popupTheme="@style/ThemeOverlay.AppCompat.Light" /> <ListView android:id="@android:id/list" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_below="@+id/tool_bar" /> </RelativeLayout> 

确保使用android:id="@android:id/list"添加列表视图,否则会抛出NullPointerException

下一步是在您的设置活动中添加(覆盖) onCreate方法

Settings.java

 @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_settings); Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar); toolbar.setTitle(R.string.action_settings); toolbar.setNavigationOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { finish(); } }); } 

确保你导入了android.suppoer.v7.widget.Toolbar 。 这应该适用于16以上的所有API(果冻豆和以上)

我有一个新的(可能更整洁的)解决scheme,它使用Support v7示例中的AppCompatPreferenceActivity 。 有了这个代码,我创build了自己的布局,其中包含一个工具栏:

 <?xml version="1.0" encoding="utf-8"?> <android.support.design.widget.CoordinatorLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:fitsSystemWindows="true" tools:context="edu.adelphi.Adelphi.ui.activity.MainActivity"> <android.support.design.widget.AppBarLayout android:id="@+id/appbar" android:layout_width="match_parent" android:layout_height="wrap_content" android:theme="@style/AppTheme.AppBarOverlay"> <android.support.v7.widget.Toolbar android:id="@+id/toolbar" android:layout_width="match_parent" android:layout_height="?attr/actionBarSize" android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/> </android.support.design.widget.AppBarLayout> <FrameLayout android:id="@+id/content" android:layout_width="match_parent" android:layout_height="match_parent"/> </android.support.design.widget.CoordinatorLayout> 

然后,在我的AppCompatPreferenceActivity ,我改变了setContentView来创build我的新布局,并将提供的布局放在我的FrameLayout

 @Override public void setContentView(@LayoutRes int layoutResID) { View view = getLayoutInflater().inflate(R.layout.toolbar, null); FrameLayout content = (FrameLayout) view.findViewById(R.id.content); getLayoutInflater().inflate(layoutResID, content, true); setContentView(view); } 

然后我只是扩展AppCompatPreferenceActivity ,允许我调用setSupportActionBar((Toolbar) findViewById(R.id.toolbar)) ,并在工具栏中setSupportActionBar((Toolbar) findViewById(R.id.toolbar))菜单项。 同时保持PreferenceActivity的好处。

我想继续詹姆斯·克罗斯的标记解决scheme,因为之后有一个closures只有活动嵌套的屏幕(PreferenceFragment)的方式不closuresSettingsActivity的问题。

其实它可以在所有嵌套的屏幕上工作(所以我不明白Gábor的解决scheme,我尝试没有成功,以及它的工作,直到某一点,但它是一个混乱的多个工具栏),因为当用户点击子偏好屏幕,只有片段被改变(参见<FrameLayout android:id="@+id/content_frame" .../> )而不是始终保持活动和可见的工具栏, 但是应当实施自定义行为以相应地closures每个片段。

在扩展ActionBarActivity的主类SettingsActivity ,应该实现以下方法。 请注意,从onCreate()调用private setupActionBar() onCreate()

 private void setupActionBar() { Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar); //Toolbar will now take on default Action Bar characteristics setSupportActionBar(toolbar); getSupportActionBar().setHomeButtonEnabled(true); getSupportActionBar().setDisplayHomeAsUpEnabled(true); } @Override public boolean onOptionsItemSelected(MenuItem item) { switch (item.getItemId()) { case android.R.id.home: onBackPressed(); return true; } return super.onOptionsItemSelected(item); } @Override public void onBackPressed() { if (getFragmentManager().getBackStackEntryCount() > 0) { getFragmentManager().popBackStackImmediate(); //If the last fragment was removed then reset the title of main // fragment (if so the previous popBackStack made entries = 0). if (getFragmentManager().getBackStackEntryCount() == 0) { getSupportActionBar() .setTitle(R.string.action_settings_title); } } else { super.onBackPressed(); } } 

对于所选嵌套屏幕的标题 ,您应该获得工具栏的引用,并使用toolbar.setTitle(R.string.pref_title_general);设置适当的标题toolbar.setTitle(R.string.pref_title_general); (例如)。

没有必要在所有的PreferenceFragment中实现getSupportActionBar() ,因为只有片段的视图在每次提交时都被更改,而不是工具栏。

不需要在每个preference.xml中创build一个伪造的ToolbarPreference类(参见Gábor的答案)。

这是一个基于AOSP代码的库,它为偏好设置和对话框增添了色彩,添加了一个操作栏,并且支持API 7中的所有版本:

https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary

那么今天(2015年11月18日),这仍然是我的一个问题。 我已经尝试了所有从这个线程的解决scheme,但有两个主要的东西,我不能解决:

  • 嵌套的首选项屏幕出现没有工具栏
  • 首选项在棒棒糖设备上没有材质外观

所以我最终创build了一个更复杂的解决scheme库。 基本上,如果我们使用的是前棒棒糖设备,我必须在内部应用样式,而且我还使用自定义片段(使用PreferenceScreen 恢复所有嵌套的层次结构)来处理嵌套的屏幕。

这个库是这个: https : //github.com/ferrannp/material-preferences

如果你对源代码感兴趣(在这里发布的时间太长),这基本上是它的核心: https : //github.com/ferrannp/material-preferences/blob/master/library/src/main/的Java / COM / FNP / materialpreferences / PreferenceFragment.java