android - EditText 长度过滤器无法正常工作
android - EditText length filter not working as it should
首先我不得不说我已经在 SO 上阅读过类似的问题和答案,这个问题基本上是 和许多其他问题的重复,但是对这些问题的回答并不像这样我想要。
问题:
像这样以编程方式在我的 EditText 上设置长度过滤器:
editText.setFilters(new InputFilter[]{new LengthFilter(10)} );
它唯一做的就是隐藏超出 EditText 限制的文本。它仍然在建议框中显示长(无限制)文本,我必须删除(退格)每个经过的字母才能删除 EditText 中显示的内容。
建议的解决方案:
正在将 InputType 设置为 textFilter
。
我以编程方式这样做:
editText.setInputType( InputType.TYPE_TEXT_VARIATION_FILTER );
它隐藏了建议,但无限文本仍然存在,我仍然必须使用退格键删除不应该出现的字母。
正在将 InputType 设置为 textNoSuggestions|textVisiblePassword
。
我以编程方式做了这个(必须添加 TYPE_CLASS_TEXT
否则它不会工作):
editText.setInputType( InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD );
这个确实有效,但问题是它停止了 "gesture typing" 并将字体更改为等宽字体。
更好的解决方案?
如您所见,如果没有其他问题,这两种方法实际上并不能正常工作。还有其他我错过的方法吗?如果我想保留手势输入和建议,我应该只使用 TextWatcher
吗?
我最终改用了 TextWatcher。我不确定这是否是执行此操作的最佳方法,但它确实适用于建议,并且不会关闭手势输入或更改字体样式。这是我的做法(我对 android 很陌生,所以如果需要改进,请随时告诉我)。
我在评论中添加了一个示例来阐明发生了什么。
创建这些全局变量:
private boolean mWatcherIsBlocked = false;
private String mBeforeChange;
private String mFilteredString;
private int mCursorPosition = 0;
然后创建 TextWatcher 并将其添加到您的 EditText
final int maxLength = 10; // desired length limit
/**
* lets say our EditText is showing "abcdefgh". We select "cdef" from it and
* paste a new text "ijklmnop" in the middle. What we should get according to
* our maxLength is this:
* (1) "ab" (0th up to the letter from before_change_text we were selecting) +
* (2) "ijklmn" (part of the text we pasted minus the number of letters the whole
* after_change_text goes over the 10 letter limit) +
* (3) "gh" (last part of before_change_text that wasn't selected)
*
* so the new text has to be "abijkmngh"
*/
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// get before_change_text if textWatcher isn't blocked
if (!mWatcherIsBlocked) mBeforeChange = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!mWatcherIsBlocked){
// get after_change_text if textWatcher isn't blocked
String after = s.toString();
// if after_change_text's length is bigger than the limit
if (after.length() > maxLength) {
// see how much it goes over the limit
int over = after.length() - maxLength;
// add parts (1) and (2) like our example above
String st = mBeforeChange.substring(0, start) + // (1)
after.substring(start, start + count - over); // (2)
// get where the cursor position should be after pasting (
// = after the last letter we could paste = length of (1) + (2) )
mCursorPosition = st.length();
// now add part (3) of our text to the first two
st += mBeforeChange.substring(
mBeforeChange.length() - (maxLength - st.length()),
mBeforeChange.length());
// now assign this new text to a global variable
mFilteredString = st;
} else {
// if after_change_text hasn't gone over the limit assign it
// directly to our global variable
mFilteredString = s.toString();
}
}
}
@Override
public void afterTextChanged(Editable s) {
// if filtered text is not the same as unfiltered text
// or textWatcher is not blocked
if (!mFilteredString.equals(s.toString()) && !mWatcherIsBlocked) {
// block textWatcher to avoid infinite loops created by setText
// (this might not work as I well as I think!)
mWatcherIsBlocked = true;
// set new text to our EditText
editText.setText(mFilteredString);
// set its cursor position
editText.setSelection(mCursorPosition);
// unblock the textWatcher
mWatcherIsBlocked = false;
}
}
};
// add the TextWatcher to our EditText
editText.addTextChangedListener(textWatcher);
首先我不得不说我已经在 SO 上阅读过类似的问题和答案,这个问题基本上是
问题:
像这样以编程方式在我的 EditText 上设置长度过滤器:
editText.setFilters(new InputFilter[]{new LengthFilter(10)} );
它唯一做的就是隐藏超出 EditText 限制的文本。它仍然在建议框中显示长(无限制)文本,我必须删除(退格)每个经过的字母才能删除 EditText 中显示的内容。
建议的解决方案:
正在将 InputType 设置为
textFilter
。
我以编程方式这样做:editText.setInputType( InputType.TYPE_TEXT_VARIATION_FILTER );
它隐藏了建议,但无限文本仍然存在,我仍然必须使用退格键删除不应该出现的字母。
正在将 InputType 设置为
textNoSuggestions|textVisiblePassword
。
我以编程方式做了这个(必须添加TYPE_CLASS_TEXT
否则它不会工作):editText.setInputType( InputType.TYPE_CLASS_TEXT | InputType.TYPE_TEXT_FLAG_NO_SUGGESTIONS | InputType.TYPE_TEXT_VARIATION_VISIBLE_PASSWORD );
这个确实有效,但问题是它停止了 "gesture typing" 并将字体更改为等宽字体。
更好的解决方案?
如您所见,如果没有其他问题,这两种方法实际上并不能正常工作。还有其他我错过的方法吗?如果我想保留手势输入和建议,我应该只使用 TextWatcher
吗?
我最终改用了 TextWatcher。我不确定这是否是执行此操作的最佳方法,但它确实适用于建议,并且不会关闭手势输入或更改字体样式。这是我的做法(我对 android 很陌生,所以如果需要改进,请随时告诉我)。
我在评论中添加了一个示例来阐明发生了什么。
创建这些全局变量:
private boolean mWatcherIsBlocked = false;
private String mBeforeChange;
private String mFilteredString;
private int mCursorPosition = 0;
然后创建 TextWatcher 并将其添加到您的 EditText
final int maxLength = 10; // desired length limit
/**
* lets say our EditText is showing "abcdefgh". We select "cdef" from it and
* paste a new text "ijklmnop" in the middle. What we should get according to
* our maxLength is this:
* (1) "ab" (0th up to the letter from before_change_text we were selecting) +
* (2) "ijklmn" (part of the text we pasted minus the number of letters the whole
* after_change_text goes over the 10 letter limit) +
* (3) "gh" (last part of before_change_text that wasn't selected)
*
* so the new text has to be "abijkmngh"
*/
TextWatcher textWatcher = new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
// get before_change_text if textWatcher isn't blocked
if (!mWatcherIsBlocked) mBeforeChange = s.toString();
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
if (!mWatcherIsBlocked){
// get after_change_text if textWatcher isn't blocked
String after = s.toString();
// if after_change_text's length is bigger than the limit
if (after.length() > maxLength) {
// see how much it goes over the limit
int over = after.length() - maxLength;
// add parts (1) and (2) like our example above
String st = mBeforeChange.substring(0, start) + // (1)
after.substring(start, start + count - over); // (2)
// get where the cursor position should be after pasting (
// = after the last letter we could paste = length of (1) + (2) )
mCursorPosition = st.length();
// now add part (3) of our text to the first two
st += mBeforeChange.substring(
mBeforeChange.length() - (maxLength - st.length()),
mBeforeChange.length());
// now assign this new text to a global variable
mFilteredString = st;
} else {
// if after_change_text hasn't gone over the limit assign it
// directly to our global variable
mFilteredString = s.toString();
}
}
}
@Override
public void afterTextChanged(Editable s) {
// if filtered text is not the same as unfiltered text
// or textWatcher is not blocked
if (!mFilteredString.equals(s.toString()) && !mWatcherIsBlocked) {
// block textWatcher to avoid infinite loops created by setText
// (this might not work as I well as I think!)
mWatcherIsBlocked = true;
// set new text to our EditText
editText.setText(mFilteredString);
// set its cursor position
editText.setSelection(mCursorPosition);
// unblock the textWatcher
mWatcherIsBlocked = false;
}
}
};
// add the TextWatcher to our EditText
editText.addTextChangedListener(textWatcher);