Comment faire pour utiliser le support.v7.préférence avec AppCompat et inconvénients potentiels

j'essayais d'implémenter des préférences pour une application AppCompat, en utilisant le support.v7.préférence. Il m'a fallu quelques jours pour y arriver, depuis support.v7.la préférence a quelques différences significatives par rapport aux préférences natives... ce qui n'est pas trop mal quand on sait, mais malheureusement il y a peu de documentation là-bas. Je pensais partager mes découvertes pour que les autres n'aient pas à endurer la même douleur.


... question:

comment implémenter au mieux les préférences pour les applications AppCompat (avec PreferenceFragment et AppCompatAcitivity étant incompatibles)?

voici quelques questions connexes:

documents officiels ici:

14
demandé sur Community 2016-01-25 04:49:47

2 réponses

Solution 1: Native PreferenceFragment with AppCompatActivity

dans AndroidStudio, choisissez Fichier > Nouveau projet>...> Activité de création . Ce modèle utilise une solution de contournement qui permet de retrofiter le PreferenceFragment pour travailler avec AppCompatActivity , similaire au support.v4.Fragment ou au support.v7.PreferenceFragmentCompat .

  • Pro: vous pouvez maintenant utiliser la fonctionnalité de préférence native dans un AppCompat app. C'est une approche rapide quand en utilisant le modèle AS, et vous pouvez vous en tenir aux préférences docs et workflows existants.
  • Con: le montage n'est pas très intuitif ou propre. En outre, comme il est généralement conseillé d'utiliser les libs de soutien lorsqu'ils sont disponibles, Je ne suis pas sûr de la façon dont l'avenir de cette approche est à l'épreuve.

Solution 2: support.v7.preference.PreferenceFragmentCompat avec AppCompatActivity

  • Pro: maximise la compatibilité
  • Con: beaucoup de lacunes à combler. Aussi cela pourrait ne pas fonctionner avec n'importe quelle préférence-extensions-libs (eg. ColorPicker ou FontPreferences ).

si vous choisissez de ne pas utiliser la Solution 1 (Je ne sais toujours pas laquelle des deux est la plus future preuve), il y a quelques inconvénients à utiliser support.v7.preference .

les inconvénients importants de L'utilisation de la Solution 2 sont mentionnés ci-dessous.

dépendances:

dependencies {
    ...
    compile 'com.android.support:appcompat-v7:23.1.1'
    compile 'com.android.support:preference-v7:23.1.1'
    compile 'com.android.support:support-v4:23.1.1'
}

thème: Vous aurez besoin de définir un preferenceTheme dans vos styles.xml, sinon l'exécution de votre application génère une exception.

<!-- Base application theme. -->
<style name="AppTheme" parent="Theme.AppCompat.Light">
    <!-- Customize your theme here. -->
    <item name="preferenceTheme">@style/PreferenceThemeOverlay</item>
</style>

vous pourriez vouloir diviser en différents styles pour 7+/14+/21+. Beaucoup de gens se plaignent de cet être buggé au moment d'écrire ces lignes. Il n'y est une réponse très complète disponible ici .

changements de comportement: utiliser les préférences natives est extrêmement simple: tout ce que vous devez faire est de définir/maintenir votre preferences.xml et utiliser addPreferencesFromResource(R.xml.preferences) dans votre PreferenceFragment . Les préférences personnalisées sont facilement faites en sous-classant DialogPreference , et puis juste référencé à l'intérieur du preferences.xml ... bam, fonctionne.

malheureusement, support.v7.preference a tout EU pour traiter avec Fragment dépouillé, ce qui le rend lâche une grande partie de sa fonctionnalité intégrée. Au lieu de simplement maintenir un XML, vous devez maintenant sous-classe et outrepasser un grand nombre de choses, tout ce qui est malheureusement non documenté.

PreferenceScreens: PreferenceScreens ne sont plus gérés par le cadre. Définir un PreferenceScreen dans votre preference.xml (comme décrit dans le docs ) affichera l'entrée, mais cliquer dessus ne fait rien. C'est maintenant à vous de traiter avec l'affichage et la navigation des sous-écrans. Ennuyeux.

