带有数字选择器的 Android PreferenceActivity 对话框
Posted
技术标签:
【中文标题】带有数字选择器的 Android PreferenceActivity 对话框【英文标题】:Android PreferenceActivity dialog with number picker 【发布时间】:2014-01-12 14:00:36 【问题描述】:我已经看到了许多针对这个问题的定制解决方案和答案。我需要一些非常简单的东西,我有一个偏好活动,我所需要的只是其中一个选项将打开带有数字选择器的对话框并保存结果。你能指导我一步一步地完成这个吗?
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>
数字选择器 XML:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_
android:layout_ >
<NumberPicker
android:id="@+id/numberPicker1"
android:layout_
android:layout_
android:layout_alignParentTop="true"
android:layout_centerHorizontal="true"
android:layout_marginTop="64dp" />
<Button
android:id="@+id/button2"
android:layout_
android:layout_
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_
android:layout_
android:layout_alignBaseline="@+id/button2"
android:layout_alignBottom="@+id/button2"
android:layout_marginRight="16dp"
android:layout_toLeftOf="@+id/numberPicker1"
android:text="Set" />
</RelativeLayout>
【问题讨论】:
【参考方案1】:实现DialogPreference
是一个解决方案:
【讨论】:
【参考方案2】:子类DialogPreference
来构建您自己的NumberPickerPreference
。
我在下面为您实现了一个。它工作得很好,但功能不完整。例如,最小值和最大值是硬编码的常量。这些实际上应该是首选项 xml 声明中的属性。要让它工作,您需要添加一个 attrs.xml 文件来指定您的自定义属性。
有关在库项目中支持自定义 xml 属性的 NumberPicker 首选项小部件的完整实现以及展示如何使用它的演示应用,请参阅 GitHub:https://github.com/Alobar/AndroidPreferenceTest
您可以将小部件用作任何其他首选项小部件,除非您必须完全限定名称:
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;
【讨论】:
onDialogClosed 应该调用 if (callChangeListener(value)) setValue(picker.getValue());为了获得正确的更改通知(请注意,Andoird Studio 中的 stock Preferences 实现依赖于此来更新偏好摘要)。 @RobinDavies 谢谢,我完全错过了那一点基础设施,我已经更新了代码。 有没有办法让这个选择器“非圆形”,即它应该停在最大值。 @SrujanBarai,是的,您可以在号码选择器上使用setWrapSelectorWheel()
。我已更新代码以包含此选项。看看,你会想要将它设置为 false。
如何更改此设置以在首选项列表中显示当前选择的值?【参考方案3】:
一个基于 ListPreference 的简单解决方案,动态添加值/条目:
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");
...
【讨论】:
【参考方案4】:这是我在 androidx 和 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" />
希望这会有所帮助。
【讨论】:
嘿,伙计,这段代码在我的 android 模拟器上运行良好,但在我的手机上却没有,我的 android 模拟器正在使用 android 7 和我的手机 android 11,我得到 java.lang.ClassCastException: java.lang。 String 不能在此行上转换为 java.lang.Integer return getPersistedInt(INITIAL_VALUE).toString()...对此有任何修复吗?似乎我必须将该行的值更改为整数?以上是关于带有数字选择器的 Android PreferenceActivity 对话框的主要内容,如果未能解决你的问题,请参考以下文章
ImageSource.Gallery 上带有抖动的图像选择器的错误