/ EDITTEXT, ANDROID, UI

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);
kunny

커니

안드로이드와 오픈소스, 코틀린(Kotlin)에 관심이 많습니다. 한국 GDG 안드로이드 운영자 및 GDE 안드로이드로 활동했으며, 현재 구글에서 애드몹 기술 지원을 담당하고 있습니다.

Read More