轉載請注明,大飛:http://blog.csdn.net/rflyee/article/details/38856539
(1)不同語言字符(英文、中文等)處理方式
(2)輸入字符達到數目后,是否仍然同意用戶輸入
第一點,涉及的東東事實上蠻多,不同語言在不同編碼中占領字節數等,不同語言在U8等編碼的表示范圍等,這一整塊知識非常豐富,自己臨時沒有理的特別順。稍后整理再說吧。
第二點。眼下主流app的處理方案也各有不同,qq5.0曾經的版本號,發表說說貌似是沒有字數限制的(我試了一個350字左右的照樣發),5.0以后限制了,這樣假設用戶輸入字數超過限制便顯示負數,可是仍然同意用戶輸入,就是不能發表了。這樣就把處理權所有交給用戶了,事實上更省事了!
方法一:
布局中限制。
android:maxLength="10" // 即限制最大輸入字符個數為10。(1)中英文都算一個字符。
(2)字數到,不能輸入
方法二:
InputFilter限制,同布局中限制類似。
editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(10)});(1)中英文都算一個字符。
(2)字數到。不能輸入
方法三:
TextWatcher限制。
這里假設字數達到限制仍然同意用戶輸入的情況不多說,好實現。
crash問題:使用搜狗輸入法時,在字數將要或者已經達到限制之后,一次輸入大量中文(不按空格,一直打字。知道搜狗的緩存字符達到上限)。 crash。stackoverflow 內存溢出。呵呵,百度輸入法不會哈。
方案一,中文按兩個,英文按一個。個數到限制,用戶不能輸入
private TextWatcher textWatcher = new TextWatcher() {
private int editStart;
private int editEnd;
private int maxLen = 10; // the max byte
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
Log.d("TextChanged", "---->beforeTextChanged : start = " + start + " count = " + count + " after = " + after);
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
editStart = opinion.getSelectionStart();
editEnd = opinion.getSelectionEnd();
// 先去掉監聽器,否則會出現棧溢出
opinion.removeTextChangedListener(textWatcher);
if (!TextUtils.isEmpty(opinion.getText())) {
String etstring = opinion.getText().toString().trim();
while (calculateLength(s.toString()) > maxLen) {
s.delete(editStart - 1, editEnd);
editStart--;
editEnd--;
Log.d("TextChanged", "editStart = " + editStart + " editEnd = " + editEnd);
}
}
opinion.setText(s);
opinion.setSelection(editStart);
// 恢復監聽器
opinion.addTextChangedListener(textWatcher);
// end by zyf --------------------------
}
private int calculateLength(String etstring) {
char[] ch = etstring.toCharArray();
int varlength = 0;
for (int i = 0; i < ch.length; i++) {
// changed by zyf 0825 , bug 6918,增加中文標點范圍 , TODO 標點范圍有待詳細化
if ((ch[i] >= 0x2E80 && ch[i] <= 0xFE4F) || (ch[i] >= 0xA13F && ch[i] <= 0xAA40) || ch[i] >= 0x80) { // 中文字符范圍0x4e00 0x9fbb
varlength = varlength + 2;
} else {
varlength++;
}
}
Log.d("TextChanged", "varlength = " + varlength);
// 這里也能夠使用getBytes,更准確嘛
// varlength = etstring.getBytes(CharSet.forName("GBK")).lenght;// 編碼依據自己的需求,注意u8中文占3個字節...
return varlength;
}
};
補加:
事實上在字符超出的情況下不一個一個刪。而是將多余字符一次性全刪掉。就可以避免內存溢出的問題,例如以下面方式。(暫未在afterTextChanged處理驗證。可自行嘗試,興許補上)。方案二同理,僅僅只是處理截取方式不同罷了。(注:中英字符問題如以上方案自行處理)
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
String str = s.toString();
if (length > maxNum) {
ToastUtil.show(mContext, "超出字數限制!");
str = str.substring(0, maxNum);
etContent.setText(str);
etContent.setSelection(str.length());
}
}
方案二
// 達到限制字數后,假設在文字中間輸入文字或者空格。最后的字符會被刪除
titleTv.addTextChangedListener(new TextWatcher() {
@Override
public void beforeTextChanged(CharSequence s, int start, int count, int after) {
}
@Override
public void onTextChanged(CharSequence s, int start, int before, int count) {
}
@Override
public void afterTextChanged(Editable s) {
// add by zyf 0825 . 多余的從新輸入的位置刪除,而不是最后
editStart = opinion.getSelectionStart();
editEnd = opinion.getSelectionEnd();
if (!TextUtils.isEmpty(titleTv.getText())) {
int varlength = 0;
int size = 0;
String etstring = titleTv.getText().toString().trim();
char[] ch = etstring.toCharArray();
for (int i = 0; i < ch.length; i++) {
size++;
if (ch[i] >= 0x4e00 && ch[i] <= 0x9fbb) {
varlength = varlength + 2;
} else
varlength++;
if (varlength > 80) {
break;
}
}
if (varlength > 80) {
s.delete(size - 1, etstring.length());
// add by zyf 0825 . 多余的從新輸入的位置刪除,而不是最后
// s.delete(editStart - 1, editEnd); // crash stackoverflow,解決方法參考上邊方案一
}
}
}
});
轉載請注明,大飛: http://blog.csdn.net/rflyee/article/details/38856539
