webentwicklung-frage-antwort-db.com.de

So verwenden Sie support.v7.preference mit AppCompat und möglichen Nachteilen

Ich habe versucht, die Einstellungen für eine AppCompat-App mithilfe von support.v7.preference zu implementieren. Ich habe ein paar Tage gebraucht, um durchzugehen, da support.v7.preference einige signifikante Unterschiede zu den ursprünglichen Präferenzen hat ... was nicht allzu schlimm ist, wenn man es weiß, aber leider gibt es wenig Dokumentation. Ich dachte, ich würde meine Erkenntnisse teilen, damit andere nicht denselben Schmerz durchmachen müssen.


Also ... Frage:

Wie lassen sich Voreinstellungen für AppCompat-Apps am besten implementieren (wobei PreferenceFragment und AppCompatAcitivity nicht kompatibel sind)?

Hier sind einige verwandte Fragen:

Offizielle Dokumente hier:

16
maxdownunder

Lösung 1: Native PreferenceFragment mit AppCompatActivity

Wählen Sie in AndroidStudio Datei> Neues Projekt> ...> EinstellungenAktivität. Diese Vorlage verwendet eine Problemumgehung, die die native PreferenceFragment für die Zusammenarbeit mit AppCompatActivity nachrüstet, ähnlich wie support.v4.Fragment oder support.v7.PreferenceFragmentCompat.

  • Pro: Sie können jetzt die native Preference-Funktion in einer AppCompat-App verwenden. Dies ist ein schneller Ansatz, wenn Sie die AS-Vorlage verwenden, und Sie können sich an die vorhandenen Einstellungsdokumente und Workflows halten.
  • Con: Die Nachrüstung ist nicht sehr intuitiv oder sauber. Da es normalerweise ratsam ist, Unterstützungsbibliotheken zu verwenden, sofern verfügbar, bin ich nicht sicher, wie zukunftssicher dieser Ansatz ist.

Lösung 2: support.v7.preference.PreferenceFragmentCompat mit AppCompatActivity

  • Pro: maximiert die Kompatibilität
  • Con: viele Lücken zu überbrücken. Dies funktioniert möglicherweise auch nicht mit einer der vorhandenen prefs-extensions-libs (zB ColorPicker oder FontPreferences).

Wenn Sie die Lösung 1 nicht verwenden möchten (ich bin immer noch nicht sicher, welche der beiden zukunftssicherer ist), gibt es bei der Verwendung von support.v7.preference einige Nachteile. 

Wichtige Nachteile der Verwendung von Lösung 2 sind unten aufgeführt.

Abhängigkeiten:

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'
}

Theme: Sie müssen in Ihrer styles.xml eine preferenceTheme definieren, andernfalls führt die Ausführung Ihrer App zu einer Ausnahme.

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

Sie können dies für 7 +/14 +/21 + in verschiedene Stile unterteilen. Viele Leute beklagen sich darüber, dass dies zum Zeitpunkt dieses Schreibens fehlerhaft war. Es gibt eine sehr umfassende Antwort hier .

Verhaltensänderungen: Die Verwendung der nativen Voreinstellungen ist äußerst unkompliziert: Sie müssen lediglich Ihren preferences.xml definieren/verwalten und addPreferencesFromResource(R.xml.preferences) in Ihrer PreferenceFragment verwenden. Benutzerdefinierte Voreinstellungen lassen sich leicht durch Unterklassifizierung von DialogPreference vornehmen und werden dann einfach innerhalb von preferences.xml... bam referenziert.

Leider hatte support.v7.preference alles, was mit dem Umgang mit Fragment zu tun hatte, was dazu führte, dass viele seiner integrierten Funktionen verloren gingen. Anstatt nur ein XML zu verwalten, müssen Sie jetzt eine ganze Menge von Unterklassen überschreiben, die leider nicht dokumentiert sind.

PreferenceScreens:PreferenceScreens werden nicht mehr vom Framework verwaltet. Wenn Sie eine PreferenceScreen in Ihrem preference.xml definieren (wie in docs beschrieben), wird der Eintrag angezeigt. Wenn Sie darauf klicken, wird jedoch nichts angezeigt. Nun liegt es an Ihnen, sich mit dem Anzeigen und Navigieren von Unterbildschirmen zu beschäftigen. Langweilig.

