Немає ActionBar у PreferenceActivity після оновлення до бібліотеки підтримки v21


83

Після того, як я перейшов на бібліотеку підтримки v21, мій ActionBar у моєму файлі PreferenceActivityзник.

Я пропустив деякі атрибути у своїй темі, щоб активувати її знову? У мене були подібні проблеми з чорним ActionBar .

Я також спробував додати це трохи хакерсько, додавши Toolbarдо кореневого макета, але це не спрацювало, як очікувалося.


Ви повинні використовувати фрагмент преференцій: developer.android.com/reference/android/preference/…
Джаред Берроуз

1
@JaredBurrows ви не можете використовувати PreferenceFragment pre 3.0, хоча
tyczj

1
Я їх теж використовую. AFIK Мені потрібно зробити посилання на PreferenceActivity, що використовує PreferenceFragments. Однак, як зазначає tycyj, вони мені потрібні і для застарілої підтримки.
rekire

1
Панель інструментів - це лише вигляд. Ви можете додати його де завгодно.
Джаред Берроус,

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

Відповіді:


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 :

приклад


ОНОВЛЕННЯ (сумісність з пряниками):

Як зазначено тут , 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 />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

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

1
Я повинен виправити себе. android:themeОбхідний шлях фіксує тільки чорний колір тексту на панелі інструментів для Android 5.0 +. Здається, щось змінилося з новою бібліотекою підтримки (я використовую 22.2.0).
tony

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
Для простих екранів налаштувань це, безумовно, найпростіше рішення.
Chris Cirefice

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

Ось мої налаштування_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.03.16

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
aka AppCompatPreferenceActivity з офіційних зразків v7.
Avinash R

4

Привіт, я не, якщо у вас все ще є ця проблема. Але я думаю, я опублікую те, що я зробив, щоб вирішити цю проблему, і сподіваюся, це допоможе комусь.

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

Перевірте це посилання тут: 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>
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.