在設定Android App的時候,常常會需要讓使用者輸入一些文字,但又不想要讓使用者輸入太多文字,要怎麼樣才可以讓文字輸入框能夠限制使用者輸入的長度呢?如果使用者輸入的文字不是只有半形字,而是還有全形字的話,又該怎麼去計算文字長度呢?



以EditText這個View為例,如果要限制EditText輸入文字的最大長度,可以設定它的「maxLength」屬性。在XML下,可以替EditText加入這個屬性,並指定最大的文字長度。如下面的XML語法,將EditText的可輸入的最大字元數量限制在10個:

<EditText
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:maxLength="10" />

如果要用Android SDK的Java程式來寫,會比較麻煩一點,可以寫成這樣:

editText.setFilters(new InputFilter[]{new InputFilter.LengthFilter(10)});

用以上的方式雖然可以快速地限制EditText的文字長度,但是卻會發生半形字和全形字雖然數量一樣,長度看起來卻差很多的問題。如下圖:

此時可以使用以下的解決方案。

MagicTextLengthWatcher

import android.text.Editable;
import android.text.TextWatcher;

/**
 * 限制文字輸入的長度
 * 
 * @author magiclen
 *
 */
public class MagicTextLengthWatcher implements TextWatcher {

	private int maxLength; // 儲存最大的字串長度
	private int currentEnd = 0; // 儲存目前字串改變的結束位置,例如:abcdefg變成abcd1234efg,變化的結束位置就在索引8

	public MagicTextLengthWatcher(final int maxLength) {
		setMaxLength(maxLength);
	}

	public final void setMaxLength(final int maxLength) {
		if (maxLength >= 0) {
			this.maxLength = maxLength;
		} else {
			this.maxLength = 0;
		}
	}

	public int getMaxLength() {
		return this.maxLength;
	}

	@Override
	public void beforeTextChanged(final CharSequence s, final int start, final int count, final int after) {

	}

	@Override
	public void onTextChanged(final CharSequence s, final int start, final int before, final int count) {
		currentEnd = start + count; // 取得變化的結束位置
	}

	@Override
	public void afterTextChanged(final Editable s) {
		while (calculateLength(s) > maxLength) { // 若變化後的長度超過最大長度
			// 刪除最後變化的字元
			currentEnd--;
			s.delete(currentEnd, currentEnd + 1);
		}
	}

	/**
	 * 計算字串的長度
	 * 
	 * @param c
	 *            傳入字串
	 * 
	 * @return 傳回字串長度
	 */
	protected int calculateLength(final CharSequence c) {
		int len = 0;
		final int l = c.length();
		for (int i = 0; i < l; i++) {
			final char tmp = c.charAt(i);
			if (tmp >= 0x20 && tmp <= 0x7E) {
				// 字元值 32~126 是 ASCII 半形字元的範圍
				len++;
			} else {
				// 非半形字元
				len += 2;
			}
		}
		return len;
	}

}

使用MagicTextLengthWatcher這個TextWatcher,可以很輕易地限制EditText的文字長度。預設將一個半形字元的長度用1計算,一個全形字元的長度用2計算(一個全形字的長度等於兩個半形字的意思)。使用方式如下:

editText.addTextChangedListener(new MagicTextLengthWatcher(10));