Es gibt einen Ansatz (beschrieben hier ), der Ihrer PreferenceFragmentCompat einen PreferenceFragmentCompat.OnPreferenceStartScreenCallback hinzufügt. Während dieser Ansatz schnell implementiert wird, tauscht er einfach den Inhalt des vorhandenen Präferenzfragments aus. Der Nachteil ist: Es gibt keine Rückwärtsnavigation, Sie sind immer "oben", was für den Benutzer nicht sehr intuitiv ist.

Bei einem anderen Ansatz (beschrieben hier ) müssen Sie auch den Back-Stack verwalten, um die erwartete Rückwärtsnavigation zu erzielen. Dies verwendet preferenceScreen.getKey() als Root für jedes neu erstellte/angezeigte Fragment.

Wenn Sie dies tun, stolpern Sie möglicherweise auch darüber, dass die Variable PreferenceFragments standardmäßig transparent ist und sich ungerade aufaddiert. Menschen neigen dazu, PreferenceFragmentCompat.onViewCreated() zu überschreiben, um so etwas hinzuzufügen

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

Custom DialogPreference: Das Erstellen eigener Präferenzen wurde auch von trivial zu langweilig. DialogPreference hat jetzt alles, was sich auf den eigentlichen Dialog bezieht, entfernt. Dieses Bit lebt jetzt in PreferenceDialogFragmentCompat. Sie müssen also beide Klassen untergliedern und sich dann damit befassen, den Dialog zu erstellen und ihn selbst anzuzeigen (erklärt hier ).

Ein Blick auf die Quelle von PreferenceFragmentCompat.onDisplayPreferenceDialog() zeigt, dass er mit genau 2 Dialogeinstellungen (EditTextPreference, ListPreference) umgehen kann. Alles andere müssen Sie selbst mit OnPreferenceDisplayDialogCallbacks implementieren ... man fragt sich, warum es keine Funktionalität gibt, Klasse von DialogPreference!


Hier ist ein Code, der die meisten dieser Problemumgehungen implementiert und sie in einem lib-Modul einfügt:

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

Hauptabsichten waren:

  • Entfernen Sie die Notwendigkeit, mit Activity und PreferenceFragment in jeder App/in jedem Projekt zu erweitern und zu arbeiten. preference.xml ist jetzt wieder die einzige pro-Projekt-Datei, die geändert/verwaltet werden soll.
  • Behandeln und zeigen Sie PreferenceScreens (Unterbildschirme) wie erwartet an.
  • Teilen Sie DialogPreference auf, um das native Verhalten wiederherzustellen.
  • Behandeln Sie eine beliebige Unterklasse von DialogPreference und zeigen Sie sie an.

Denken Sie nicht, dass es sauber genug ist, um es einfach sofort zu verwenden, aber es könnte Ihnen einige Hinweise geben, wenn Sie ähnliche Probleme behandeln. Machen Sie eine Runde und lassen Sie mich wissen, ob Sie Vorschläge haben.

53
maxdownunder

Ich habe dazu eine alternative Lösung, auf die ich mich sehr freuen würde.

Ich habe ein benutzerdefiniertes Layout für mein Vorliebenfragment erstellt, mit einem "Zurück" -Button in der oberen linken Ecke. 

Zuerst speichere ich im "onCreatePreference" den Stamm PreferenceScreen ab:

root = this.getPreferenceScreen();

Dann füge ich OnPreferenceStartScreenCallback wie oben beschrieben und in anderen Threads hinzu, damit das Fragment auf den Subscreen wechselt, aber in meinem "onPreferenceStartScreen" setze ich auch die Zurück-Schaltfläche auf "sichtbar":

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

Zum Schluss noch der backButton-Clickhandler:

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

Das scheint gut für mich zu funktionieren. Offensichtlich funktioniert der Backstack nicht, aber ich kann damit leben, da es einen Back-Button gibt.

Nicht perfekt, aber angesichts der abgründigen API glaube ich, dass ich glücklich bin.

Ich würde gerne hören, wenn jemand der Meinung ist, dass es Probleme mit diesem Ansatz gibt.

0
Mathias