मुझे पता है कि इस पहले से ही एक लाख उत्तर हैं, जिसमें से एक को स्वीकार किया गया है। हालाँकि, स्वीकृत उत्तर में कई कीड़े हैं और बाकी सभी संभव मामलों में विस्तार किए बिना, उनमें से एक (या शायद दो) को ठीक करते हैं।
इसलिए मैंने मूल रूप से समर्थन उत्तरों में सुझाए गए अधिकांश बग फिक्स को संकलित करने के साथ-साथ 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);
}
}
यह इनपुट को फ़िल्टर करने में फ़िल्टर को "ट्रिक" करेगा, हालांकि दृश्य वास्तव में फ़ोकस नहीं हुआ है। यदि दृश्य बाद में अपने आप पर ध्यान केंद्रित करने से चूक जाता है, तो इनपुट स्वच्छता फिर से ट्रिगर हो जाएगी, लेकिन कुछ भी नहीं बदलेगा क्योंकि यह पहले से ही तय था।
समापन
वाह। वह बहुत कुछ था। मूल रूप से ऐसा लग रहा था कि यह एक बहुत ही मामूली आसान समस्या होगी, जो कि वेनिला एंड्रॉइड के कई छोटे बदसूरत टुकड़ों (कम से कम जावा में) को उजागर करती है। और एक बार फिर, आपको केवल श्रोता को जोड़ने और विस्तार करने की आवश्यकता है EditText
यदि आपकी सीमा में किसी तरह से 0 शामिल नहीं है। (और वास्तविक रूप से, यदि आपकी सीमा में 0 शामिल नहीं है, लेकिन 1 या -1 से शुरू होता है, तो आप भी समस्याओं में नहीं चलेंगे।)
अंतिम नोट के रूप में, यह केवल ints के लिए काम करता है । निश्चित रूप से दशमलव ( 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
।
यह वैसे भी ज्यादातर काम संभालता है, इसलिए यह बहुत ही समान रूप से काम करेगा।