Android 升级到支持库 v21 后 PreferenceActivity 中没有 ActionBar
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/26509180/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
No ActionBar in PreferenceActivity after upgrade to Support Library v21
提问by rekire
After I upgraded to the Support Library v21 my ActionBar in my PreferenceActivity
is gone.
升级到 Support Library v21 后,我的 ActionBarPreferenceActivity
不见了。
Did I miss some attributes in my theme to activate it again? I had some similar trouble with a black ActionBar.
我是否错过了主题中的某些属性以再次激活它?我在使用黑色 ActionBar 时遇到了类似的问题。
I also tried to add it a little hackish by adding a Toolbar
to the root layout, but that did not work as expected.
我还尝试通过向Toolbar
根布局添加 a 来将其添加一些hackish ,但这并没有按预期工作。
回答by David Passmore
Please find the GitHub Repo: Here
请找到 GitHub 存储库:这里
Very Similar to your own code but added xml to allow for set title:
与您自己的代码非常相似,但添加了 xml 以允许设置标题:
Continuing to use PreferenceActivity
:
继续使用PreferenceActivity
:
settings_toolbar.xml :
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 :
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 :
Result :
UPDATE (Gingerbread Compatibility) :
更新(姜饼兼容性):
As pointed out here, Gingerbread Devices are returning NullPointerException on this line:
正如这里所指出的,Gingerbread Devices 在这一行返回 NullPointerException:
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
FIX:
使固定:
SettingsActivity.java :
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.JELLY_BEAN) {
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();
}
});
}
}
Any issues with the above let me know!
以上有任何问题请告诉我!
UPDATE 2: TINTING WORKAROUND
更新 2:着色解决方法
As pointed out in many dev notes PreferenceActivity
does not support tinting of elements, however by utilising a few internal classes you CAN achieve this. That is until these classes are removed. (Works using appCompat support-v7 v21.0.3).
正如许多开发说明PreferenceActivity
中所指出的,不支持元素着色,但是通过使用一些内部类,您可以实现这一点。直到这些类被删除。(使用 appCompat support-v7 v21.0.3 工作)。
Add the following imports:
添加以下导入:
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;
Then override the onCreateView
method:
然后重写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:
Result:
AppCompat 22.1
应用兼容 22.1
AppCompat 22.1 introduced new tinted elements, meaning that there is no longer a need to utilise the internal classes to achieve the same effect as the last update. Instead follow this (still overriding onCreateView
):
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.JELLY_BEAN) {
// 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;
}
NESTED PREFERENCE SCREENS
嵌套首选项屏幕
A lot of people are experiencing issues with including the Toolbar in nested <PreferenceScreen />
s however, I have found a solution!! - After a lot of trial and error!
很多人都遇到了在嵌套<PreferenceScreen />
s 中包含 Toolbar 的问题,但是,我找到了解决方案!!- 经过大量的反复试验!
Add the following to your SettingsActivity
:
将以下内容添加到您的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();
}
});
}
The reason that PreferenceScreen
's are such a pain is because they are based as a wrapper dialog, so we need to capture the dialog layout to add the toolbar to it.
之所以说PreferenceScreen
的是这样的痛苦是因为它们是基于作为包装对话,所以我们需要捕捉的对话框布局到工具栏添加到它。
Toolbar Shadow
工具栏阴影
By design importing the Toolbar
does not allow for elevation and shadowing in pre-v21 devices, so if you would like to have elevation on your Toolbar
you need to wrap it in a AppBarLayout
:
通过设计导入Toolbar
不允许在 v21 之前的设备中进行高程和阴影,因此如果您想在您的设备上进行高程,则Toolbar
需要将其包装在AppBarLayout
:
`settings_toolbar.xml :
`settings_toolbar.xml :
<android.support.design.widget.AppBarLayout
xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="wrap_content">
<android.support.v7.widget.Toolbar
.../>
</android.support.design.widget.AppBarLayout>
Not forgetting to add the add the Design Support library as a dependency in build.gradle
file:
不要忘记添加添加设计支持库作为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
安卓 6.0
I have investigated the reported overlapping issue and I cannot reproduce the issue.
我已经调查了报告的重叠问题,但我无法重现该问题。
The full code in use as above produces the following:
上面使用的完整代码产生以下结果:
If I am missing something please let me know via this repoand I will investigate.
如果我遗漏了什么,请通过这个 repo告诉我,我会调查。
回答by Abdullah
Use AppCompatActivity & PreferenceFragment to solve the issue:
使用 AppCompatActivity & PreferenceFragment 解决问题:
AppCompatActivity:
应用兼容活动:
public class SettingsActivity extends AppCompatActivity {
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getFragmentManager().beginTransaction().replace(android.R.id.content, new SettingsFragment()).commit();
}}
PreferenceFragment:
偏好片段:
public class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings_preferences);
}}
回答by rekire
I ended in adding the Toolbar myself with this simple code:
我最终用这个简单的代码自己添加了工具栏:
// get the root container of the preferences list
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar bar = (Toolbar)LayoutInflater.from(this).inflate(R.layout.preferences_toolbar, root, false);
root.addView(bar, 0); // insert at top
bar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
Here is my preferences_toolbar.xml:
这是我的preferences_toolbar.xml:
<android.support.v7.widget.Toolbar
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:app="http://schemas.android.com/apk/res-auto"
android:layout_height="wrap_content"
android:layout_width="match_parent"
android:minHeight="?attr/actionBarSize"
app:navigationContentDescription="@string/abc_action_bar_up_description"
android:background="?attr/colorPrimary"
app:navigationIcon="?attr/homeAsUpIndicator"
app:theme="@style/Theme.Toolbar" />
回答by Tad
A better solution than "rolling your own" action bar is to use the AppCompatDelegateclass, which lets you bring in an actual-factual action bar from the support library. Here is example code to use it, taken from ?ubomír Ku?era's answer to this question.
比“滚动您自己的”操作栏更好的解决方案是使用AppCompatDelegate类,它允许您从支持库中引入实际的操作栏。这是使用它的示例代码,取自 ?ubomír Ku?era 对这个问题的回答。
...
import android.support.v7.app.ActionBar;
import android.support.v7.app.AppCompatDelegate;
import android.support.v7.widget.Toolbar;
...
public class SettingsActivity extends PreferenceActivity {
private AppCompatDelegate mDelegate;
@Override
protected void onCreate(Bundle savedInstanceState) {
getDelegate().installViewFactory();
getDelegate().onCreate(savedInstanceState);
super.onCreate(savedInstanceState);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
getDelegate().onPostCreate(savedInstanceState);
}
public ActionBar getSupportActionBar() {
return getDelegate().getSupportActionBar();
}
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
}
@Override
public MenuInflater getMenuInflater() {
return getDelegate().getMenuInflater();
}
@Override
public void setContentView(@LayoutRes int layoutResID) {
getDelegate().setContentView(layoutResID);
}
@Override
public void setContentView(View view) {
getDelegate().setContentView(view);
}
@Override
public void setContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().setContentView(view, params);
}
@Override
public void addContentView(View view, ViewGroup.LayoutParams params) {
getDelegate().addContentView(view, params);
}
@Override
protected void onPostResume() {
super.onPostResume();
getDelegate().onPostResume();
}
@Override
protected void onTitleChanged(CharSequence title, int color) {
super.onTitleChanged(title, color);
getDelegate().setTitle(title);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
getDelegate().onConfigurationChanged(newConfig);
}
@Override
protected void onStop() {
super.onStop();
getDelegate().onStop();
}
@Override
protected void onDestroy() {
super.onDestroy();
getDelegate().onDestroy();
}
public void invalidateOptionsMenu() {
getDelegate().invalidateOptionsMenu();
}
private AppCompatDelegate getDelegate() {
if (mDelegate == null) {
mDelegate = AppCompatDelegate.create(this, null);
}
return mDelegate;
}
}
回答by AfrikAndroid
Hi I am not if you still have this issue. But I figure I will post what I did to resolve this and hope it will help someone.
嗨,如果你仍然有这个问题,我不是。但我想我会发布我为解决这个问题所做的工作,并希望它能帮助别人。
1) First off, you might have noticed that PreferenceActivity extends ListActivity which in turns extends from Activity.
1) 首先,您可能已经注意到 PreferenceActivity 扩展了 ListActivity,而 ListActivity 又从 Activity 扩展而来。
According to the comments on the developers blog (http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html), to use v21 all your activities must inherit from ActionBarActivity. So there is your issue.
根据开发者博客(http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html)上的评论,要使用 v21,您的所有活动都必须从 ActionBarActivity 继承. 所以这是你的问题。
2) The steps I used to resolve are :
2)我用来解决的步骤是:
a) Make sure that you set the Theme of your PreferenceActivity to inherits one ot the Theme.AppCompat Themes.
b) Make your class PreferenceActivity extends ActionBarActivity.
c) Use the PreferenceFragment as your container for all your preferences.
This should resolve it.
这应该解决它。
Cheers!
干杯!
回答by Moterrola
I did something similar to accepted question, but I'm using my layout in other activities as well (MainActivity
too), so I cannot just hard-code an arrow in it.
我做了一些类似于已接受问题的事情,但我也在其他活动中使用了我的布局(MainActivity
也是),所以我不能只是在其中硬编码一个箭头。
What worked for me:
什么对我有用:
private void setupActionBar() {
LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();
Toolbar toolbar = (Toolbar)LayoutInflater.from(this).inflate(R.layout.app_bar, root, false);
root.addView(toolbar, 0);
setSupportActionBar(toolbar);
ActionBar ab = getSupportActionBar();
ab.setDisplayHomeAsUpEnabled(true);
}
回答by any mous
I had the same issue. just try to change the Theme of the activity to the one that has any ActionBar in it. adding the following line in the activity tag of SettingsActivity worked out for me :
我遇到过同样的问题。只需尝试将活动的主题更改为其中包含任何 ActionBar 的主题。在 SettingsActivity 的活动标签中添加以下行为我解决:
android:theme="Theme.AppCompat.DayNight.DarkActionBar"
android:theme="Theme.AppCompat.DayNight.DarkActionBar"
回答by Tejumola David
An easy way I figured out is overriding:
我想出的一个简单方法是覆盖:
@android:style/Theme.Material.Light.DarkActionBar
In your style:
以你的风格:
<style name="SettingsTheme" parent="@android:style/Theme.Material.Light.DarkActionBar">
<item name="android:colorPrimary">@color/sunshine_blue</item>
<item name="android:colorPrimaryDark">@color/sunshine_dark_blue</item>
</style>