Android PreferenceActivity Dialog With Number Picker


Answer :

Subclass DialogPreference to build your own NumberPickerPreference.

I have implemented one below for you. It works perfectly fine, but is not feature complete. For example the minimum and maximum values are hard-coded constants. These should really be attributes on the preference xml declaration. To get that to work you would need to add an attrs.xml file specifying your custom attributes.

For the full implementation of the NumberPicker preference widget that supports custom xml attributes in a library project and a demo app showing how to use it, see GitHub: https://github.com/Alobar/AndroidPreferenceTest

You would use the widget as any other preference widget, except you have to fully qualify the name:

preferences.xml

<PreferenceScreen xmlns:android="http://schemas.android.com/apk/res/android">      <com.example.preference.NumberPickerPreference         android:key="key_number"         android:title="Give me a number"         android:defaultValue="55" />  </PreferenceScreen> 

NumberPickerPreference.java

package com.example.preference;  import android.content.Context; import android.content.res.TypedArray; import android.preference.DialogPreference; import android.util.AttributeSet; import android.view.Gravity; import android.view.View; import android.view.ViewGroup; import android.widget.FrameLayout; import android.widget.NumberPicker;  /**  * A {@link android.preference.Preference} that displays a number picker as a dialog.  */ public class NumberPickerPreference extends DialogPreference {      // allowed range     public static final int MAX_VALUE = 100;     public static final int MIN_VALUE = 0;     // enable or disable the 'circular behavior'     public static final boolean WRAP_SELECTOR_WHEEL = true;       private NumberPicker picker;     private int value;      public NumberPickerPreference(Context context, AttributeSet attrs) {         super(context, attrs);     }      public NumberPickerPreference(Context context, AttributeSet attrs, int defStyleAttr) {         super(context, attrs, defStyleAttr);     }      @Override     protected View onCreateDialogView() {         FrameLayout.LayoutParams layoutParams = new FrameLayout.LayoutParams(                 ViewGroup.LayoutParams.WRAP_CONTENT, ViewGroup.LayoutParams.WRAP_CONTENT);         layoutParams.gravity = Gravity.CENTER;          picker = new NumberPicker(getContext());         picker.setLayoutParams(layoutParams);          FrameLayout dialogView = new FrameLayout(getContext());         dialogView.addView(picker);          return dialogView;     }      @Override     protected void onBindDialogView(View view) {         super.onBindDialogView(view);         picker.setMinValue(MIN_VALUE);         picker.setMaxValue(MAX_VALUE);         picker.setWrapSelectorWheel(WRAP_SELECTOR_WHEEL);         picker.setValue(getValue());     }      @Override     protected void onDialogClosed(boolean positiveResult) {         if (positiveResult) {             picker.clearFocus();             int newValue = picker.getValue();             if (callChangeListener(newValue)) {                 setValue(newValue);             }         }     }      @Override     protected Object onGetDefaultValue(TypedArray a, int index) {         return a.getInt(index, MIN_VALUE);     }      @Override     protected void onSetInitialValue(boolean restorePersistedValue, Object defaultValue) {         setValue(restorePersistedValue ? getPersistedInt(MIN_VALUE) : (Integer) defaultValue);     }      public void setValue(int value) {         this.value = value;         persistInt(this.value);     }      public int getValue() {         return this.value;     } } 

Here's how I did it in androidx and kotlin:

NumberPickerPreference.kt

import android.content.Context import android.util.AttributeSet import androidx.preference.DialogPreference  class NumberPickerPreference(context: Context?, attrs: AttributeSet?) :     DialogPreference(context, attrs) {      override fun getSummary(): CharSequence {         return getPersistedInt(INITIAL_VALUE).toString()     }      fun getPersistedInt() = super.getPersistedInt(INITIAL_VALUE)      fun doPersistInt(value: Int) {         super.persistInt(value)         notifyChanged()     }      companion object {         // allowed range         const val INITIAL_VALUE = 50         const val MIN_VALUE = 12         const val MAX_VALUE = 100     } } 

NumberPickerPreferenceDialog.kt

import android.content.Context import android.os.Bundle import android.view.View import android.widget.NumberPicker import androidx.preference.PreferenceDialogFragmentCompat   class NumberPickerPreferenceDialog : PreferenceDialogFragmentCompat() {     lateinit var numberPicker: NumberPicker      override fun onCreateDialogView(context: Context?): View {         numberPicker = NumberPicker(context)         numberPicker.minValue = NumberPickerPreference.MIN_VALUE         numberPicker.maxValue = NumberPickerPreference.MAX_VALUE          return numberPicker     }      override fun onBindDialogView(view: View?) {         super.onBindDialogView(view)         numberPicker.value = (preference as NumberPickerPreference).getPersistedInt()     }      override fun onDialogClosed(positiveResult: Boolean) {         if (positiveResult) {             numberPicker.clearFocus()             val newValue: Int = numberPicker.value             if (preference.callChangeListener(newValue)) {                 (preference as NumberPickerPreference).doPersistInt(newValue)                 preference.summary             }         }     }      companion object {         fun newInstance(key: String): NumberPickerPreferenceDialog {             val fragment = NumberPickerPreferenceDialog()             val bundle = Bundle(1)             bundle.putString(ARG_KEY, key)             fragment.arguments = bundle              return fragment         }     } } 

SettingsFragment.kt

import android.os.Bundle import androidx.preference.Preference import androidx.preference.PreferenceFragmentCompat  class SettingsFragment : PreferenceFragmentCompat() {     private val DIALOG_FRAGMENT_TAG = "NumberPickerDialog"      override fun onCreatePreferences(savedInstanceState: Bundle?, rootKey: String?) {         setPreferencesFromResource(R.xml.settings, rootKey)     }      override fun onDisplayPreferenceDialog(preference: Preference?) {         if (parentFragmentManager.findFragmentByTag(DIALOG_FRAGMENT_TAG) != null) {             return         }         if (preference is NumberPickerPreference) {             val dialog = NumberPickerPreferenceDialog.newInstance(preference.key)             dialog.setTargetFragment(this, 0)             dialog.show(parentFragmentManager, DIALOG_FRAGMENT_TAG)         } else             super.onDisplayPreferenceDialog(preference)     } } 

settings.xml

<your.package.NumberPickerPreference         app:key="your_pref_key"         app:title="@string/your_pref_title" /> 

Hope this helps.


Implementing DialogPreference is a solution:

  • NumberPicker Preference Dialog for Android is really simple.
  • Or check this resolved question: Create NumberPicker dialog in preference

Comments

Popular posts from this blog

Are Regular VACUUM ANALYZE Still Recommended Under 9.1?

Can Feynman Diagrams Be Used To Represent Any Perturbation Theory?