LoginSignup
2
0

More than 1 year has passed since last update.

Androidで設定画面を作ってみる

Last updated at Posted at 2022-11-27

Andoroidでシステム設定のような設定画面を作ってみる

Androidのアプリで設定画面を持っているものが有ります。AndroidX Preference Libraryを使って、Andoroid OSのシステム設定のような設定画面をアプリ内に作ってみましょう。

参考URL
本家Android develpers 設定

どんな設定画面を作るか?

とりあえず、こんな設定画面を作ってみましょう。

設定値として色々な型が可能ですが、

  • 文字列(何でも入力可)
  • 文字列(数値のみ)
  • リスト形式
  • チェックボックス形式
  • スィッチ形式(ON/OFF、YES/NO、True/False)

を作って見ましょう。
「文字列(何でも入力可)」と「文字列(数値のみ)」AndroidX Preference Libraryの型としてはEditTextPreferenceで一緒ですが、入力の時のキーパットが違います。
「文字列(何でも入力可)」は何でも入力できるキーパッドですが、

「文字列(数値のみ)」の場合は数値しか入力できないキーパッドになります。ここで数値しか入らないことを保証しています。

リスト形式の場合は、どれかひとつを選ぶダイアログが表示されます

チェックボックス形式は上の図の通りですね。複数選択可能です。
スィッチ形式はONかOFFかのどちらかが選択可能です。

build.gradleに依存関係の追加

build.gradleに依存性を追加します。

build.gradle
dependencies {
    (中略)
    implementation 'androidx.preference:preference-ktx:1.2.0'
    implementation 'androidx.preference:preference:1.2.0'
    implementation 'androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1'
}

ここで、注意しないといけないのは、androidx.lifecycle:lifecycle-viewmodel-ktx:2.5.1を追加しないと、ビルド時に意味不明のエラーになります。

Duplicate class androidx.lifecycle.ViewModelLazy found in modules lifecycle-viewmodel-2.5.1-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.1) and lifecycle-viewmodel-ktx-2.3.1-runtime (androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1)
Duplicate class androidx.lifecycle.ViewTreeViewModelKt found in modules lifecycle-viewmodel-2.5.1-runtime (androidx.lifecycle:lifecycle-viewmodel:2.5.1) and lifecycle-viewmodel-ktx-2.3.1-runtime (androidx.lifecycle:lifecycle-viewmodel-ktx:2.3.1)

Go to the documentation to learn how to Fix dependency resolution errors.

色々ネットを検索して、上記の解決方法を見つけたのですが、正直、なんでこのビルドエラーになって、なんでこれで解消するのか、自分の力量では説明できません。(lifecycle関係なんか使ってないのに・・・androidx.preference:preferenceから芋づる式で入ってしまうんだろうか?)

設定画面のFragmentウィザードで雛形を一気に作る

AndroidStudioに設定画面のウィザートが用意されていてある程度の雛形がすぐ作成できます。
javaのフォルダを右クリック → 新規 → Fragment → Setting Fragment

設定画面のFragment作成のダイアログが表示されます。ここはデフォルトのままFragment名はSettingFragmentのままでいきます。
Screenshot_20221126_205832.png
完了をクリックすると、こんな感じで雛形ができあがっています。
Screenshot_20221126_212351.png

  • SettingFragment(フラグメント)
  • arrays.xml(リスト形式で使う)
  • root_preferences.xml(設定画面のデザインレイアウト)

がウィザードで作成されれているのがわかります。
root_preferences.xmlを開くとデザイナのviewが上がってきます。こんな感じで雛形ができています。
Screenshot_20221126_210247.png
左上の「Palette」に設定画面に使用可能なパーツが出ています。ここから、その下の「Component Tree」にドラッグ&ドロップして設定画面にパーツを追加していきます。パーツとして何が使用可能か、一通り見てみましょう。

「Commons」の下
Screenshot_20221126_210313.png
「Preferences」の下
Screenshot_20221126_210329.png
「Groups」の下
Screenshot_20221126_210340.png

設定画面のデザイン

