J'avais des difficultés à utiliser la nouvelle barre d'outils Material Design dans la bibliothèque de support sur un écran Préférences.
J'ai un fichier settings.xml comme ci-dessous:
<PreferenceScreen xmlns:Android="http://schemas.Android.com/apk/res/Android">
<PreferenceCategory
Android:title="@string/AddingItems"
Android:key="pref_key_storage_settings">
<ListPreference
Android:key="pref_key_new_items"
Android:title="@string/LocationOfNewItems"
Android:summary="@string/LocationOfNewItemsSummary"
Android:entries="@array/new_items_entry"
Android:entryValues="@array/new_item_entry_value"
Android:defaultValue="1"/>
</PreferenceCategory>
</PreferenceScreen>
Les chaînes sont définies ailleurs.
Vous pouvez utiliser un PreferenceFragment
comme alternative à PreferenceActivity
. Donc, voici l’emballage Activity
exemple:
public class MyPreferenceActivity extends ActionBarActivity {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.pref_with_actionbar);
Android.support.v7.widget.Toolbar toolbar = (Android.support.v7.widget.Toolbar) findViewById(uk.japplications.jcommon.R.id.toolbar);
setSupportActionBar(toolbar);
getFragmentManager().beginTransaction().replace(R.id.content_frame, new MyPreferenceFragment()).commit();
}
}
Et voici le fichier de mise en page (pref_with_actionbar):
<RelativeLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_height="@dimen/action_bar_height"
Android:layout_width="match_parent"
Android:minHeight="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:theme="@style/ToolbarTheme.Base"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
<FrameLayout
Android:id="@+id/content_frame"
Android:layout_below="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
</RelativeLayout>
Et enfin le PreferenceFragment
:
public static class MyPreferenceFragment extends PreferenceFragment{
@Override
public void onCreate(final Bundle savedInstanceState){
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.settings);
}
}
J'espère que ça aidera quelqu'un.
S'il vous plaît trouver le repo GitHub: Ici
Un peu tard pour la soirée, mais c’est la solution que j’utilise comme solution pour 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 :
Selon les commentaires, les appareils Gingerbread retournent une exception NullPointerException sur cette ligne:
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.ICE_CREAM_SANDWICH) {
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 LA TEINTE
Comme indiqué dans de nombreuses notes de développement, 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:
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. 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.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 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 NESTED
De nombreuses personnes rencontrent des problèmes pour inclure la barre d'outils dans un <PreferenceScreen />
imbriqué. 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, c'est parce qu'ils sont basés 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.
De par sa conception, l'importation de Toolbar
ne permet pas l'élévation ni l'ombrage dans les appareils antérieurs à la v21, donc si vous souhaitez avoir une élévation sur votre Toolbar
, vous devez l'envelopper dans un AppBarLayout
:
settings_toolbar.xml
:
<Android.support.design.widget.AppBarLayout
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'
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:
Si je manque quelque chose s'il vous plaît faites le moi savoir via ce repo et je vais enquêter.
Complètement nouvelle mise à jour.
Avec quelques expériences, il semble que j'ai trouvé la solution de travail AppCompat 22.1+ pour les écrans de préférences imbriqués.
Premièrement, comme cela est mentionné dans de nombreuses réponses (dont une ici), vous devrez utiliser le nouveau AppCompatDelegate
. Utilisez le fichier AppCompatPreferenceActivity.Java
dans les démonstrations de support ( https://Android.googlesource.com/platform/development/+/58bf5b99e6132332afb8b44b4c8cedf5756ad464/samples/Sort7Demos/sort app/AppCompatPreferenceActivity.Java ) et étendez-le simplement ou copiez les fonctions correspondantes dans votre propre PreferenceActivity
. Je vais montrer la première approche ici:
public class SettingsActivity extends AppCompatPreferenceActivity {
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.settings, target);
setContentView(R.layout.settings_page);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
setSupportActionBar(toolbar);
ActionBar bar = getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
bar.setTitle(...);
}
@Override
protected boolean isValidFragment(String fragmentName) {
return SettingsFragment.class.getName().equals(fragmentName);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Android.R.id.home:
onBackPressed();
break;
}
return super.onOptionsItemSelected(item);
}
}
La mise en page est assez simple et habituelle (layout/settings_page.xml
):
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:layout_margin="0dp"
Android:orientation="vertical"
Android:padding="0dp">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
Android:elevation="4dp"
Android:theme="@style/..."/>
<ListView
Android:id="@id/Android:list"
Android:layout_width="match_parent"
Android:layout_height="match_parent"/>
</LinearLayout>
Les préférences elles-mêmes sont définies comme d'habitude (xml/settings.xml
):
<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android">
<header
Android:fragment="com.example.SettingsFragment"
Android:summary="@string/..."
Android:title="@string/...">
<extra
Android:name="page"
Android:value="page1"/>
</header>
<header
Android:fragment="com.example.SettingsFragment"
Android:summary="@string/..."
Android:title="@string/...">
<extra
Android:name="page"
Android:value="page2"/>
</header>
...
</preference-headers>
Aucune différence réelle dans les solutions sur le net jusqu'à ce point. En fait, vous pouvez l'utiliser même si vous n'avez pas d'écrans imbriqués, pas d'en-têtes, juste un seul écran.
Nous utilisons un PreferenceFragment
commun pour toutes les pages plus profondes, différencié par les paramètres extra
dans les en-têtes. Chaque page aura un XML séparé avec un PreferenceScreen
commun (xml/settings_page1.xml
et al.) Commun. Le fragment utilise la même présentation que l'activité, y compris la barre d'outils.
public class SettingsFragment extends PreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getActivity().setTheme(R.style...);
if (getArguments() != null) {
String page = getArguments().getString("page");
if (page != null)
switch (page) {
case "page1":
addPreferencesFromResource(R.xml.settings_page1);
break;
case "page2":
addPreferencesFromResource(R.xml.settings_page2);
break;
...
}
}
}
@Override
public View onCreateView(@NonNull LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View layout = inflater.inflate(R.layout.settings_page, container, false);
if (layout != null) {
AppCompatPreferenceActivity activity = (AppCompatPreferenceActivity) getActivity();
Toolbar toolbar = (Toolbar) layout.findViewById(R.id.toolbar);
activity.setSupportActionBar(toolbar);
ActionBar bar = activity.getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
bar.setDisplayShowTitleEnabled(true);
bar.setHomeAsUpIndicator(R.drawable.abc_ic_ab_back_mtrl_am_alpha);
bar.setTitle(getPreferenceScreen().getTitle());
}
return layout;
}
@Override
public void onResume() {
super.onResume();
if (getView() != null) {
View frame = (View) getView().getParent();
if (frame != null)
frame.setPadding(0, 0, 0, 0);
}
}
}
Enfin, un bref résumé de la façon dont cela fonctionne réellement. La nouvelle AppCompatDelegate
nous permet d'utiliser n'importe quelle activité avec les fonctionnalités d'AppCompat, pas seulement celles qui s'étendent des activités réellement présentes dans AppCompat. Cela signifie que nous pouvons transformer le bon vieux PreferenceActivity
en un nouveau et ajouter la barre d’outils comme d’habitude. À partir de ce moment, nous pouvons nous en tenir aux anciennes solutions concernant les écrans de préférence et les en-têtes, sans aucun écart par rapport à la documentation existante. Il y a juste un point important: n'utilisez pas onCreate()
dans l'activité car cela entraînerait des erreurs. Utilisez onBuildHeaders()
pour toutes les opérations telles que l'ajout de la barre d'outils.
La seule différence réelle réside dans le fait que vous pouvez utiliser la même approche avec les fragments pour que cela fonctionne avec les écrans imbriqués. Vous pouvez utiliser leur onCreateView()
de la même manière, en gonflant votre propre présentation au lieu de celle du système, en ajoutant la barre d’outils de la même manière que dans l’activité.
Si vous souhaitez utiliser PreferenceHeaders, vous pouvez utiliser l'approche suivante:
import Android.support.v7.widget.Toolbar;
public class MyPreferenceActivity extends PreferenceActivity
Toolbar mToolbar;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ViewGroup root = (ViewGroup) findViewById(Android.R.id.content);
LinearLayout content = (LinearLayout) root.getChildAt(0);
LinearLayout toolbarContainer = (LinearLayout) View.inflate(this, R.layout.activity_settings, null);
root.removeAllViews();
toolbarContainer.addView(content);
root.addView(toolbarContainer);
mToolbar = (Toolbar) toolbarContainer.findViewById(R.id.toolbar);
}
@Override
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
// Other methods
}
layout/activity_settings.xml
<LinearLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_height="?attr/actionBarSize"
Android:layout_width="match_parent"
Android:minHeight="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:theme="@style/AppTheme"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light"/>
</LinearLayout>
Vous pouvez utiliser la disposition que vous préférez ici. Assurez-vous simplement de l'ajuster dans le code Java.
Et enfin, votre fichier avec en-têtes (xml/pref_headers.xml)
<preference-headers xmlns:Android="http://schemas.Android.com/apk/res/Android">
<header
Android:fragment="com.example.FirstFragment"
Android:title="@string/pref_header_first" />
<header
Android:fragment="com.example.SecondFragment"
Android:title="@string/pref_header_second" />
</preference-headers>
Avec la sortie de Android Support Library 22.1.0 et de la nouvelle AppCompatDelegate, vous trouverez ici un bon exemple d’une implémentation de PreferenceActivity avec prise en charge matérielle avec compatibilité ascendante.
Update Il fonctionne également sur les écrans imbriqués.
Moi aussi, je cherchais une solution pour ajouter la barre d’outillage de support v7 ( API 25 ) à AppCompatPreferenceActivity (créé automatiquement par AndroidStudio lors de l’ajout de SettingsActivity). Après avoir lu plusieurs solutions et essayé chacune d’elles, j’ai eu du mal à faire afficher également les exemples générés PreferenceFragment avec une barre d’outils.
Une solution modifiée qui fonctionnait en quelque sorte allait de " Gabor ".
L'une des mises en garde à laquelle j'ai dû faire face était que 'onBuildHeaders' a déjà tiré une fois. Si vous tournez un périphérique (un téléphone, par exemple) sur le côté, la vue est recréée et PreferenceActivity est à nouveau sans barre d’outils. Toutefois, PreferenceFragments conservera le sien.
J'ai essayé d'utiliser 'onPostCreate' pour appeler 'setContentView', cette opération permettant de recréer la barre d'outils lorsque l'orientation changeant, PreferenceFragments serait alors vide.
Ce que j'ai proposé exploite à peu près tous les conseils et réponses que je pourrais lire sur ce sujet. J'espère que d'autres le trouveront utile aussi.
Nous allons commencer avec le Java
Premier dans (le généré) AppCompatPreferenceActivity.Java J'ai modifié 'setSupportActionBar' ainsi:
public void setSupportActionBar(@Nullable Toolbar toolbar) {
getDelegate().setSupportActionBar(toolbar);
ActionBar bar = getDelegate().getSupportActionBar();
bar.setHomeButtonEnabled(true);
bar.setDisplayHomeAsUpEnabled(true);
}
Deuxièmement , j'ai créé une nouvelle classe nommée AppCompatPreferenceFragment.Java (c'est courant un nom non utilisé, même s’il ne reste peut-être pas comme ça!):
abstract class AppCompatPreferenceFragment extends PreferenceFragment {
@Override
public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
View view = inflater.inflate(R.layout.activity_settings, container, false);
if (view != null) {
Toolbar toolbar = (Toolbar) view.findViewById(R.id.toolbar_settings);
((AppCompatPreferenceActivity) getActivity()).setSupportActionBar(toolbar);
}
return view;
}
@Override
public void onResume() {
super.onResume();
View frame = (View) getView().getParent();
if (frame != null) frame.setPadding(0, 0, 0, 0);
}
}
C'est la partie de la réponse de Gabor qui a fonctionné.
Last , Pour plus de cohérence, nous devons apporter quelques modifications à SettingsActivity.Java :
public class SettingsActivity extends AppCompatPreferenceActivity {
boolean mAttachedFragment;
@Override
protected void onCreate(Bundle savedInstanceState) {
mAttachedFragment = false;
super.onCreate(savedInstanceState);
}
@Override
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public void onBuildHeaders(List<Header> target) {
loadHeadersFromResource(R.xml.pref_headers, target);
}
@Override
public void onAttachFragment(Fragment fragment) {
mAttachedFragment = true;
super.onAttachFragment(fragment);
}
@Override
protected void onPostCreate(Bundle savedInstanceState) {
super.onPostCreate(savedInstanceState);
//if we didn't attach a fragment, go ahead and apply the layout
if (!mAttachedFragment) {
setContentView(R.layout.activity_settings);
setSupportActionBar((Toolbar)findViewById(R.id.toolbar_settings));
}
}
/**
* This fragment shows general preferences only. It is used when the
* activity is showing a two-pane settings UI.
*/
@TargetApi(Build.VERSION_CODES.HONEYCOMB)
public static class GeneralPreferenceFragment extends AppCompatPreferenceFragment {
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.pref_general);
setHasOptionsMenu(true);
bindPreferenceSummaryToValue(findPreference("example_text"));
bindPreferenceSummaryToValue(findPreference("example_list"));
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
int id = item.getItemId();
if (id == Android.R.id.home) {
startActivity(new Intent(getActivity(), SettingsActivity.class));
return true;
}
return super.onOptionsItemSelected(item);
}
}
}
Certains codes ont été omis de l'activité par souci de brièveté. Les composants clés ici sont ' onAttachedFragment ', ' onPostCreate ', et que 'GeneralPreferenceFragment' étend désormais la coutume ' AppCompatPreferenceFragment ' au lieu de PreferenceFragment.
Résumé du code : si un fragment est présent, le fragment injecte la nouvelle présentation et appelle la fonction modifiée 'setSupportActionBar'. Si le fragment n'est pas présent, SettingsActivity injecte la nouvelle présentation sur 'onPostCreate'
Passons maintenant au XML (très simple):
activity_settings.xml :
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
Android:orientation="vertical"
Android:layout_width="match_parent"
Android:layout_height="match_parent">
<include
layout="@layout/app_bar_settings"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</LinearLayout>
app_bar_settings.xml :
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout
xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/content_frame"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:fitsSystemWindows="true"
tools:context=".SettingsActivity">
<Android.support.design.widget.AppBarLayout
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:theme="@style/AppTheme.NoActionBar.AppBarOverlay">
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar_settings"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
app:popupTheme="@style/AppTheme.NoActionBar.PopupOverlay" />
</Android.support.design.widget.AppBarLayout>
<include layout="@layout/content_settings" />
</Android.support.design.widget.CoordinatorLayout>
content_settings.xml :
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:id="@+id/content"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:paddingBottom="@dimen/activity_vertical_margin"
Android:paddingLeft="@dimen/activity_horizontal_margin"
Android:paddingRight="@dimen/activity_horizontal_margin"
Android:paddingTop="@dimen/activity_vertical_margin"
app:layout_behavior="@string/appbar_scrolling_view_behavior"
tools:context=".SettingsActivity"
tools:showIn="@layout/app_bar_settings">
<ListView
Android:id="@Android:id/list"
Android:layout_width="match_parent"
Android:layout_height="wrap_content" />
</RelativeLayout>
Résultat final :
Bien que les réponses ci-dessus semblent complexes, si vous voulez une solution rapide pour utiliser Toolbar avec l’API 7 et plus tout en prolongeant PreferenceActivity
, j’ai reçu l’aide de ce projet ci-dessous.
https://github.com/AndroidDeveloperLB/ActionBarPreferenceActivity
activity_settings.xml
<LinearLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:tools="http://schemas.Android.com/tools"
xmlns:app="http://schemas.Android.com/apk/res-auto"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:orientation="vertical" >
<Android.support.v7.widget.Toolbar
Android:id="@+id/toolbar"
Android:layout_width="match_parent"
Android:layout_height="wrap_content"
Android:background="@color/app_theme_light"
app:popupTheme="@style/Theme.AppCompat.Light"
app:theme="@style/Theme.AppCompat" />
<FrameLayout
Android:layout_width="match_parent"
Android:layout_height="match_parent"
Android:padding="@dimen/padding_medium" >
<ListView
Android:id="@Android:id/list"
Android:layout_width="match_parent"
Android:layout_height="match_parent" />
</FrameLayout>
SettingsActivity.Java
public class SettingsActivity extends PreferenceActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.toolbar);
addPreferencesFromResource(R.xml.preferences);
toolbar.setClickable(true);
toolbar.setNavigationIcon(getResIdFromAttribute(this, R.attr.homeAsUpIndicator));
toolbar.setTitle(R.string.menu_settings);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
private static int getResIdFromAttribute(final Activity activity, final int attr) {
if (attr == 0) {
return 0;
}
final TypedValue typedvalueattr = new TypedValue();
activity.getTheme().resolveAttribute(attr, typedvalueattr, true);
return typedvalueattr.resourceId;
}
}
J'ai une nouvelle solution (peut-être plus simple) qui utilise les AppCompatPreferenceActivity
des exemples de Support v7. Avec ce code en main, j'ai créé ma propre mise en page qui comprend une barre d'outils:
<?xml version="1.0" encoding="utf-8"?>
<Android.support.design.widget.CoordinatorLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto" xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent" Android:layout_height="match_parent"
Android:fitsSystemWindows="true" tools:context="edu.adelphi.Adelphi.ui.activity.MainActivity">
<Android.support.design.widget.AppBarLayout Android:id="@+id/appbar"
Android:layout_width="match_parent" Android:layout_height="wrap_content"
Android:theme="@style/AppTheme.AppBarOverlay">
<Android.support.v7.widget.Toolbar Android:id="@+id/toolbar"
Android:layout_width="match_parent" Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary" app:popupTheme="@style/AppTheme.PopupOverlay"/>
</Android.support.design.widget.AppBarLayout>
<FrameLayout Android:id="@+id/content"
Android:layout_width="match_parent" Android:layout_height="match_parent"/>
</Android.support.design.widget.CoordinatorLayout>
Ensuite, dans mon AppCompatPreferenceActivity
, j'ai modifié setContentView
pour créer une nouvelle mise en page et placer la mise en page fournie dans mon FrameLayout
:
@Override
public void setContentView(@LayoutRes int layoutResID) {
View view = getLayoutInflater().inflate(R.layout.toolbar, null);
FrameLayout content = (FrameLayout) view.findViewById(R.id.content);
getLayoutInflater().inflate(layoutResID, content, true);
setContentView(view);
}
Ensuite, je prolonge simplement AppCompatPreferenceActivity
, ce qui me permet d’appeler setSupportActionBar((Toolbar) findViewById(R.id.toolbar))
et de gonfler les éléments de menu de la barre d’outils. Tout en gardant les avantages d'un PreferenceActivity
.
Restons simples et propres ici, sans casser aucune disposition incorporée
import Android.support.design.widget.AppBarLayout;
import Android.support.v4.app.NavUtils;
import Android.support.v7.widget.Toolbar;
private void setupActionBar() {
Toolbar toolbar = new Toolbar(this);
AppBarLayout appBarLayout = new AppBarLayout(this);
appBarLayout.addView(toolbar);
final ViewGroup root = (ViewGroup) findViewById(Android.R.id.content);
final ViewGroup window = (ViewGroup) root.getChildAt(0);
window.addView(appBarLayout, 0);
setSupportActionBar(toolbar);
// Show the Up button in the action bar.
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
onBackPressed();
}
});
}
J'ai trouvé cette solution simple en travaillant dessus. Nous devons d’abord créer une mise en page pour l’activité paramètres.
activity_settings.xml
<RelativeLayout xmlns:Android="http://schemas.Android.com/apk/res/Android"
xmlns:app="http://schemas.Android.com/apk/res-auto"
xmlns:tools="http://schemas.Android.com/tools"
Android:layout_width="match_parent"
Android:layout_height="match_parent"
tools:context="com.my.package">
<Android.support.v7.widget.Toolbar
Android:id="@+id/tool_bar"
Android:layout_width="match_parent"
Android:layout_height="?attr/actionBarSize"
Android:background="?attr/colorPrimary"
Android:theme="@style/ThemeOverlay.AppCompat.Dark.ActionBar"
app:elevation="@dimen/appbar_elevation"
app:navigationIcon="?attr/homeAsUpIndicator"
app:navigationContentDescription="@string/abc_action_bar_up_description"
app:popupTheme="@style/ThemeOverlay.AppCompat.Light" />
<ListView
Android:id="@Android:id/list"
Android:layout_width="wrap_content"
Android:layout_height="wrap_content"
Android:layout_below="@+id/tool_bar" />
</RelativeLayout>
Assurez-vous d’ajouter une vue de liste avec Android:id="@Android:id/list"
, sinon cela jettera NullPointerException
La prochaine étape consiste à ajouter (remplacer) la méthode onCreate
dans l'activité de paramétrage.
Settings.Java
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_settings);
Toolbar toolbar = (Toolbar) findViewById(R.id.tool_bar);
toolbar.setTitle(R.string.action_settings);
toolbar.setNavigationOnClickListener(new View.OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
}
Assurez-vous d'importer Android.suppoer.v7.widget.Toolbar
. Cela devrait fonctionner à peu près sur toutes les API de plus de 16 ans (haricot gelée et plus)
Je voudrais continuer la solution marquée de James Cross, car après cela, il y a un problème consistant à fermer uniquement l'écran imbriqué actif (PreferenceFragment) afin de ne pas fermer également SettingsActivity.
En fait, cela fonctionne sur tous les écrans imbriqués (donc, je ne comprends pas la solution de Gábor que j'ai essayée sans succès. Cela fonctionne jusqu'à un certain point, mais c'est un fouillis de barres d'outils multiples), car lorsque l'utilisateur clique sur un écran de préférence secondaire , seul le fragment est modifié (voir <FrameLayout Android:id="@+id/content_frame" .../>
) pas la barre d’outils qui reste toujours active et visible, mais un comportement personnalisé doit être implémenté pour fermez chaque fragment en conséquence.
Dans la classe principale SettingsActivity
qui étend ActionBarActivity
, les méthodes suivantes doivent être implémentées. Notez que private setupActionBar()
est appelé à partir de onCreate()
private void setupActionBar() {
Toolbar toolbar = (Toolbar)findViewById(R.id.toolbar);
//Toolbar will now take on default Action Bar characteristics
setSupportActionBar(toolbar);
getSupportActionBar().setHomeButtonEnabled(true);
getSupportActionBar().setDisplayHomeAsUpEnabled(true);
}
@Override
public boolean onOptionsItemSelected(MenuItem item) {
switch (item.getItemId()) {
case Android.R.id.home:
onBackPressed();
return true;
}
return super.onOptionsItemSelected(item);
}
@Override
public void onBackPressed() {
if (getFragmentManager().getBackStackEntryCount() > 0) {
getFragmentManager().popBackStackImmediate();
//If the last fragment was removed then reset the title of main
// fragment (if so the previous popBackStack made entries = 0).
if (getFragmentManager().getBackStackEntryCount() == 0) {
getSupportActionBar()
.setTitle(R.string.action_settings_title);
}
} else {
super.onBackPressed();
}
}
Pour le title de l'écran imbriqué choisi, vous devez obtenir la référence de votre barre d'outils et définir le titre approprié avec toolbar.setTitle(R.string.pref_title_general);
(par exemple).
Il y a pas besoin d'implémenter la getSupportActionBar()
dans tous les PreferenceFragment puisque seule la vue du fragment est modifiée à chaque validation, pas la barre d'outils;
Il y a inutile de créer une fausse classe ToolbarPreference à ajouter à chaque préférence.xml (voir la réponse de Gábor).
Voici une bibliothèque que j'ai créée et basée sur du code AOSP, qui ajoute une teinte aux préférences et aux boîtes de dialogue, ajoute une barre d'actions et prend en charge toutes les versions de l'API 7:
https://github.com/AndroidDeveloperLB/MaterialPreferenceLibrary
Eh bien, cela reste un problème pour moi aujourd'hui (18 nov. 2015). J'ai essayé toutes les solutions de ce fil, mais il y avait deux choses principales que je ne pouvais pas résoudre:
J'ai donc fini par créer une bibliothèque avec une solution plus compliquée. Fondamentalement, je devais appliquer en interne des styles aux préférences si nous utilisions un périphérique pré-Lollipop et je gérais également les écrans imbriqués à l'aide d'un fragment personnalisé (la restauration de toute la hiérarchie imbriquée en tirant parti de PreferenceScreen clé ).
La bibliothèque est celle-ci: https://github.com/ferrannp/material-preferences
Et si vous êtes intéressé par le code source (trop long pour le poster ici), il s’agit essentiellement du noyau: https://github.com/ferrannp/material-preferences/blob/master/library/ src/main/Java/com/fnp/materialpreferences/PreferenceFragment.Java