Нет ActionBar в PreferenceActivity после обновления до библиотеки поддержки v21


83

После того, как я обновился до библиотеки поддержки v21, мой ActionBar в моем PreferenceActivity.

Я пропустил некоторые атрибуты в своей теме, чтобы активировать ее снова? У меня была похожая проблема с черным ActionBar .

Я также попытался добавить немного хакерства, добавив Toolbarв корневой макет, но это не сработало, как ожидалось.


Вы должны использовать Preference Fragment: developer.android.com/reference/android/preference/…
Джаред Берроуз,

1
@JaredBurrows, вы не можете использовать PreferenceFragment до 3.0
tyczj

1
Я тоже ими пользуюсь. AFIK Мне нужно связать PreferenceActivity, который использует PreferenceFragments. Однако, как указывает tycyj, они мне нужны также для поддержки старых версий.
rekire

1
Панель инструментов - это просто представление. Вы можете добавить его где угодно.
Джаред Берроуз,

1
Вы можете проверить пример, который я сделал здесь: github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
разработчик Android

Ответы:


170

Пожалуйста, найдите репозиторий GitHub: здесь


Очень похоже на ваш собственный код, но добавлен 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 :

пример


ОБНОВЛЕНИЕ (Совместимость с пряниками):

Как указано здесь , Gingerbread Devices возвращают исключение 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 />однако я нашел решение !! - После долгих проб и ошибок!

Добавьте в свой 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не допускает возвышения и затенения на устройствах до версии 21, поэтому, если вы хотите, чтобы у вас был уровень возвышения, 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

Похоже, что в этом примере кнопка вверх сломана на Gingerbread.
idunnololz

1
Спасибо за отличный ответ, несколько дней назад я дал вам принятое состояние. Я просто скопировал тонировочную часть, чтобы убедиться, что она будет отлично смотреться :)
rekire

1
Я должен поправиться. android:themeОбходной путь фиксирует только черный цвет текста на панели инструментов для Android 5.0+. Похоже, что что-то изменилось с новой библиотекой поддержки (я использую 22.2.0).
Тони

4
Родителем android.R.id.list является FrameLayout в android N
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 its android.support.v7.app.ActionBarActivity
Абдулла,

4
Просто расширите AppCompatActivity вместо ActionBarActivity.
SammyT

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 ()
rekire 02

6

Лучшее решение, чем использование собственной панели действий, - использовать AppCompatDelegate. класса , который позволяет вам получить фактическую панель действий из библиотеки поддержки. Вот пример кода для его использования, взятый из ответа Любомира Кучера на этот вопрос .

...
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
он же AppCompatPreferenceActivity из официальных образцов v7.
Avinash R

3

Привет, нет, если у вас все еще есть эта проблема. Но я полагаю, что опубликую то, что я сделал, чтобы решить эту проблему, и надеюсь, что это кому-то поможет.

1) Во-первых, вы могли заметить, что PreferenceActivity расширяет 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 01


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>
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.