web-dev-qa-db-ja.com

AppCompatでのsupport.v7.preferenceの使用方法と潜在的な欠点

Support.v7.preferenceを使用して、AppCompatアプリの設定を実装しようとしました。 support.v7.preferenceにはネイティブの設定といくつかの重要な違いがあるので、それをいじくるのに数日かかりました。他の人が同じ苦痛を経験する必要がないように、私の発見を共有したいと思いました。


だから...質問:

(PreferenceFragmentとAppCompatAcitivityに互換性がない)AppCompatアプリの設定を最適に実装するにはどうすればよいですか?

関連する質問をいくつか示します。

公式ドキュメントはこちら:

17
maxdownunder

解決策1:ネイティブPreferenceFragmentAppCompatActivity

AndroidStudioで、File> New Project> ...> SettingsActivityを選択します。このテンプレートでは、_support.v4.Fragment_または_support.v7.PreferenceFragmentCompat_と同様に、ネイティブPreferenceFragmentを改造してAppCompatActivityを操作する回避策を使用します。

  • プロ:AppCompatアプリ内でネイティブの設定機能を使用できるようになりました。これは、ASテンプレートを使用する場合の迅速なアプローチであり、既存の設定ドキュメントとワークフローをそのまま使用できます。
  • 欠点:後付けは直感的でもクリーンでもありません。また、可能であればサポートライブラリを使用することをお勧めしますので、このアプローチがどれほど将来性があるかはわかりません。

ソリューション2:_support.v7.preference.PreferenceFragmentCompat_ with AppCompatActivity

  • プロ:互換性を最大化
  • 欠点:橋渡しすべきギャップがたくさんあります。また、これは、既存の設定拡張機能ライブラリ(たとえば、ColorPickerまたはFontPreferences)では機能しない可能性があります。

ソリューション1を使用しないことを選択した場合(2つのうちどちらがより将来性があるかはまだわかりません)、_support.v7.preference_を使用するときにいくつかの欠点があります。

Solution 2を使用する際の重要な欠点を以下に示します。

依存関係:

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

テーマ:preferenceThemeをstyles.xmlで定義する必要がありますそれ以外の場合、アプリを実行すると例外が発生します。

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

これを7 +/14 +/21 +の異なるスタイルに分割したいかもしれません。この記事の執筆時点では、多くの人がこれがバグだと不満を持っています。利用可能な非常に包括的な答えがあります ここ

動作の変更:ネイティブ設定の使用は非常に簡単です:_preferences.xml_を定義/維持し、addPreferencesFromResource(R.xml.preferences)PreferenceFragment内。カスタム設定はDialogPreferenceをサブクラス化することで簡単に実行でき、_preferences.xml_...内で参照するだけで動作します。

残念ながら、_support.v7.preference_はFragmentの処理に関連するすべてのものを取り除いており、組み込み機能の多くを失っています。 XMLを保守するだけでなく、多くのことをサブクラス化してオーバーライドする必要がありますが、そのすべてが残念ながら文書化されていません。

PreferenceScreens:PreferenceScreensは、フレームワークによって管理されなくなりました。 _preference.xml_でPreferenceScreenを定義すると( docs で説明)、エントリは表示されますが、クリックしても何も起こりません。サブ画面の表示とナビゲートは、あなた次第です。退屈な。

PreferenceFragmentCompatに_PreferenceFragmentCompat.OnPreferenceStartScreenCallback_を追加する方法が1つあります(説明は here )。このアプローチはすぐに実装されますが、既存の設定フラグメントのコンテンツを交換するだけです。欠点は、バックナビゲーションがなく、常に「上部」にいるため、ユーザーにとって直感的ではないことです。

別のアプローチ(説明 here )では、期待どおりに戻るナビゲーションを実現するために、バックスタックも管理する必要があります。これは、新しく作成/表示された各フラグメントのルートとしてpreferenceScreen.getKey()を使用します。

その場合、デフォルトでPreferenceFragmentsが透明になり、奇妙に加算されることも考えられます。人々はPreferenceFragmentCompat.onViewCreated()をオーバーライドして次のようなものを追加する傾向があります

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

カスタムDialogPreference:独自の設定を作成することも、ささいなことから退屈なことへと進んでいます。 DialogPreferenceには、実際のダイアログを処理するものがすべて含まれているため、削除されました。そのビットは現在PreferenceDialogFragmentCompatにあります。したがって、両方をサブクラス化し、ダイアログを作成して自分で表示する必要があります( ここ で説明)。

PreferenceFragmentCompat.onDisplayPreferenceDialog()のソースを見ると、正確に2つのダイアログ設定(EditTextPreferenceListPreference)を処理する方法がわかっていることがわかります。 OnPreferenceDisplayDialogCallbacks ...不思議なことに、なぜDialogPreferenceのサブクラスを処理する機能がないのでしょうか。


以下は、これらの回避策のほとんどを実装し、libモジュールにボックス化するコードです。

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

主な意図は:

  • 各アプリ/プロジェクトでActivityPreferenceFragmentを拡張して操作する必要をなくします。 _preference.xml_が、変更/維持するプロジェクトごとの唯一のファイルになりました。
  • 期待どおりにPreferenceScreens(サブ画面)を処理して表示します。
  • DialogPreferenceの分割を解除して、ネイティブの動作を復元します。
  • DialogPreferenceのサブクラスを処理して表示します。

箱から出しただけで使用できるほどクリーンだとは思わないでください。同様の問題に対処するときにヒントが得られる場合があります。試してみて、何か提案があれば教えてください。

52
maxdownunder

私はこれに対する代替の解決策を持っています。フィードバックが欲しいです。

左上隅に「戻る」ボタンを使用して、preferencefragmentのカスタムレイアウトを作成しました。

まず、 "onCreatePreference"にルートPreferenceScreenを格納します。

root = this.getPreferenceScreen();

次に、上記のようにOnPreferenceStartScreenCallbackを追加し、他のスレッドでフラグメントをサブ画面に移動させますが、「onPreferenceStartScreen」で、戻るボタンも次のように表示されるように設定します。

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

最後に、backButtonクリックハンドラー:

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

これは私にとってはうまくいくようです。明らかに、バックスタックは機能しませんが、[戻る]ボタンがあるので、それでも問題ありません。

完璧ではありませんが、最悪のAPIを考えると私は満足していると思います。

誰かがこのアプローチに問題があると思ったら聞いてみたいです。

0
Mathias