나는 이것에 이미 백만 개의 답변이 있으며, 하나는 받아 들였다. 그러나 허용 된 답변에는 수많은 버그가 있으며 나머지 대부분은 가능한 모든 사용 사례로 확장하지 않고 단순히 하나 또는 두 개를 수정합니다.
따라서 기본적으로 지원 답변에서 제안 된 대부분의 버그 수정을 컴파일하고 범위를 벗어난 숫자를 0 방향 (범위가 0에서 시작하지 않는 경우)으로 연속 입력 할 수있는 방법을 추가했습니다. 더 이상 범위 내에 있지 않아야합니다. 분명히하기 위해, 지금이 다른 많은 솔루션에 실제로 문제를 일으키는 유일한 시간입니다.
수정 사항은 다음과 같습니다.
public class InputFilterIntRange implements InputFilter, View.OnFocusChangeListener {
private final int min, max;
public InputFilterIntRange(int min, int max) {
if (min > max) {
// Input sanitation for the filter itself
int mid = max;
max = min;
min = mid;
}
this.min = min;
this.max = max;
}
@Override
public CharSequence filter(CharSequence source, int start, int end, Spanned dest, int dstart, int dend) {
// Determine the final string that will result from the attempted input
String destString = dest.toString();
String inputString = destString.substring(0, dstart) + source.toString() + destString.substring(dstart);
// Don't prevent - sign from being entered first if min is negative
if (inputString.equalsIgnoreCase("-") && min < 0) return null;
try {
int input = Integer.parseInt(inputString);
if (mightBeInRange(input))
return null;
} catch (NumberFormatException nfe) {}
return "";
}
@Override
public void onFocusChange(View v, boolean hasFocus) {
// Since we can't actively filter all values
// (ex: range 25 -> 350, input "15" - could be working on typing "150"),
// lock values to range after text loses focus
if (!hasFocus) {
if (v instanceof EditText) sanitizeValues((EditText) v);
}
}
private boolean mightBeInRange(int value) {
// Quick "fail"
if (value >= 0 && value > max) return false;
if (value >= 0 && value >= min) return true;
if (value < 0 && value < min) return false;
if (value < 0 && value <= max) return true;
boolean negativeInput = value < 0;
// If min and max have the same number of digits, we can actively filter
if (numberOfDigits(min) == numberOfDigits(max)) {
if (!negativeInput) {
if (numberOfDigits(value) >= numberOfDigits(min) && value < min) return false;
} else {
if (numberOfDigits(value) >= numberOfDigits(max) && value > max) return false;
}
}
return true;
}
private int numberOfDigits(int n) {
return String.valueOf(n).replace("-", "").length();
}
private void sanitizeValues(EditText valueText) {
try {
int value = Integer.parseInt(valueText.getText().toString());
// If value is outside the range, bring it up/down to the endpoint
if (value < min) {
value = min;
valueText.setText(String.valueOf(value));
} else if (value > max) {
value = max;
valueText.setText(String.valueOf(value));
}
} catch (NumberFormatException nfe) {
valueText.setText("");
}
}
}
일부 입력 사례는 "활성 적으로"처리 할 수 없으므로 (즉, 사용자가 입력 한대로)이를 무시하고 사용자가 텍스트 편집을 마친 후에 처리해야합니다.
사용 방법은 다음과 같습니다.
EditText myEditText = findViewById(R.id.my_edit_text);
InputFilterIntRange rangeFilter = new InputFilterIntRange(25, 350);
myEditText.setFilters(new InputFilter[]{rangeFilter});
// Following line is only necessary if your range is like [25, 350] or [-350, -25].
// If your range has 0 as an endpoint or allows some negative AND positive numbers,
// all cases will be handled pre-emptively.
myEditText.setOnFocusChangeListener(rangeFilter);
이제 사용자가 허용되는 범위보다 0에 가까운 숫자를 입력하려고하면 다음 두 가지 중 하나가 발생합니다.
경우 min
와 max
동일한 자릿수의 그들이 마지막 자리에 도착하면, 그들은 모두에서 입력을 허용하지 않습니다.
텍스트가 포커스를 잃을 때 범위를 벗어난 숫자가 필드에 남아 있으면 가장 가까운 경계로 자동 조정됩니다.
물론, 사용자는 허용되는 범위보다 0에서 더 멀리 떨어진 값을 입력 할 수 없으며 이와 같은 숫자로 인해 텍스트 필드에 "실수로"있을 수도 없습니다.
알려진 문제
EditText
사용자가 작업을 마쳤을 때 포커스를 잃는 경우에만 작동 합니다.
다른 옵션은 사용자가 "완료"/ 반환 키를 눌렀을 때 살균하는 것이지만, 대부분 또는 대부분의 경우 어쨌든 초점이 손실됩니다.
그러나 소프트 키보드를 닫아도 요소 초점이 자동으로 해제되지 는 않습니다 . 나는 안드로이드 개발자의 99.99 %가 그것을 원한다고 확신하지만 (그리고 EditText
요소에 대한 초점 처리 는 일반적으로 큰 문제가 아니 었습니다), 그러나 현재로서는 내장 기능이 없습니다. 이 문제를 해결하는 가장 쉬운 방법은 EditText
다음과 같이 확장하는 것입니다.
public class EditTextCloseEvent extends AppCompatEditText {
public EditTextCloseEvent(Context context) {
super(context);
}
public EditTextCloseEvent(Context context, AttributeSet attrs) {
super(context, attrs);
}
public EditTextCloseEvent(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
}
@Override
public boolean onKeyPreIme(int keyCode, KeyEvent event) {
if (event.getKeyCode() == KeyEvent.KEYCODE_BACK) {
for (InputFilter filter : this.getFilters()) {
if (filter instanceof InputFilterIntRange)
((InputFilterIntRange) filter).onFocusChange(this, false);
}
}
return super.dispatchKeyEvent(event);
}
}
뷰가 실제로 포커스를 잃지 않았더라도 입력을 살균하기 위해 필터를 "트릭"합니다 . 보기가 나중에 자체적으로 초점을 잃으면 입력 위생이 다시 트리거되지만 이미 수정되었으므로 아무것도 변경되지 않습니다.
폐쇄
아휴. 그것은 많았다. 처음에는 꽤 쉬운 문제인 것처럼 보였지만 바닐라 안드로이드의 작은 조각을 발견했습니다 (적어도 Java에서는). 다시 한 번, 리스너를 추가하고 EditText
범위에 0이 포함되지 않은 경우 확장 하면됩니다. (실제로 범위에 0이 포함되어 있지 않지만 1 또는 -1에서 시작하면 문제가 발생하지 않습니다.)
마지막으로, 이것은 int 에서만 작동합니다 . 확실히 십진수 ( double
, float
) 로 작동하도록 구현할 수있는 방법이 있지만, 나나 원래의 요구자는 그것을 필요로하지 않기 때문에 특별히 깊이 들어가고 싶지는 않습니다. 완료 후 필터링을 다음 행과 함께 사용하는 것이 매우 쉽습니다.
// Quick "fail"
if (value >= 0 && value > max) return false;
if (value >= 0 && value >= min) return true;
if (value < 0 && value < min) return false;
if (value < 0 && value <= max) return true;
당신은에서 변경해야 할 것입니다 int
에 float
(또는 double
), 하나의 삽입을 허용 .
(또는 ,
, 국가에 따라?), 그리고 대신의 진수 유형 중 하나로서 구문 분석 int
.
어쨌든 대부분의 작업을 처리하므로 매우 유사하게 작동합니다.