Je veux prendre en charge au moins l'api 10, je veux pouvoir styler mes préférences, je veux pouvoir avoir des en-têtes (ou afficher PreferenceScreen
s). Il semble que PreferenceActivity
, non entièrement pris en charge par la coloration de AppCompat
, ne convienne pas. J'essaie donc d'utiliser AppCompatActivity
et PreferenceFragmentCompat
.
public class Prefs extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
if (savedInstanceState == null)
getSupportFragmentManager().beginTransaction()
.replace(Android.R.id.content, new PreferencesFragment())
.commit();
}
public static class PreferencesFragment extends PreferenceFragmentCompat {
@Override public void onCreate(final Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
addPreferencesFromResource(R.xml.preferences);
}
@Override
public void onDisplayPreferenceDialog(Preference preference) {
// the following call results in a dialogue being shown
super.onDisplayPreferenceDialog(preference);
}
@Override public void onNavigateToScreen(PreferenceScreen preferenceScreen) {
// I can probably use this to go to to a nested preference screen
// I'm not sure...
}
}
}
Maintenant, je veux créer une préférence personnalisée qui fournira le choix d'une police. Avec PreferenceActivity
, je pourrais simplement faire
import Android.preference.DialogPreference;
public class FontPreference extends DialogPreference {
public FontPreference(Context context, AttributeSet attrs) {super(context, attrs);}
@Override protected void onPrepareDialogBuilder(Builder builder) {
super.onPrepareDialogBuilder(builder);
// do something with builder and make a Nice cute dialogue, for example, like this
builder.setSingleChoiceItems(new FontAdapter(), 0, null);
}
}
et utilisez xml comme celui-ci pour l'afficher
<my.app.FontPreference Android:title="Choose font" Android:summary="Unnecessary summary" />
Mais maintenant, il n'y a pas de onPrepareDialogBuilder
dans Android.support.v7.preference.DialogPreference
. Au lieu de cela, il a été déplacé vers PreferenceDialogFragmentCompat
. J'ai trouvé peu d'informations sur la façon d'utiliser cette chose, et je ne sais pas comment passer du xml à l'affichage. Le fragment de préférence v14 a le code suivant:
public void onDisplayPreferenceDialog(Preference preference) {
...
final DialogFragment f;
if (preference instanceof EditTextPreference)
f = EditTextPreferenceDialogFragment.newInstance(preference.getKey());
...
f.show(getFragmentManager(), DIALOG_FRAGMENT_TAG);
}
J'ai essayé le sous-classement Android.support.v7.preference.DialogPreference
et que onDisplayPreferenceDialog
utilise un morceau de code similaire pour instancier un mannequin FontPreferenceFragment
mais il échoue avec l'exception suivante.
Java.lang.IllegalStateException: Target fragment must implement TargetFragment interface
À ce stade, je suis déjà trop profondément dans le pétrin et je ne veux pas creuser davantage. Google ne sait rien de cette exception. Quoi qu'il en soit, cette méthode semble être trop compliquée. Alors, quelle est la meilleure façon de créer des préférences personnalisées à l'aide de la bibliothèque Android.support.v7.preference?
Remarque importante: Actuellement (v23.0.1 de la bibliothèque v7) il y a encore beaucoup de problèmes de thème avec le 'PreferenceThemeOverlay' (voir ce problème ). Sur Lollipop par exemple, vous vous retrouvez avec des en-têtes de catégorie de style Holo.
Après quelques heures frustrantes, j'ai finalement réussi à créer une préférence v7 personnalisée. Créer votre propre Preference
semble plus difficile que vous ne le pensez. Assurez-vous donc de prendre un peu de temps.
Au début, vous vous demandez peut-être pourquoi vous trouverez à la fois un DialogPreference
et un PreferenceDialogFragmentCompat
pour chaque type de préférence. Il s'avère que le premier est la préférence réelle, le second est le DialogFragment
où la préférence serait affichée. Malheureusement, vous devez sous-classer les deux d'entre eux .
Ne vous inquiétez pas, vous n'aurez pas besoin de changer de code. Il vous suffit de déplacer certaines méthodes:
setTitle()
ou persist*()
) se trouvent dans la classe DialogPreference
.onBindDialogView(View)
& onDialogClosed(boolean)
) ont été déplacées vers PreferenceDialogFragmentCompat
.Vous voudrez peut-être que votre classe existante prolonge la première, de cette façon, vous n'avez pas besoin de changer trop de choses, je pense. La saisie semi-automatique devrait vous aider à trouver les méthodes manquantes.
Lorsque vous avez terminé les étapes ci-dessus, il est temps de lier ces deux classes ensemble. Dans votre fichier xml, vous vous référerez à la partie préférences. Cependant, Android ne sait pas encore quel Fragment
il doit gonfler lorsque votre préférence personnalisée doit être. Par conséquent, vous devez remplacer onDisplayPreferenceDialog(Preference)
:
@Override
public void onDisplayPreferenceDialog(Preference preference) {
DialogFragment fragment;
if (preference instanceof LocationChooserDialog) {
fragment = LocationChooserFragmentCompat.newInstance(preference);
fragment.setTargetFragment(this, 0);
fragment.show(getFragmentManager(),
"Android.support.v7.preference.PreferenceFragment.DIALOG");
} else super.onDisplayPreferenceDialog(preference);
}
et aussi votre DialogFragment
doit gérer la 'clé':
public static YourPreferenceDialogFragmentCompat newInstance(Preference preference) {
YourPreferenceDialogFragmentCompat fragment = new YourPreferenceDialogFragmentCompat();
Bundle bundle = new Bundle(1);
bundle.putString("key", preference.getKey());
fragment.setArguments(bundle);
return fragment;
}
Cela devrait faire l'affaire. Si vous rencontrez des problèmes, essayez de jeter un œil aux sous-classes existantes et voyez comment Android l'a résolu (dans Android Studio: tapez le nom d'une classe et appuyez sur Ctrl + b pour voir la classe décompilée. J'espère que ça aide.
Il existe un bon didacticiel et un projet Github qui explique en détail comment créer une classe de préférences personnalisée qui étend la bibliothèque de préférences de support:
https://medium.com/@JakobUlbrich/building-a-settings-screen-for-Android-part-3-ae9793fd31ec - "Construire un Android Écran des paramètres (partie 3) ", par Jakob Ulbrich
https://github.com/jakobulbrich/preferences-demo - Exemple Android sur Github
Les points clés sont:
Vous aurez besoin d'un PreferenceDialogFragmentCompat
personnalisé, qui contrôle le lancement d'une boîte de dialogue lorsque vous cliquez sur la ligne de préférence. Il configure également la vue de la boîte de dialogue dans onBindDialogView()
.
Dans votre écran de préférences, remplacez onDisplayPreferenceDialog()
pour lancer votre PreferenceDialogFragmentCompat
personnalisé.
Vous aurez besoin d'un DialogPreference
personnalisé, qui contient la disposition de la boîte de dialogue. Ajoutez ce DialogPreference
à votre fichier de préférences XML.
L'exception se produit lorsque votre FontPreferenceFragment
n'implémente pas DialogPreference.TargetFragment . Vous devrez vous assurer que votre fragment implémente cette interface.