いまさらだけどPreferenceFragmentCompatでインナーPreferenceScreenを使うと自動で画面遷移しない件、ぐるぐる先生に聞くとPreferenceFragmentCompatを継承してゴニョゴニョしてさらにActivityにもOnPreferenceStartFragmentCallbackインターフェースやらOnPreferenceStartScreenCallbackインターフェースやらを実装せよとおっしゃられる、めんどくさいんじゃぁー?そもそも処理があっちこっちに散らかっていやなんじゃぁー(T T)
でもPreferences画面がxmlだけで完結している前提ならもう少し簡単な方法がありました\(^o^)/
しかもPreferenceFragmentCompatを継承して#onNavigateToScreenをoverrideするだけ(@@)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 |
public class MyPrefFragment extends PreferenceFragmentCompat { ... @Override public void onCreatePreferences(final Bundle savedInstanceState, final String rootKey) { ... // XMLリソースIDも固定値の代わりにBundleに入れて // Fragment#setArgumentsで引き渡すと汎用に使えるのじゃ setPreferencesFromResource(R.xml.preferences, rootKey); ... } ... @Override public void onNavigateToScreen(final PreferenceScreen preferenceScreen) { super.onNavigateToScreen(preferenceScreen); if (DEBUG) Log.v(TAG, "onNavigateToScreen:"); try { final Fragment fragment = getClass().newInstance(); final Bundle args = new Bundle(); args.putString(PreferenceFragmentCompat.ARG_PREFERENCE_ROOT, preferenceScreen.getKey()); fragment.setArguments(args); getFragmentManager().beginTransaction() .replace(R.id.container, fragment) .setTransition(FragmentTransaction.TRANSIT_FRAGMENT_OPEN) .addToBackStack(preferenceScreen.getKey()) .commit(); } catch (final java.lang.InstantiationException e) { Log.w(TAG, e); } catch (final IllegalAccessException e) { Log.w(TAG, e); } } ... } |
自分自身以外のFragmentクラスを使いたければフラグメントを生成している部分を書き換えます。前のコードスニペットでは次のようにして自分自身と同じFramgnetを生成しています。
1 |
final Fragment fragment = getClass().newInstance(); |
例えば次のようにすると好きなFragmentを生成して画面遷移できるのですじゃ〜
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
@NonNull protected Class< ? extends Fragment> getPreferenceClass( final PreferenceScreen preferenceScreen) { // 今は自分自身のClassを返しているけどPreferenceScreenの内容(キー名とか)に // 応じてサポートライブラリ版のFragmentを継承したクラスを返せばよいのじゃ return this.getClass(); } @Override public void onNavigateToScreen(final PreferenceScreen preferenceScreen) { ... final Fragment fragment = getPreferenceClass(preferenceScreen).newInstance(); ... } |
あとreplaceのときのコンテナidは上のスニペットだとR.id.containerに固定しているけど、もし変えたければそれもBundleに突っ込んでsetArgumentsで引き渡せばよいのじゃ、簡単なのじゃ
あっ、でも1つ制限が。xmlのPreferenceScreenにもダミーでユニークなキーを設定しておく必要があります。でないとキーがnullになってしまうので、トップレベルのPreferenceScreenしか表示できません。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
< ?xml version="1.0" encoding="utf-8"?> <preferencescreen xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" > ... <preferencecategory android:title="@string/pref_title" > ... <preferencescreen android:key="preference_screen_1" android:title="@string/pref_title_1"> <!-- ListPreferenceとかSwitchPreferenceCompatで定義 --> ... </preferencescreen> <preferencescreen android:key="preference_screen_notice" android:title="@string/notice_title"> <preferencecategory android:layout="@layout/notice_screen"> </preferencecategory> </preferencescreen> </preferencecategory> ... </preferencescreen> |
1つ目のインナーPreferenceScreen(preference_screen_1)は普通にxmlでPrefarenceを定義したもの、2つ目(preference_screen_notice)は静的なテキスト/画像等を表示するだけのレイアウトリソースを参照して表示するインナーPreferenceScreenなのですじゃ。
この方法の利点は、
- コードが散らからない(PreferenceFragmentCompat#onNavigateToScreenをoverrideするだけ)
- サポートライブラリ版ではない通常のPreferenceFragmentとほぼ同じxmlが使える。
SwitchPreferenceはSwitchPreferenceCompatに置き換えないといけないとかはあるけど - バックキーの処理を自動でしてくれる(通常のPrefereceFragmentと同じ使い勝手)
ところでListPreferenceはサポートライブラリ版でもフレームワーク版でも同じ名前なのにSwitchPreferenceはSwitchPreferenceCompatに置き換えないといけないのはなんでなんじゃ?
ということで短いけど、今日はさよならなのじゃぁー、金曜日は温泉に行く日なのじゃぁー♨