升级到支持库v21后,PreferenceActivity中没有ActionBar


83

升级到支持库v21之后,我的ActionBarPreferenceActivity消失了。

我是否错过了主题中的某些属性以再次激活它?黑色的ActionBar也有类似的麻烦。

我还尝试通过Toolbar在根布局中添加a来给它增加一点点技巧,但这并没有达到预期的效果。



1
@JaredBurrows您不能使用PreferenceFragment 3.0之前的版本
tyczj 2014年

1
我也在用它们。AFIK我需要链接到使用PreferenceFragments的PreferenceActivity。但是,正如tycyj指出的那样,我也需要它们以提供传统支持。
2014年

1
工具栏只是一个视图。您可以在任何地方添加它。
Jared Burrows 2014年

Answers:


170

请在以下位置找到GitHub Repo:


与您自己的代码非常相似,但添加了xml以允许设置标题:

继续使用PreferenceActivity

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 :

例


UPDATE(姜饼兼容性):

正如指出的在这里,姜饼设备是在这条线返回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.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();
            }
        });
    }
}

以上任何问题都请通知我!


更新2:着色解决方案

正如许多开发人员笔记中指出的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.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;
}

嵌套偏好屏幕

很多人都遇到了在嵌套<PreferenceScreen />s中包含工具栏的问题,但是,我找到了解决方案!-经过大量的反复试验!

将以下内容添加到您的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如此痛苦,是因为它们基于包装对话框,因此我们需要捕获对话框布局以向其添加工具栏。


工具栏阴影

通过设计导入,Toolbar不允许在v21之前的设备中进行加高和阴影处理,因此,如果您希望在其上加高,则Toolbar需要将其包装在中AppBarLayout

`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>

别忘了将设计支持库添加为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

我已经调查了所报告的重叠问题,因此无法重现该问题。

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

在此处输入图片说明

如果我遗漏了一些东西,请通过此仓库让我知道,我将进行调查。


不错的一个:我使用了第一种方法(姜饼不在我的目标上)。谢谢!
JJ86

在此示例中,似乎姜饼上的向上按钮已损坏。
idunnololz 2015年

1
谢谢您的出色回答,几天前我给了您接受状态。我只是复制了着色部分,以确保它看起来很棒:)
否定

1
我必须纠正自己。该android:theme变通办法只固定在工具栏Android 5.0以上版本的黑色文本颜色。新的支持库(我使用的是22.2.0)似乎有所更改。
托尼2015年

4
android.R.id.list的父级是android N中的FrameLayout
zys

45

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

1
不推荐使用ActionBarActivity。
rekire

@rekire其android.support.v7.app.ActionBarActivity
阿卜杜拉

4
只需扩展AppCompatActivity而不是ActionBarActivity。
SammyT,2015年

1
为我工作,并且比上面简单得多。
亚伦·布伦库什

1
对于简单的首选项屏幕,这是迄今为止最容易实现的解决方案。
克里斯·西里菲斯

7

我最后用以下简单代码添加了工具栏:

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

这是我的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" />

我想我把它放在onCreate()中了
拒收

6

比“滚动自己的”操作栏更好的解决方案是使用AppCompatDelegate类,该类使您可以从支持库中引入实际操作栏。这是使用代码的示例代码,摘自ĽubomírKuč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;
    }
}

4
aka AppCompatPreferenceActivity(来自官方v7示例)。
Avinash R

3

嗨,如果您还有这个问题,我不是。但是我认为我将发布解决该问题的方法,希望它能对某人有所帮助。

1)首先,您可能已经注意到PreferenceActivity扩展了ListActivity,而ListActivity又从Activity扩展了。

根据开发者博客(http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html)上的评论,要使用v21,您的所有活动都必须继承自ActionBarActivity 。所以有你的问题。

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.

这应该解决它。

干杯!


4
“使您的类PreferenceActivity扩展ActionBarActivity”-但是如何?
vbence 2015年

在此处查看此链接: code.hootsuite.com/…–
AfrikAndroid

1
谢谢,我认为这越接近越好。真正的痛苦是PreferenceActivity具有通过loadHeadersFromResource的内置导航,其中包含您必须自己构建导航的片段。
vbence

0

我做了与接受的问题类似的操作,但是我也在其他活动中使用了布局MainActivity,所以我不能仅在其中硬编码箭头。

对我有用的是:

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

0

我遇到过同样的问题。只需尝试将活动的主题更改为其中包含任何ActionBar的主题即可。在SettingsActivity的活动标签中添加以下行对我来说很有效:

android:theme="Theme.AppCompat.DayNight.DarkActionBar"


-1

我想出一个简单的方法是覆盖:

@android:style/Theme.Material.Light.DarkActionBar

按照您的风格:

<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>
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.