il y a une approche (décrite ici ), qui ajoute un PreferenceFragmentCompat.OnPreferenceStartScreenCallback à votre PreferenceFragmentCompat . Bien que cette approche soit rapidement mise en œuvre, elle ne fait que remplacer le contenu du fragment de préférence existant. L'inconvénient est qu'il n'y a pas de navigation arrière, vous êtes toujours "au sommet", ce qui n'est pas très intuitif pour l'utilisateur.

dans une autre approche (décrite ici ), vous aurez également à gérer la pile arrière afin de réaliser la navigation arrière comme prévu. Cela utilise preferenceScreen.getKey() comme racine pour chaque fragment nouvellement créé/affiché.

en faisant cela, vous pourriez aussi trébucher sur le PreferenceFragments étant transparent par défaut et s'additionnant étrangement l'un sur l'autre. Les gens ont tendance à remplacer PreferenceFragmentCompat.onViewCreated() pour ajouter quelque chose comme

// Set the default white background in the view so as to avoid transparency
view.setBackgroundColor(ContextCompat.getColor(getContext(), R.color.background_material_light));

référence de dialogue personnalisé: faire ses propres préférences est également passé de trivial à ennuyeux. DialogPreference a maintenant tout ce qui concerne le dialogue réel, supprimé. Ce morceau vit maintenant dans PreferenceDialogFragmentCompat . Donc vous devrez sous-classer les deux, puis gérer la création du dialogue et l'afficher vous-même (expliqué ici ).

en regardant la source de PreferenceFragmentCompat.onDisplayPreferenceDialog() montre qu'il sait comment pour traiter exactement 2 préférences de dialogue( EditTextPreference , ListPreference ), tout le reste vous aurez à mettre en œuvre vous-même en utilisant OnPreferenceDisplayDialogCallback s... on se demande pourquoi il n'y a pas de fonctionnalité pour gérer la sous-classe DialogPreference !


voici un code qui implémente la plupart de ces solutions de rechange et les encadre dans un module lib:

https://github.com/mstummer/extended-preferences-compat.git

les principales intentions étaient:

  • supprimer le besoin d'étendre et de jouer avec Activity et PreferenceFragment dans chaque app/projets. preference.xml est à nouveau le seul fichier par projet à changer/maintenir.
  • Gérer et afficher PreferenceScreens (sous-écrans), comme prévu.
  • de l'Onu-split DialogPreference pour restaurer le natif de comportement.
  • sous-classe DialogPreference .

ne pensez pas qu'il est assez propre pour être utilisé simplement hors de la boîte, mais il pourrait vous donner quelques conseils quand traiter des questions similaires. Faites un tour et dites-moi si vous avez des suggestions.

51
répondu maxdownunder 2017-05-23 11:46:52

j'ai une solution alternative à ça, sur laquelle j'aimerais avoir un feedback.

j'ai fait une mise en page personnalisée pour mon fragment préféré, avec un bouton" Back " dans le coin supérieur gauche.

tout D'abord, dans le "uncreatepreference" j'emmagasine la racine PreferenceScreen:

root = this.getPreferenceScreen();

ensuite, j'ajoute le OnPreferenceStartScreenCallback comme décrit ci-dessus et dans d'autres threads pour faire passer le fragment à subscreen, mais dans mon "onPreferenceStartScreen" j'ai aussi placé le bouton arrière pour visible comme ceci:

    public boolean onPreferenceStartScreen(PreferenceFragmentCompat preferenceFragmentCompat, PreferenceScreen preferenceScreen) {
        preferenceFragmentCompat.setPreferenceScreen(preferenceScreen);
        backButton.setVisibility(View.VISIBLE);
        return true;
}

enfin, le clickhandler de backButton:

    setPreferenceScreen(root);
    back.setVisibility(View.GONE);

Cela semble bien fonctionner pour moi. Évidemment la pile arrière ne fonctionnera pas, mais je peux vivre avec cela puisqu'il y a un bouton arrière.

pas parfait, mais vu L'API épouvantable, je pense que je suis content.

j'aimerais entendre si quelqu'un pense qu'il y a des problèmes avec cette approche.

0
répondu Mathias 2017-11-02 09:16:15