「Component Tree」の構造を見ると

  • PreferenceScreen
    • PreferenceCategory
      • 設定画面のパーツ
      • ・・・
    • PreferenceCategory
      • 設定画面のパーツ
      • ・・・

といった階層構造になっているのがわかると思います。今回、上の設定画面を作るのに必要な設定画面のパーツは

設定画面のパーツ class
文字列(何でも入力可) EditTextPreference
文字列(数値のみ) EditTextPreference
リスト形式 ListPreference
チェックボックス形式 CheckBoxPreference
スィッチ形式 SwitchPreference

となります。では実際に雛形を参考にしながら設定画面のパーツを配置していきます。「ComponetTree」はこのようになります。
Screenshot_20221127_113704.png
実は、チェックボックス形式(CheckBoxPreference)は設定値としては1個毎にバラバラになるので、上の例のように3つの中から任意の個数選択可能だと3つ配置することになります。
リスト形式のリストの中身ですが、雛形で作られたarrys.xmlを参照しています。
Screenshot_20221127_114324.png
arrays.xmlはこうなっています。

arrays.xml
<resources>
    <!-- Reply Preference -->
    <string-array name="list_entries">
        <item>設定1</item>
        <item>設定2</item>
        <item>設定3</item>
    </string-array>
    <string-array name="list_values">
        <item>1</item>
        <item>2</item>
        <item>3</item>
    </string-array>
</resources>

ListPreferenceのプロパティの「entries」が実際に設定画面で表示されるリストの内容、「entryValues」が選択された時に採用される値です。それがarrays.xmlとリンクしているのがわかるでしょうか。HTMLのSELECTタグみたいな仕組みになっています。

できあがったroot_preferences.xmlはこのようになります。

root_preferences.xml
<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:app="http://schemas.android.com/apk/res-auto">
    <PreferenceCategory app:title="@string/textCatTitle">
        <EditTextPreference
            app:key="textPreference"
            app:title="@string/textPrefTitle"
            app:useSimpleSummaryProvider="true" />
    </PreferenceCategory>
    <PreferenceCategory android:title="@string/numberCatTitle">
        <EditTextPreference
            android:defaultValue="0"
            android:key="numberPreference"
            android:selectAllOnFocus="true"
            android:singleLine="true"
            android:title="@string/numberPrefTitle"
            app:useSimpleSummaryProvider="true" />
    </PreferenceCategory>
    <PreferenceCategory app:title="@string/listCatTitle">
        <ListPreference
            app:entries="@array/list_entries"
            app:entryValues="@array/list_values"
            app:key="listPreference"
            app:title="@string/listPrefTitle"
            app:useSimpleSummaryProvider="true" />
    </PreferenceCategory>
    <PreferenceCategory android:title="@string/checkCatTitle">
        <CheckBoxPreference
            android:defaultValue="false"
            android:key="checkboxPreference1"
            android:title="@string/checkPrefTtile1" />
        <CheckBoxPreference
            android:defaultValue="false"
            android:key="checkboxPreference2"
            android:title="@string/checkPrefTtile2" />
        <CheckBoxPreference
            android:defaultValue="false"
            android:key="checkboxPreference3"
            android:title="@string/checkPrefTtile3" />
    </PreferenceCategory>
    <PreferenceCategory android:title="@string/switchCatTitle">
        <SwitchPreferenceCompat
            app:defaultValue="false"
            app:key="switchPreference"
            app:summaryOff="@string/summaryOff"
            app:summaryOn="@string/summaryOn"
            app:title="@string/switchPrefTitle" />
    </PreferenceCategory>
</PreferenceScreen>

SettingFragment.ktの修正

上でも説明しましたが、「文字列(何でも入力可)」、「文字列(数値のみ) 」は設定パーツ的にはEditTextPreferenceで同じです。ここで、「文字列(数値のみ) 」は数値のみ入力可能なキーパッドが表示されるように細工をします。

