圖片發(fā)自簡書App
輸入手機號時玻靡,為了看著更加方便可能會顯示成xxx xxxx xxxx
剃浇,如圖
為了這個需求律适,自己簡單的研究了一下,寫了個這個小東西自己練練思維
簡單來看就是按照3-4-4來分割淆衷,通過添加addTextChangedListener()
就能獲得文本修改的值,可以在afterTextChanged(Editable s)
方法中處理就行了渤弛,主要就是在對應的位置添加分隔符就OK了
private StringBuffer mStringBuffer = new StringBuffer();
/** 分割符 */
private char separator = ' ';
/** 分割符插入位置規(guī)則 */
private int[] RULES = {3, 4, 4};
@Override
public void afterTextChanged(Editable s) {
if (!TextUtils.equals(s, mStringBuffer)) {
mStringBuffer = new StringBuffer();
for (int i = 0, length = s.length(); i < length; i++) {
char c = s.charAt(i);
if (c != separator) {
mStringBuffer.append(c);
}
int standardPos = 0;
int offset = 0;
for (int pos : RULES) {
standardPos += pos + offset++;
if (mStringBuffer.length() == standardPos) {
mStringBuffer.append(separator);
break;
}
}
}
editText.setText(mStringBuffer);
}
}
這些代碼基本已經實現了主要功能祝拯,但是還有不少小問題,例如:
- 光標的位置問題
- 空格刪除問題
- ……
后續(xù)再處理這些問題的過程中進行了一些優(yōu)化,還擴展了一些使用方式佳头,最終是以實現TextWatcher
的方式來封裝的鹰贵,不說廢話,上代碼
public class AutoSeparateTextWatcher implements TextWatcher {
/***/
private StringBuffer mStringBuffer = new StringBuffer();
/** 分割符 */
private char separator = ' ';
/** 分割符插入位置規(guī)則 */
private int[] RULES = {3, 4, 4};
/** 最大輸入長度 */
private int MAX_INPUT_LENGTH;
/** EditText */
private EditText editText;
/** 最大輸入長度InputFilter */
private InputFilter.LengthFilter mLengthFilter;
/**
* @param editText 目標EditText
*/
public AutoSeparateTextWatcher(@NonNull EditText editText) {
this.editText = editText;
//更新輸入最大長度
setupMaxInputLength();
}
/**
* 設置分割規(guī)則
* @param RULES 分割規(guī)則數組
* 例如:138 383 81438的分割數組是{3,3,5}
*/
public void setRULES(@NonNull int[] RULES) {
this.RULES = RULES;
setupMaxInputLength();
String originalText = removeSpecialSeparator(editText, this.separator);
if (!TextUtils.isEmpty(originalText)) {
editText.setText(originalText);
editText.setSelection(editText.getText().length());
}
}
/**
* 設置分割符
* @param separator 分隔符康嘉,默認為空格
*/
public void setSeparator(char separator) {
String originalText = removeSpecialSeparator(editText, this.separator);
this.separator = separator;
if (!TextUtils.isEmpty(originalText)) {
editText.setText(originalText);
editText.setSelection(editText.getText().length());
}
}
public char getSeparator() {
return separator;
}
/** 更新最大輸入長度 */
private void setupMaxInputLength() {
MAX_INPUT_LENGTH = RULES.length - 1;
for (int value : RULES) {
MAX_INPUT_LENGTH += value;
}
//更新LengthFilter
InputFilter[] filters = editText.getFilters();
if (filters.length > 0 && mLengthFilter != null) {
//判斷editText的InputFilter中是否已經包含mLengthFilter
for (int i = 0; i < filters.length; i++) {
InputFilter filter = filters[i];
if (mLengthFilter == filter) {
mLengthFilter = new InputFilter.LengthFilter(MAX_INPUT_LENGTH);
filters[i] = mLengthFilter;
return;
}
}
}
addLengthFilter(filters);
}
/**
* @param filters
*/
private void addLengthFilter(InputFilter[] filters) {
if (filters == null) {
filters = new InputFilter[0];
}
InputFilter[] newFilters = new InputFilter[filters.length + 1];
System.arraycopy(filters, 0, newFilters, 0, filters.length);
mLengthFilter = new InputFilter.LengthFilter(MAX_INPUT_LENGTH);
newFilters[newFilters.length - 1] = mLengthFilter;
editText.setFilters(newFilters);
}
@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) {
if (!TextUtils.equals(s, mStringBuffer)) {
//刪除mStringBuffer中的文本
mStringBuffer.delete(0, mStringBuffer.length());
//添加分隔符
mStringBuffer.append(handleText(s, RULES, separator));
//刪除多余字符
if (mStringBuffer.length() > MAX_INPUT_LENGTH) {
mStringBuffer.delete(MAX_INPUT_LENGTH, mStringBuffer.length());
}
final int currSelectStart = editText.getSelectionStart();
//計算分隔符導致的光標offset
int separatorOffset = calculateSeparatorOffset(s, mStringBuffer, currSelectStart);
editText.setText(mStringBuffer);
//計算并設置當前的selectStart位置
int selectStart = currSelectStart + separatorOffset;
if (selectStart < 0) {
selectStart = 0;
} else if (selectStart > mStringBuffer.length()) {
selectStart = mStringBuffer.length();
}
editText.setSelection(selectStart);
}
}
/**
* 計算符號的offset
*
* @param before
* @param after
* @param selectionStart
*
* @return
*/
private int calculateSeparatorOffset(@NonNull CharSequence before, @NonNull CharSequence after, int selectionStart) {
int offset = 0;
final int beforeLength = before.length();
final int afterLength = after.length();
final int length = afterLength > beforeLength ? beforeLength : afterLength;
for (int i = 0; i < length; i++) {
if (i >= selectionStart) {
break;
}
char bc = before.charAt(i);
char ac = after.charAt(i);
if (bc == separator && ac != separator) {
offset--;
} else if (bc != separator && ac == separator) {
offset++;
}
}
return offset;
}
/**
* @param s
* @param rules
* @param separator
*
* @return
*/
public static String handleText(Editable s, int[] rules, char separator) {
StringBuffer stringBuffer = new StringBuffer();
for (int i = 0, length = s.length(); i < length; i++) {
char c = s.charAt(i);
if (c != separator) {
stringBuffer.append(c);
}
if (length != stringBuffer.length() && isSeparationPosition(rules, stringBuffer.length())) {
stringBuffer.append(separator);
}
}
return stringBuffer.toString();
}
/**
* @param RULES
* @param length
*
* @return
*/
private static boolean isSeparationPosition(int[] RULES, int length) {
if (RULES == null) {
return false;
}
int standardPos = 0;
int offset = 0;
for (int pos : RULES) {
standardPos += pos;
if (length == standardPos + offset++) {
return true;
}
}
return false;
}
/**
* @param editText
* @param specialSeparator
*
* @return
*/
public static String removeSpecialSeparator(EditText editText, char specialSeparator) {
if (editText == null) {
return null;
}
Editable text = editText.getText();
return text == null ? null : text.toString().replace(String.valueOf(specialSeparator), "");
}
}
這里提供了可以修改分割字符串規(guī)則和分割符的方法碉输,部分處理添加分割符合移除分割符的方法都做成了靜態(tài)方法,方便外面直接調用處理亭珍,可能在構造器傳入EditText
對象敷钾,可能會造成內存問題,這個暫時還沒有處理肄梨。
使用
TextWatcher
來封裝闰非,主要是因為最終還是要通過TextWatcher
來實現,那就沒有必要繼承EditText
來進行封裝峭范,降低了使用成本财松,添加一個TextWatcher
就能實現的事情,為什么要搞得那么復雜呢!
AutoSeparateTextWatcher
使用方式也比較簡單
EditText editText = findViewById(R.id.edit_text);
AutoSeparateTextWatcher textWatcher = new AutoSeparateTextWatcher(editText);
textWatcher.setRULES(new int[]{4,4,4,4});
textWatcher.setSeparator('-');
editText.addTextChangedListener(textWatcher);
如果發(fā)現有什么bug還請及時指出