LoginSignup
4
5

More than 3 years have passed since last update.

AndroidXで使えるPreferenceActivityを作った話

Last updated at Posted at 2019-05-05

PreferenceActivityって便利でしたよね

XMLで設定項目を定義することで簡単に設定画面を作ることができます。API Level 15では直接設定画面を作ることがdeprecatedになった後もPreferenceFragmentと組み合わせて使われていました。しかし、ついにAPI Level 29にてdeprecatedになってしまいました。:cry:
FragmentのほうはPreferenceFragmentCompatがAndroidXで提供されていますが、PreferenceActivityの代替手段は提供されていません。

無いのなら作ってしまえばいいということで(少し前に)作りました。PreferenceActivityCompatです。

jCenterに登録していますので以下だけでつかえます。

implementation 'net.mm2d:preference:0.1.2'

Android 4.x上でもマテリアルデザインが適用されます。

PreferenceActivity PreferenceActivityCompat
4N4.png 7C4.png

元々のPreferenceActivtyの全機能をサポートしているわけではなく、preference-headersを定義してPreferenceFragmentを呼び出していたところを、PreferenceFragmentCompatを呼び出せるようにしたものです。
また、実際の設定項目などの部分はPreferenceFragmentCompatにお任せで、PreferenceFragmentCompat自体の改善を行うものではありません。

使い方

少し前まで、Android StudioでSettings Activityを作成すると勝手に作られていたAppCompatPreferenceActivityを使った設定画面を拙作のPreferenceActivityCompatに置き換えるという形で説明していきます。(ほぼReadmeの翻訳)

1. preferenceThemePreferenceActivityのテーマに追加

    <style name="AppTheme" parent="Theme.AppCompat.Light.DarkActionBar">
        <item name="colorPrimary">@color/colorPrimary</item>
        <item name="colorPrimaryDark">@color/colorPrimaryDark</item>
        <item name="colorAccent">@color/colorAccent</item>

+        <item name="preferenceTheme">@style/PreferenceCompatTheme</item>
    </style>

2. SettingsActivityの親クラスを書き換え

- public class SettingsActivity extends AppCompatPreferenceActivity {
+ public class SettingsActivity extends PreferenceActivityCompat {

isValidFragmentprotectedで定義されていると思いますので、publicに書き換えます。

    @Override
-     protected boolean isValidFragment(final String fragmentName) {
+     public boolean isValidFragment(final String fragmentName) {

onMenuItemSelectedをOverrideしている場合は、onOptionsItemSelectedに書き換えます。

    @Override
-    public boolean onMenuItemSelected(int featureId, MenuItem item) {
+    public boolean onOptionsItemSelected(final MenuItem item) {
        final int id = item.getItemId();
        if (id == android.R.id.home) {
-            if (!super.onMenuItemSelected(featureId, item)) {
+            if (!super.onOptionsItemSelected(item)) {
                NavUtils.navigateUpFromSameTask(this);
            }
            return true;
        }
-        return super.onMenuItemSelected(featureId, item);
+        return super.onOptionsItemSelected(item);
    }

3. PreferenceFragmentPreferenceFragmentCompatに書き換え

onCreateで書いていた処理はonCreatePreferencesに書き換えます。

-     public static class GeneralPreferenceFragment extends PreferenceFragment {
+     public static class GeneralPreferenceFragment extends PreferenceFragmentCompat {
        @Override
-         public void onCreate(final Bundle savedInstanceState) {
-             super.onCreate(savedInstanceState);
+         public void onCreatePreferences(final Bundle savedInstanceState,final String rootKey) {
            addPreferencesFromResource(R.xml.native_pref_general);
        }

4. インポートの書き換え

android.preference.PreferenceActivity.Headernet.mm2d.preference.Headerに置き換えます。

- import android.preference.PreferenceActivity.Header;
+ import net.mm2d.preference.Header;

android.preferenceandroidx.preferenceに書き換えます。

- import android.preference.ListPreference;
- import android.preference.Preference;
- import android.preference.Preference.OnPreferenceChangeListener;
- import android.preference.PreferenceFragment;
- import android.preference.PreferenceManager;
+ import androidx.preference.ListPreference;
+ import androidx.preference.Preference;
+ import androidx.preference.Preference.OnPreferenceChangeListener;
+ import androidx.preference.PreferenceFragmentCompat;
+ import androidx.preference.PreferenceManager;

5. xmlのnamespaceの書き換え

preference-headersを定義しているxmlのnamespaceをandroidからappに書き換えます。

<preference-headers
-     xmlns:android="http://schemas.android.com/apk/res/android">
+     xmlns:app="http://schemas.android.com/apk/res-auto">
    <header
-         android:fragment="net.mm2d.preference.sample.SettingsActivity$GeneralPreferenceFragment"
-         android:icon="@drawable/ic_info_black_24dp"
-         android:title="@string/pref_header_general"
+         app:fragment="net.mm2d.preference.sample.SettingsActivity$GeneralPreferenceFragment"
+         app:icon="@drawable/ic_info_black_24dp"
+         app:title="@string/pref_header_general"
        />

6. SwtichPreferenceSwitchPreferenceCompatに書き換え(必要なら)

PreferenceFragmentCompatでは置き換え可能というだけなので、PreferenceActivityCompatは関係無いです。

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">
-     <SwitchPreference
+     <!--suppress AndroidElementNotAllowed -->
+     <SwitchPreferenceCompat
        android:defaultValue="true"
        android:key="example_switch"
        android:summary="@string/pref_description_social_recommendations"
        android:title="@string/pref_title_social_recommendations"
        />

なぜ置き換えるか、というと、Android 4.4 以前ではSwitchPreferenceのままではマテリアルデザインにならないからです。

SwitchPreference SwitchPreferenceCompat
switch-preference.png switch-preference-compat.png

ただ、警告が出ちゃうのが美しくないです:sweat:

7. アイコン用のmarginが不要ならapp:iconSpaceReserved="false"を追加

こちらもPreferenceFragmentCompatを使う上での話でPreferenceActivityCompatは関係無いです。

    <Preference
        android:title="@string/pref_title_system_sync_settings"
+         app:iconSpaceReserved="false"
        >

デフォルトでアイコン分の余白が出るようになっちゃったんですよね。app:iconSpaceReserved="false"で詰めることができます。

default app:iconSpaceReserved="false"
icon-space-reserved-true.png icon-space-reserved-false.png

まとめ

かつてのPreferenceActivityを延命させられるかもしれないライブラリを作ってみたというご紹介でした。

4
5
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
4
5