使用支持(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:
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,里面有一个通用的PreferenceScreen
( xml/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实现的很好的例子,具有向后兼容性的材料支持。
更新它也适用于嵌套的屏幕。
虽然上面的答案看起来很详细,但如果您希望快速修复解决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>
最终结果 :
让我们在这里保持简单和干净,而不会破坏任何内置的布局
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