web-dev-qa-db-fra.com

Aucune barre d'action dans PreferenceActivity après la mise à niveau vers Support Library v21

Après avoir mis à niveau vers la bibliothèque de support technique v21, ma barre d’action dans ma PreferenceActivity a disparu.

Ai-je oublié des attributs dans mon thème pour l'activer à nouveau? J'ai eu un problème similaire avec un ActionBar noir .

J'ai également essayé d'ajouter un peu de hack en ajoutant Toolbar à la disposition racine, mais cela ne fonctionnait pas comme prévu.

84
rekire

S'il vous plaît trouver le repo GitHub: ici


Très similaire à votre propre code mais ajouté XML pour permettre le titre du jeu:

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 :

example


UPDATE (Compatibilité pain d'épice):

Comme souligné ici , les périphériques Gingerbread retournent une exception 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!


UPDATE 2: SOLUTION DE CONTOURNEMENT

Comme indiqué dans de nombreuses notes de dev, PreferenceActivity ne prend pas en charge la coloration des éléments. Toutefois, en utilisant quelques classes internes, vous POUVEZ y parvenir. C'est jusqu'à ce que ces classes sont supprimées. (Fonctionne avec appCompat support-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;

Puis substituez la méthode 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:

example 2


AppCompat 22.1

AppCompat 22.1 a introduit de nouveaux éléments coloré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. Suivez plutôt ceci (en remplaçant toujours 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;
}

ECRANS DE PREFERENCE NEDES

De nombreuses personnes rencontrent des problèmes pour inclure la barre d'outils dans des <PreferenceScreen />s imbriqués. Cependant, j'ai trouvé une solution! - Après beaucoup d'essais et d'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 PreferenceScreen pose un problème est qu’elle repose sur une boîte de dialogue d’emballage, 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 Toolbar ne permet pas l'élévation ni l'ombrage dans les périphériques antérieurs à la v21, donc si vous souhaitez avoir une élévation sur votre Toolbar, vous devez l'envelopper dans une 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 fichier 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

J'ai enquêté sur le problème de chevauchement signalé et je ne peux pas le reproduire.

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

 enter image description here

Si je manque quelque chose s'il vous plaît faites le moi savoir via ce repo et je vais enquêter.

171
David Passmore

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

PreferenceFragment:

public class SettingsFragment extends PreferenceFragment {

@Override
public void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    addPreferencesFromResource(R.xml.settings_preferences);
}}
44
Abdullah

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 mon 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" />
7
rekire

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 factuelle à partir de la bibliothèque de support. Voici un exemple de code à 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;
    }
}
6
Tad

Salut, je ne suis pas si vous avez toujours ce problème. Mais je pense que je posterai ce que j'ai fait pour résoudre ce problème et 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 doit hériter de ActionBarActivity. Donc, voici votre problème.

2) Les étapes que j'ai l'habitude de résoudre sont les suivantes:

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é!

4
AfrikAndroid

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

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

0
any mous

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

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