【问题标题】:Android PreferenceActivity dialog with number picker带有数字选择器的 Android PreferenceActivity 对话框
【发布时间】: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_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>

【问题讨论】:

    标签: android dialog numberpicker


    【解决方案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()...对此有任何修复吗?似乎我必须将该行的值更改为整数?
        猜你喜欢
        • 2013-07-12
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-04-01
        • 2012-08-01
        • 1970-01-01
        • 2011-11-29
        • 1970-01-01
        相关资源
        最近更新 更多