Tôi biết đã có một triệu câu trả lời cho điều này rồi, với một câu được chấp nhận. Tuy nhiên, có rất nhiều lỗi trong câu trả lời được chấp nhận và hầu hết phần còn lại chỉ đơn giản là sửa một (hoặc có thể hai) trong số đó, mà không mở rộng cho tất cả các trường hợp sử dụng có thể.
Vì vậy, về cơ bản tôi đã biên dịch hầu hết các bản sửa lỗi được đề xuất trong các câu trả lời hỗ trợ cũng như thêm một phương thức để cho phép nhập số liên tục ngoài phạm vi theo hướng 0 (nếu phạm vi không bắt đầu từ 0), ít nhất là cho đến khi chắc chắn rằng nó không còn có thể trong phạm vi. Bởi vì rõ ràng, đây là lần duy nhất thực sự gây rắc rối với nhiều giải pháp khác.
Đây là cách khắc phục:
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("");
}
}
}
Lưu ý rằng một số trường hợp đầu vào không thể xử lý "chủ động" (nghĩa là, vì người dùng đang nhập nó), vì vậy chúng tôi phải bỏ qua chúng và xử lý chúng sau khi người dùng hoàn thành chỉnh sửa văn bản.
Đây là cách bạn có thể sử dụng nó:
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);
Bây giờ, khi người dùng cố gắng nhập một số gần bằng 0 hơn phạm vi cho phép, một trong hai điều sẽ xảy ra:
Nếu min
và max
có cùng số chữ số, họ sẽ không được phép nhập số đó một khi họ đến chữ số cuối cùng.
Nếu một số bên ngoài phạm vi được để lại trong trường khi văn bản mất tiêu điểm, nó sẽ tự động được điều chỉnh đến ranh giới gần nhất.
Và tất nhiên, người dùng sẽ không bao giờ được phép nhập giá trị xa hơn 0 so với phạm vi cho phép, cũng như không thể để một số như thế "vô tình" nằm trong trường văn bản vì lý do này.
Vấn đề đã biết (s?)
- Điều này chỉ hoạt động nếu
EditText
mất tập trung khi người dùng được thực hiện với nó.
Tùy chọn khác là vệ sinh khi người dùng nhấn phím "hoàn thành" / trả lại, nhưng trong nhiều hoặc thậm chí hầu hết các trường hợp, điều này gây ra sự mất tập trung dù sao đi nữa.
Tuy nhiên, việc đóng bàn phím mềm sẽ không tự động bỏ tiêu điểm. Tôi chắc chắn 99,99% các nhà phát triển Android mong muốn điều đó (và việc xử lý tập trung vào EditText
các yếu tố nói chung không phải là một vấn đề khó khăn), nhưng cho đến nay vẫn chưa có chức năng tích hợp cho nó. Phương pháp đơn giản nhất mà tôi đã tìm thấy để giải quyết vấn đề này, nếu bạn cần, là mở rộng EditText
một cái gì đó như thế này:
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);
}
}
Điều này sẽ "đánh lừa" bộ lọc trong việc vệ sinh đầu vào mặc dù chế độ xem chưa thực sự mất tiêu điểm. Nếu chế độ xem xảy ra sau đó tự mất tập trung, vệ sinh đầu vào sẽ kích hoạt lại, nhưng sẽ không có gì thay đổi vì nó đã được sửa.
Đóng cửa
Phù Đó là rất nhiều. Điều ban đầu có vẻ như là một vấn đề khá dễ dàng đã kết thúc bằng việc phát hiện ra nhiều mảnh vani xấu xí của Android (ít nhất là trong Java). Và một lần nữa, bạn chỉ cần thêm người nghe và mở rộng EditText
nếu phạm vi của bạn không bao gồm 0 theo một cách nào đó. (Và thực tế, nếu phạm vi của bạn không bao gồm 0 mà bắt đầu từ 1 hoặc -1, bạn cũng sẽ không gặp vấn đề.)
Như một lưu ý cuối cùng, điều này chỉ hoạt động cho ints . Chắc chắn có một cách để thực hiện nó để làm việc với số thập phân ( double
, float
), nhưng vì cả tôi và người hỏi ban đầu đều không có nhu cầu đó, tôi đặc biệt không muốn tìm hiểu sâu về nó. Sẽ rất dễ dàng khi chỉ cần sử dụng bộ lọc sau hoàn thành cùng với các dòng sau:
// 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;
Bạn sẽ chỉ phải thay đổi từ int
đến float
(hoặc double
), cho phép chèn của một đơn .
(hoặc ,
, tùy thuộc vào quốc gia?), Và phân tích cú pháp là một trong những loại thập phân thay vì một int
.
Điều đó xử lý hầu hết các công việc, vì vậy nó sẽ hoạt động rất giống nhau.