9

有谁知道使用Android的默认数字选择器允许负数的简单方法?我知道是 InputFilter 不允许这样做,但是有没有简单的方法可以覆盖而不重写整个小部件?

4

4 回答 4

14

更通用和优雅的解决方案是使用NumberPicker.Formatter并在 NumberPicker 中仅使用正数。

例如,如果我想在 [-50, 50] 中选择一个数字:

final int minValue = -50
final int maxValue = 50
NumberPicker numberPicker = new NumberPicker(myActivity);
numberPicker.setMinValue(0);
numberPicker.setMaxValue(maxValue - minValue);
numberPicker.setValue(myCurrentValue - minValue);
numberPicker.setFormatter(new NumberPicker.Formatter() {
    @Override
    public String format(int index) {
        return Integer.toString(index + minValue);
    }
});

然后取回选定的值:

int myNewValue = numberPicker.getValue() + minValue
于 2013-07-17T12:17:11.553 回答
5

利用:


String[] nums {"-1","-2","-3","-4"};
numberpicker.setDisplayedValues(nums);
或者

String[] nums = new String[4];
for(int i=0; i<nums.length; i++)
nums[i] = "-" + Integer.toString(i);
numberpicker.setDisplayedValues(nums);

其中任何一个都可以让您为 NumberPicker 使用任何字符串集。你正在做的是你指定一组你传递给 NumberPicker 的字符串。然后它将显示您的值而不是默认值。

于 2013-02-24T16:04:13.410 回答
1

使用.setFormatter()不允许输入负数。使用.setDisplayedValues()键盘显示文本而不是数字。所以这里是类SignedNumberPicker

class SignedNumberPicker extends android.widget.NumberPicker {
  int nToAdd=0,mMaxValue=0,mMinValue=0;
  EditText tv;
  private void init() {
    super.setFormatter(new Formatter() {
      @Override
      public String format(int i) {
        int r=i-nToAdd;
        return String.valueOf(r);
      }
    });
    tv.setInputType(InputType.TYPE_CLASS_NUMBER | InputType.TYPE_NUMBER_FLAG_SIGNED);
    tv.setFilters(new InputFilter[] {new InputTextFilter()});
    tv.setOnFocusChangeListener(new OnFocusChangeListener() {
      @Override
      public void onFocusChange(View view, boolean b) {
        if (b) {
          tv.selectAll();
        } else {
          String str = String.valueOf(((EditText) view).getText());
          if (TextUtils.isEmpty(str.replace("-",""))) {
            tv.setText(String.valueOf(getRealValue()));
          } else {
            textToValue();
          }
          InputMethodManager keyboard = (InputMethodManager) getContext().getSystemService(Context
              .INPUT_METHOD_SERVICE);
          if (keyboard != null) {
            keyboard.hideSoftInputFromWindow(tv.getWindowToken(),0);
          }
          tv.setVisibility(INVISIBLE);
        }
        if (mOnTextFocusChangedListener!=null) {
          mOnTextFocusChangedListener.onTextFocusChanged(b);
        }
      }
    });
  }
  void textToValue() {
    try {
      setValue(Integer.valueOf(tv.getText().toString()));
    } catch (Exception e) {}
  }
  OnTextFocusChangedListener mOnTextFocusChangedListener =null;
  public interface OnTextFocusChangedListener {
    void onTextFocusChanged(boolean textViewHasFocus);
  }
  public void setOnTextFocusChangedListener(OnTextFocusChangedListener l) {
    mOnTextFocusChangedListener =l;
  }
  public SignedNumberPicker(Context context) {
    super(context);
    init();
  }
  public SignedNumberPicker(Context context, AttributeSet attrs) {
    super(context, attrs);
    init();
  }
  @Override
  public void addView(View child) {
    super.addView(child);
    init(child);
  }
  @Override
  public void addView(View child, int index, android.view.ViewGroup.LayoutParams params) {
    super.addView(child, index, params);
    init(child);
  }
  @Override
  public void addView(View child, android.view.ViewGroup.LayoutParams params) {
    super.addView(child, params);
    init(child);
  }
  private void init(View view) {
    if(view instanceof EditText){
      tv=((EditText) view);
    }
  }

  @Override
  public void setMinValue(int minValue) {
    if (minValue<0) {
      nToAdd=-minValue;
      super.setMaxValue(super.getMaxValue()+nToAdd);
    }
    mMinValue=minValue;
    super.setMinValue(minValue+nToAdd);
  }

  @Override
  public void setMaxValue(int maxValue) {
    if (maxValue+nToAdd<0) {
      nToAdd=-maxValue;
    }
    mMaxValue=maxValue;
    super.setMaxValue(maxValue+nToAdd);
  }

