Android PreferenceActivity dialog with number picker

Viewed 17572

I have seen many customized solutions and answers to this question. I need something very simple, I have a preference activity and all I need is that one of the options will open dialog with a number picker and save the results. Can you please guide me step by step with how to accomplish this?

public class SettingsActivity extends PreferenceActivity
{
    @Override
    protected void onCreate(final Bundle savedInstanceState)
    {
        super.onCreate(savedInstanceState);
        getFragmentManager().beginTransaction().replace(android.R.id.content, new MyPreferenceFragment()).commit();
        //requestWindowFeature(Window.FEATURE_NO_TITLE);    
    }

    public static class MyPreferenceFragment extends PreferenceFragment
    {
        @Override
        public void onCreate(final Bundle savedInstanceState)
        {
            super.onCreate(savedInstanceState);
            addPreferencesFromResource(R.xml.prefs);

        }
    }

}

XML:

    <SwitchPreference
        android:key="cross"
        android:summaryOff="Cross is invisible"
        android:summaryOn="Cross is visible"
        android:switchTextOff="OFF"
        android:switchTextOn="ON"
        android:title="Cross" 
        android:defaultValue="true"/>

    <SwitchPreference
        android:key="autoP"
        android:summaryOff="App will go to sleep"
        android:summaryOn="App will not go to sleep"
        android:switchTextOff="OFF"
        android:switchTextOn="ON"
        android:title="Always On" 
        android:defaultValue="true"/>

    <SwitchPreference
        android:key="tempD"
        android:summaryOff="Temprature not displayed"
        android:summaryOn="Temprature displayed"
        android:switchTextOff="OFF"
        android:switchTextOn="ON"
        android:title="Tempature Display" 
        android:defaultValue="true"/>

    <ListPreference
        android:entries="@array/units"
        android:entryValues="@array/lunits"
        android:key="listUnits"
        android:summary="Units schosssing"
        android:title="Units" android:defaultValue="C"/>

     <!--Need to add button to open dialog-->       

</PreferenceScreen>

Number Picker XML:

<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent" >

    <NumberPicker
        android:id="@+id/numberPicker1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignParentTop="true"
        android:layout_centerHorizontal="true"
        android:layout_marginTop="64dp" />

    <Button
        android:id="@+id/button2"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_below="@+id/numberPicker1"
        android:layout_marginLeft="20dp"
        android:layout_marginTop="98dp"
        android:layout_toRightOf="@+id/numberPicker1"
        android:text="Cancel" />

    <Button
        android:id="@+id/button1"
        android:layout_width="wrap_content"
        android:layout_height="wrap_content"
        android:layout_alignBaseline="@+id/button2"
        android:layout_alignBottom="@+id/button2"
        android:layout_marginRight="16dp"
        android:layout_toLeftOf="@+id/numberPicker1"
        android:text="Set" />

</RelativeLayout>
4 Answers

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.

A simple solution based on ListPreference, add values/entries on the fly:

root_preferences.xml:

<PreferenceScreen xmlns:app="http://schemas.android.com/apk/res-auto"
    ...

    <ListPreference
        app:key="myNumber"
        app:title="my title"
        app:useSimpleSummaryProvider="true"/>

SettingsActivity.java:

public  class SettingsFragment extends PreferenceFragmentCompat {

    @Override
    public void onCreatePreferences(Bundle savedInstanceState, String rootKey) {
        setPreferencesFromResource(R.xml.root_preferences, rootKey);

        ListPreference e = findPreference("myNumber");
        if (e != null) {
            String[] vals = new String[100];
            for (int i = 0; i < vals.length; i++)
                vals[i] = String.valueOf(i + 1);
            e.setEntries(vals);
            e.setEntryValues(vals);
            e.setDefaultValue("1");
        }
    }
...
}
Related