Aucune barre d'action dans PreferenceActivity après la mise à niveau vers la bibliothèque de support v21

83

Après la mise à niveau vers la bibliothèque de support v21, mon ActionBar dans mon PreferenceActivityest parti.

Ai-je manqué certains attributs de mon thème pour le réactiver? J'ai eu des problèmes similaires avec une ActionBar noire .

J'ai également essayé de l'ajouter un peu hackish en ajoutant un Toolbarà la disposition racine, mais cela n'a pas fonctionné comme prévu.

rekire
la source
Vous devriez utiliser le fragment de préférence: developer.android.com/reference/android/preference/...
Jared Burrows
1
@JaredBurrows vous ne pouvez pas utiliser PreferenceFragment pre 3.0 cependant
tyczj
1
Je les utilise aussi. AFIK J'ai besoin de créer un lien vers une PreferenceActivity qui utilise PreferenceFragments. Cependant, comme le souligne tycyj, j'en ai besoin aussi pour le soutien de l'héritage.
rekire
1
La barre d'outils n'est qu'une vue. Vous pouvez l'ajouter n'importe où.
Jared Burrows
1
Vous pouvez consulter l'exemple que j'ai fait ici: github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
développeur Android

Réponses:

170

Veuillez trouver le dépôt GitHub: ici


Très similaire à votre propre code mais ajouté xml pour permettre le titre défini:

Continuer à utiliser 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 :

exemple


MISE À JOUR (compatibilité pain d'épice):

Comme indiqué ici , Gingerbread Devices renvoie NullPointerException sur cette ligne:

LinearLayout root = (LinearLayout)findViewById(android.R.id.list).getParent().getParent().getParent();

RÉPARER:

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

Tout problème avec ce qui précède, faites le moi savoir!


MISE À JOUR 2: CONTOURNEMENT DE TEINTE

Comme indiqué dans de nombreuses notes de développement, PreferenceActivityne prend pas en charge la teinte des éléments, mais en utilisant quelques classes internes, vous POUVEZ y parvenir. C'est jusqu'à ce que ces classes soient supprimées. (Fonctionne avec le support appCompat-v7 v21.0.3).

Ajoutez les importations suivantes:

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;

Remplacez ensuite la onCreateViewméthode:

@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:

exemple 2


AppCompat 22.1

AppCompat 22.1 a introduit de nouveaux éléments teintés, ce qui signifie qu'il n'est plus nécessaire d'utiliser les classes internes pour obtenir le même effet que la dernière mise à jour. Au lieu de cela, suivez ceci (toujours prioritaire 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;
}

ÉCRANS DE PRÉFÉRENCE EMBARQUÉS

Beaucoup de gens rencontrent des problèmes pour inclure la barre d'outils dans les <PreferenceScreen />s imbriqués , cependant, j'ai trouvé une solution !! - Après de nombreux essais et erreurs!

Ajoutez ce qui suit à votre 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();
        }
    });
}

La raison pour laquelle cela PreferenceScreenest si pénible est parce qu'ils sont basés sur une boîte de dialogue enveloppante, nous devons donc capturer la disposition de la boîte de dialogue pour y ajouter la barre d'outils.


Ombre de la barre d'outils

De par sa conception, l'importation de Toolbarne permet pas d'élévation et d'ombrage dans les appareils antérieurs à la v21, donc si vous souhaitez avoir une élévation sur votre, Toolbarvous devez l'envelopper dans un 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>

Sans oublier d'ajouter l'ajout de la bibliothèque Design Support en tant que dépendance dans le build.gradlefichier:

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

J'ai étudié le problème de chevauchement signalé et je ne peux pas reproduire le problème.

Le code complet utilisé comme ci-dessus produit les éléments suivants:

entrez la description de l'image ici

S'il me manque quelque chose, veuillez me le faire savoir via ce dépôt et j'enquêterai .

David Passmore
la source
Belle: j'ai utilisé la première approche (le pain d'épice n'est pas sur ma cible). Merci!
JJ86
Il semble que le bouton haut soit cassé sur Gingerbread en utilisant cet exemple.
idunnololz
1
Merci pour votre excellente réponse, je vous ai donné il y a quelques jours l'état accepté. Je viens de copier la partie teinture, pour m'assurer qu'elle aura
fière
1
Je dois me corriger. La android:themesolution de contournement corrige uniquement la couleur du texte noir dans la barre d'outils pour Android 5.0+. Il apparaît comme quelque chose de changé avec la nouvelle bibliothèque de support (j'utilise 22.2.0).
tony
4
Le parent de android.R.id.list est FrameLayout dans Android N
zys
45

Utilisez AppCompatActivity & PreferenceFragment pour résoudre le problème:

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

PréférenceFragment:

public class SettingsFragment extends PreferenceFragment {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.settings_preferences);
}}
Abdullah
la source
1
ActionBarActivity est obsolète.
rekire le
@rekire its android.support.v7.app.ActionBarActivity
Abdullah
4
Étendez simplement AppCompatActivity au lieu d'ActionBarActivity.
SammyT
1
A travaillé pour moi, et beaucoup plus simple que ce qui précède.
Aaron Blenkush
1
Pour les écrans de préférences simples, c'est de loin la solution la plus simple à mettre en œuvre.
Chris Cirefice
7

J'ai fini par ajouter moi-même la barre d'outils avec ce code simple:

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

Voici ma 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" />
rekire
la source
Je suppose que je l'ai mis dans onCreate ()
rekire
6

Une meilleure solution que de "lancer votre propre" barre d'action consiste à utiliser la classe AppCompatDelegate , qui vous permet d' ajouter une barre d'action réelle et factuelle à partir de la bibliothèque de support. Voici un exemple de code pour l'utiliser, tiré de la réponse de Ľubomír Kučera à cette question .

...
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;
    }
}
Tad
la source
4
aka AppCompatPreferenceActivity à partir d' exemples officiels v7.
Avinash R
4

Salut je ne suis pas si vous avez toujours ce problème. Mais je pense que je publierai ce que j'ai fait pour résoudre ce problème et j'espère que cela aidera quelqu'un.

1) Tout d'abord, vous avez peut-être remarqué que PreferenceActivity étend ListActivity qui à son tour s'étend de Activity.

Selon les commentaires sur le blog des développeurs ( http://android-developers.blogspot.com/2014/10/appcompat-v21-material-design-for-pre.html ), pour utiliser v21 toutes vos activités doivent hériter d'ActionBarActivity . Il y a donc votre problème.

2) Les étapes que j'ai utilisées pour résoudre sont:

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.

Cela devrait le résoudre.

À votre santé!

AfrikAndroid
la source
4
"Faites que votre classe PreferenceActivity étend ActionBarActivity" - mais COMMENT?
vbence
Consultez ce lien ici: code.hootsuite.com
...
1
Merci, je pense que cela se rapproche le plus possible. Le vrai problème est que PreferenceActivity a une navigation intégrée via loadHeadersFromResource , avec des fragments que vous devez créer vous-même.
vbence
0

J'ai fait quelque chose de similaire à la question acceptée, mais j'utilise également ma mise en page dans d'autres activités MainActivity, donc je ne peux pas simplement coder une flèche en dur.

Ce qui a fonctionné pour moi:

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);
}
Moterrola
la source
0

J'ai eu le même problème. essayez simplement de changer le thème de l'activité en celui qui contient une ActionBar. l'ajout de la ligne suivante dans la balise d'activité de SettingsActivity a fonctionné pour moi:

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

n'importe quel mous
la source
-1

Un moyen facile que j'ai compris est de passer outre:

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

Dans votre 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>
Tejumola David
la source