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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-08-20 11:38:52  来源:igfitidea点击:

No ActionBar in PreferenceActivity after upgrade to Support Library v21

androidandroid-support-librarypreferenceactivityandroid-5.0-lollipop

提问by rekire

After I upgraded to the Support Library v21 my ActionBar in my PreferenceActivityis 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 Toolbarto 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 :

example

例子



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 PreferenceActivitydoes 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 onCreateViewmethod:

然后重写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:

example 2

例子2



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 Toolbardoes not allow for elevation and shadowing in pre-v21 devices, so if you would like to have elevation on your Toolbaryou 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.gradlefile:

不要忘记添加添加设计支持库作为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:

上面使用的完整代码产生以下结果:

enter image description here

在此处输入图片说明

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 (MainActivitytoo), 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>