  @Override
  public void setValue(int value) {
    super.setValue(value+nToAdd);
  }
  public int getRealValue() {
    if (tv.hasFocus()) textToValue();
    return super.getValue()-nToAdd;
  }
  private NumberPicker.OnValueChangeListener mOnValueChangedListener=null;
  @Override
  public void setOnValueChangedListener(OnValueChangeListener onValueChangedListener) {
    mOnValueChangedListener=onValueChangedListener;
    super.setOnValueChangedListener(new OnValueChangeListener() {
      @Override
      public void onValueChange(NumberPicker picker, int oldVal, int newVal) {
        mOnValueChangedListener.onValueChange(picker,oldVal-nToAdd,newVal-nToAdd);
      }
    });
  }

  //copied from NumberPicker source & modified
  //https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/widget/NumberPicker.java
  class InputTextFilter extends NumberKeyListener {

    // XXX This doesn't allow for range limits when controlled by a
    // soft input method!
    public int getInputType() {
      return InputType.TYPE_CLASS_TEXT;
    }

    @Override
    protected char[] getAcceptedChars() {
      return DIGIT_CHARACTERS;
    }

    @Override
    public CharSequence filter(
        CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
      // We don't know what the output will be, so always cancel any
      // pending set selection command.
      /*if (mSetSelectionCommand != null) {
        mSetSelectionCommand.cancel();
      }*/
      //and we will ignore this

      CharSequence filtered = super.filter(source, start, end, dest, dstart, dend);
      if (filtered == null) {
        filtered = source.subSequence(start, end);
      }

      String result = String.valueOf(dest.subSequence(0, dstart)) + filtered
          + dest.subSequence(dend, dest.length());

      if ("".equals(result)) {
        return result;
      }
      int val = getSelectedPos(result);

    /*
     * Ensure the user can't type in a value greater than the max
     * allowed. We have to allow less than min as the user might
     * want to delete some numbers and then type a new number.
     * And prevent multiple-"0" that exceeds the length of upper
     * bound number.
     */
      if (val > mMaxValue || (result.length() > String.valueOf(mMaxValue).length() && result
          .length()>String.valueOf(mMinValue).length()) || (val<0 && val<mMinValue)) {
        return "";
      } else {
        return filtered;
      }
    }
    private int getSelectedPos(String value) {
      try {
        return Integer.parseInt(value);
      } catch (NumberFormatException e) {
        // Ignore as if it's not a number we don't care
      }
      return mMinValue;
    }
    private final char[] DIGIT_CHARACTERS = new char[] {
        //THE MINUS SIGN
        '-',
        // Latin digits are the common case
        '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
        // Arabic-Indic
        '\u0660', '\u0661', '\u0662', '\u0663', '\u0664', '\u0665', '\u0666', '\u0667', '\u0668'
        , '\u0669',
        // Extended Arabic-Indic
        '\u06f0', '\u06f1', '\u06f2', '\u06f3', '\u06f4', '\u06f5', '\u06f6', '\u06f7', '\u06f8'
        , '\u06f9',
        // Hindi and Marathi (Devanagari script)
        '\u0966', '\u0967', '\u0968', '\u0969', '\u096a', '\u096b', '\u096c', '\u096d', '\u096e'
        , '\u096f',
        // Bengali
        '\u09e6', '\u09e7', '\u09e8', '\u09e9', '\u09ea', '\u09eb', '\u09ec', '\u09ed', '\u09ee'
        , '\u09ef',
        // Kannada
        '\u0ce6', '\u0ce7', '\u0ce8', '\u0ce9', '\u0cea', '\u0ceb', '\u0cec', '\u0ced', '\u0cee'
        , '\u0cef'
    };
  }
}

像“正常” NumberPicker 一样使用它,但可以随意使用负数。而不是getValue(), use getRealValue(), 因为getValue()NumberPicker (!?) 在内部使用。我还添加了setOnTextFocusChangedListener()方法,这可能便于禁用 OK 按钮等。

更新:如果你想阻止用户输入相同的值,只要显示键盘,你可以禁用 OK 按钮,并听取值的变化:

dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
numberPicker.setOnTextFocusChangedListener(new SignedNumberPicker.OnTextFocusChangedListener() {
  @Override
  public void onTextFocusChanged(boolean textViewHasFocus) {
    if (textViewHasFocus) {
      dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(false);
    } else {
      dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(numberPicker.getRealValue()!=currentValue);
    }
  }
});
numberPicker.setOnValueChangedListener(new NumberPicker.OnValueChangeListener() {
  @Override
  public void onValueChange(android.widget.NumberPicker picker, int oldVal, int newVal) {
    dialog.getButton(AlertDialog.BUTTON_POSITIVE).setEnabled(newVal!=currentValue);
  }
});
于 2018-03-26T19:25:06.533 回答
-1

是您正在寻找的示例。

private static final int DEFAULT_MAX = 200;
private static final int DEFAULT_MIN = 0;// change this acc to your requirement
于 2013-01-16T11:44:21.070 回答