PreferenceFragmentCompat の PreferenceCategory の下側マージンが太すぎる件
android.preference.PreferenceFragment
は Android P から非推奨になります。android.support.v7.preference.PreferenceFragmentCompat
を使ってください。
This class was deprecated in API level P.
Use PreferenceFragmentCompat
PreferenceFragment | Android Developers
PreferenceFragmentCompat でググると面倒くさそうな記事がいくつも出てくるから嫌なんだけど…。
仕方ないので使ってみることにします。
PreferenceFragmentCompat の導入
モジュールの build.gradle に依存関係を追加。
dependencies { //... implementation 'com.android.support:preference-v7:27.1.0' }
適当な PreferenceScreen を作る。(preferences.xml)
<?xml version="1.0" encoding="utf-8"?> <PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"> <PreferenceCategory android:title="設定カテゴリ 1"> <SwitchPreference android:title="スイッチ" /> <CheckBoxPreference android:title="チェックボックス" /> </PreferenceCategory> <PreferenceCategory android:title="設定カテゴリ 2"> <Preference android:title="何か 1" /> <Preference android:title="何か 2" /> </PreferenceCategory> </PreferenceScreen>
PreferenceFragmentCompat
を継承したクラスを作る。
public class MyPreferenceFragmentCompat extends PreferenceFragmentCompat { @Override public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); } }
Activity
で読み込む。
public class MainActivity extends AppCompatActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); getSupportFragmentManager().beginTransaction() .replace(android.R.id.content, new MyPreferenceFragmentCompat()) .commit(); } }
とりあえず実行してみる。
しかしアプリはすぐに落ちて、Logcat を見ると preferenceTheme を指定しろと言われている。
java.lang.IllegalStateException: Must specify preferenceTheme in theme
styles.xml を編集する。@style/PreferenceThemeOverlay.v14.Material を指定するとマテリアルデザインになるらしい。
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- ... --> <!-- PreferenceFragmentCompat のための設定 --> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> </style> </resources>
再び実行。
今度は落ちなかったけど、よく見るとなんか変。
比較用に android.preference.PreferenceFragment
を使った物も用意した。左側が PreferenceFragmentCompat
で、右側が android.preference.PreferenceFragment
。
PreferenceCategory
に余計なマージンが付いているのが分かる。
原因は preferenceTheme に指定した @style/PreferenceThemeOverlay.v14.Material だと思うので、それを調べてみる。
<style name="PreferenceThemeOverlay.v14.Material"> <!-- ... --> <item name="preferenceCategoryStyle">@style/Preference.Category.Material</item> <!-- ... --> </style>
<style name="Preference.Category.Material"> <item name="android:layout">@layout/preference_category_material</item> </style>
<?xml version="1.0" encoding="utf-8"?> <TextView xmlns:android="http://schemas.android.com/apk/res/android" android:id="@android:id/title" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_marginBottom="16dip" android:textAppearance="@style/Preference_TextAppearanceMaterialBody2" android:textColor="@color/preference_fallback_accent_color" android:paddingLeft="?android:attr/listPreferredItemPaddingLeft" android:paddingRight="?android:attr/listPreferredItemPaddingRight" android:paddingTop="16dip" />
android:layout_marginBottom の指定がある。
android:layout_marginBottom="16dip"
恐らく原因はこれ。原因が分かったので自力で直せるだろうが、楽チンな方法がないか調べてみる。
同じような悩みを抱えた人がいた。
Android-Support-Preference-V7-Fix というライブラリに挙げられた Issue で、返信を見ると解決済みらしい。
Android-Support-Preference-V7-Fix の導入と置き換え
とりあえず導入してみる。
com.android.support:preference-v7 の代わりに com.takisoft.fix:preference-v7 を追加する。
dependencies { //... //implementation 'com.android.support:preference-v7:27.1.0' implementation 'com.takisoft.fix:preference-v7:27.1.0.0' }
Java コードの import を書き換えて、オーバーライドするメソッドも変更する。
//... import com.takisoft.fix.support.v7.preference.PreferenceFragmentCompat; public class MyPreferenceFragmentCompat extends PreferenceFragmentCompat { // @Override // public void onCreatePreferences(Bundle savedInstanceState, String rootKey) { // addPreferencesFromResource(R.xml.preferences); // } @Override public void onCreatePreferencesFix(@Nullable Bundle savedInstanceState, String rootKey) { addPreferencesFromResource(R.xml.preferences); } }
preferenceCategory_marginBottom に 0dp を指定する。
<resources> <!-- Base application theme. --> <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar"> <!-- ... --> <!-- PreferenceFragmentCompat のための設定 --> <item name="preferenceTheme">@style/PreferenceThemeOverlay.v14.Material</item> <item name="preferenceCategory_marginBottom">0dp</item> </style> </resources>
これで実行してみる。左側が PreferenceFragmentCompat
で、右側が android.preference.PreferenceFragment
。
微妙にずれている。0dp は小さすぎたようなので、1dp に変えてみる。
<item name="preferenceCategory_marginBottom">1dp</item>
今度はぴったりになった。マージンの色が違うのが気になるけど、まあいいか…。