EditText에 inputFilter와 maxLength를 함께 적용하려면?
사용자로부터 문자열 형태의 입력을 받으러면 EditText
를 사용해야 합니다. 이 때, 필요에 따라 사용자가 최대로 입력할 수 있는 문자열의 길이를 제한하기 위해 android:maxLength
속성을 사용합니다.
문자열의 길이 외에 다른 입력 제한 조건을 설정하지 않는다면, android:maxLength
에서 설정한 조건이 문제없이 적용됩니다. 하지만, 다른 입력 제한 조건을 설정하기 위해 InputFilter
를 사용한 경우 앞에서 설정한 조건이 무시됩니다.
이러한 현상은 android:maxLength
속성이 내부적으로 InputFilter
형태로 처리되기 때문에 발생합니다. 이와 관련된 내용은 공식 문서에서도 확인할 수 있습니다. 아래는 문서 내 XML 속성에 대한 설명 중 일부입니다.
Attribute name | Related Method | Description |
---|---|---|
android:maxLength | setFilters(InputFilter) | Set an input filter to constrain the text length to the specified number. |
조금 더 자세한 내용을 확인하기 위해 소스 코드 내부를 확인해 보겠습니다. InputFilter
를 처리하는 로직은 EditText
가 상속한 TextView
에 구현되어 있습니다. 다음은 TextView
의 생성자 중 일부입니다.
[frameworks/base/core/java/android/widget/TextView.java]
public TextView(
Context context, @Nullable AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
// ... 생략 ...
int n = a.getIndexCount();
for (int i = 0; i < n; i++) {
int attr = a.getIndex(i);
switch (attr) {
// ... 생략 ...
case com.android.internal.R.styleable.TextView_maxLength:
maxlength = a.getInt(attr, -1);
break;
// ... 생략 ...
}
}
// ... 생략 ...
if (maxlength >= 0) {
setFilters(new InputFilter[] { new InputFilter.LengthFilter(maxlength) });
} else {
setFilters(NO_FILTERS);
}
// ... 생략 ...
}
문서에 기술된 대로, android:maxLength
속성에서 지정한 값을 토대로 최대로 입력할 수 있는 문자열을 제한하는 필터(InputFilter.LengthFilter(int)
)를 필터로 지정하고 있습니다. 그렇다면, 왜 이 속성이 다른 InputFilter
와 함께 사용될 수 없는지 알아보기 위해 setFilters(InputFilter)
내부를 살펴보겠습니다.
[frameworks/base/core/java/android/widget/TextView.java]
public void setFilters(InputFilter[] filters) {
if (filters == null) {
throw new IllegalArgumentException();
}
mFilters = filters;
if (mText instanceof Editable) {
setFilters((Editable) mText, filters);
}
}
private void setFilters(Editable e, InputFilter[] filters) {
if (mEditor != null) {
final boolean undoFilter = mEditor.mUndoInputFilter != null;
final boolean keyFilter = mEditor.mKeyListener instanceof InputFilter;
int num = 0;
if (undoFilter) num++;
if (keyFilter) num++;
if (num > 0) {
InputFilter[] nf = new InputFilter[filters.length + num];
System.arraycopy(filters, 0, nf, 0, filters.length);
num = 0;
if (undoFilter) {
nf[filters.length] = mEditor.mUndoInputFilter;
num++;
}
if (keyFilter) {
nf[filters.length + num] = (InputFilter) mEditor.mKeyListener;
}
e.setFilters(nf);
return;
}
}
e.setFilters(filters);
}
내부 코드에서 알 수 있듯이, setFilters(InputFilter)
메서드를 사용하면 시스템 내부에서 별도로 사용하는 필터를 제외하고 기존의 필터를 완전히 대체합니다. 이 때문에 android:maxLength
속성과 setFilters(InputFilter)
는 함께 사용할 수 없으며, 항상 후자에서 지정한 값만 적용됩니다.
따라서, 입력할 수 있는 문자열의 길이 뿐 아니라 다른 필터를 추가하고 싶다면 android:maxLength
속성을 사용하지 말고 setFilters(InputFilter)
에 문자열 길이를 제한하는 필터를 추가하여 지정해야 합니다.
다음은 입력할 수 있는 문자열의 길이를 15개로 제한하면서 입력한 문자열을 대문자로 변환하는 필터를 적용하는 예제입니다.
EditText editText = (EditText) findViewById(R.id.edit_text_id);
// 문자열 길이를 제한하는 LengthFilter와 문자열을 대문자로 변환하는 AllCaps 필터를 추가합니다.
InputFilter[] filters = new InputFilter[]{
new InputFilter.LengthFilter(15),
new InputFilter.AllCaps()
};
// EditText에 필터를 적용합니다.
editText.setFilters(filters);