SettingFragment.kt
    override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey)
        //  入力を数値のみに限定する
        val numberPreference = findPreference<EditTextPreference>("numberPreference")
        numberPreference?.setOnBindEditTextListener { editText ->
            editText.inputType = InputType.TYPE_CLASS_NUMBER
        }
    }

onCreatePreferencesメソッドはウィザードの雛形ですでにできあがっているので、そこに追加します。

設定を表示する画面も作ってみる

設定を書き込んだだけじゃ、画面で確認する方法がないので、設定を表示する画面も作ってみます。少々、雑ですが、こんな画面を作ります。

アクションバーにアイコンを2つ配置して、スパナのアイコンをタップするとSettingFragmentの画面へ、Uターンのアイコンをタップするとこの表示画面へ、お互いに行き来できるようにしてみました。

DisplayFragment.kt
class DisplayFragment : Fragment() {
   private lateinit var binding: FragmentDisplayBinding
   override fun onCreateView(
        inflater: LayoutInflater, container: ViewGroup?, savedInstanceState: Bundle?): View {
        binding = FragmentDisplayBinding.inflate(inflater, container, false)
        return binding.root
    }
    override fun onViewCreated(view: View, savedInstanceState: Bundle?) {
        super.onViewCreated(view, savedInstanceState)
        val sharedPreference = activity?.let { PreferenceManager.getDefaultSharedPreferences(it) }
        binding.textPref.text = sharedPreference?.getString("textPreference", "") ?: ""
        binding.numberPref.text = sharedPreference?.getString("numberPreference", "") ?: ""
        binding.listPref.text = sharedPreference?.getString("listPreference", "") ?: ""
        binding.checkPref1.text = sharedPreference?.getBoolean("checkboxPreference1", false) .toString()
        binding.checkPref2.text = sharedPreference?.getBoolean("checkboxPreference2", false) .toString()
        binding.checkPref3.text = sharedPreference?.getBoolean("checkboxPreference3", false) .toString()
        binding.switchPref.text = sharedPreference?.getBoolean("switchPreference", false) .toString()
    }
}

onViewCreatedメソッドにSharedPreferenceから値を取得して表示する処理を入れています。

MainActivity

MainActivityは最初にDisplayFragmentを表示して、アクションバーのアイコンタップによってどっちのFragmentに遷移するかの処理をいれます。

MainActivity.kt
class MainActivity : AppCompatActivity() {
    private lateinit var binding: ActivityMainBinding
   override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        binding = ActivityMainBinding.inflate(layoutInflater).apply {
            setContentView(this.root)
        }
        supportFragmentManager
            .beginTransaction()
            .replace(R.id.fragmentContainerView, DisplayFragment())
            .commit()
    }
    override fun onCreateOptionsMenu(menu: Menu?): Boolean {
        menuInflater.inflate(R.menu.menu, menu)
        return true
    }
    override fun onOptionsItemSelected(item: MenuItem): Boolean {
        when (item.itemId) {
            R.id.setting -> {
                supportFragmentManager
                    .beginTransaction()
                    .replace(R.id.fragmentContainerView, SettingsFragment())
                    .commit()
            }
            R.id.disp -> {
                supportFragmentManager
                    .beginTransaction()
                    .replace(R.id.fragmentContainerView, DisplayFragment())
                    .commit()
            }
            else -> {}
        }
        return true
    }
}

入力した設定値はAndroid端末内のSharedPreferenceとしてxmlで保存されますので、アプリを終了しても、端末を再起動しても残っています。AndroidStudioのDeviceFileExploerで見ると
/data/data/{パッケージ名}/shared_prefs
の下にxmlでこんな風に保存されます。

<?xml version='1.0' encoding='utf-8' standalone='yes' ?>
<map>
    <string name="listPreference">2</string>
    <boolean name="checkboxPreference1" value="false" />
    <boolean name="switchPreference" value="true" />
    <string name="numberPreference">123</string>
    <boolean name="checkboxPreference3" value="true" />
    <string name="textPreference">ああああ</string>
    <boolean name="checkboxPreference2" value="false" />
</map>

最後に

以上で、一通り説明しました。完成形はgitHubに置きました。

2
0
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
2
0