Android TextInputLayout 예제

이 튜토리얼에서는 Android TextInputLayout이 제공하는 기능을 자세히 살펴보겠습니다. Android TextInputLayout은 Material Design Support Library와 함께 제공되는 디자인 컴포넌트입니다.

Android TextInputLayout

Android TexInputLayout은 LinearLayout을 확장합니다. TextInputLayout의 주요 용도는 EditText(또는 해당 하위 항목)을 래퍼로 사용하여 부동 힌트 애니메이션을 활성화하는 것입니다. 규칙: TextInputLayout은 일반 EditText 대신 TextInputEditText을 래핑해야 합니다. 이유? TextInputEditText은 EditText의 하위 클래스로 TextInputLayout의 자식으로 사용하기 위해 설계되었습니다. 또한 EditText를 사용하면 경고가 표시됩니다. : EditText added is not a TextInputEditText. Please switch to using that class instead. TextInputLayout은 부동 힌트 레이블만 표시하는 것 이상의 기능을 제공합니다.

Android TextInputLayout 기능

이 튜토리얼에서 다룰 일부 기능은 다음과 같습니다 :

  1. 부동 힌트 활성화/비활성화
  2. 부동 힌트 애니메이션 활성화/비활성화
  3. 오류 메시지 표시
  4. 문자 카운터 표시
  5. 사용자에게 캐릭터 카운트가 제한을 초과했을 때 경고하기
  6. 부동 힌트, 오류 레이블, 캐릭터 카운터의 텍스트 모양을 사용자 정의하기
  7. 비밀번호 가시성 토글

우리는 각 기능을 살펴보고 안드로이드 스튜디오 프로젝트에 구현할 것입니다.

안드로이드 TextInputLayout 예제 프로젝트 구조

이것은 단일 활동 애플리케이션입니다. 우리는 레이아웃, 활동 및 styles.xmlcolors.xml 파일 내에서 모든 작업을 수행할 것입니다. 먼저 아래와 같이 build.gradle 파일 내에 디자인 지원 라이브러리의 종속성을 추가하십시오.

compile 'com.android.support:design:25.3.1'

부동 힌트 사용/사용 안 함

TextInputLayout에서 부동 힌트는 기본적으로 활성화됩니다. 비활성화하려면 다음 속성을 태그 안에 추가해야 합니다: app:hintEnabled="false". 아래 XML 코드는 activity_main.xml 레이아웃에서 가져온 것이며 세 개의 EditText 필드가 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">


        <android.support.design.widget.TextInputEditText
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            android:hint="TextInputEditText" />


        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/activity_horizontal_margin">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Floating Hint Enabled Default" />

        </android.support.design.widget.TextInputLayout>


        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:hintEnabled="false">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Floating Hint Disabled" />

        </android.support.design.widget.TextInputLayout>

</LinearLayout>
</ScrollView>

세 번째 EditText 필드에는 떠다니는 힌트가 비활성화되어 있습니다. 위의 코드의 출력을 확인해 봅시다:

이전 기능과 유사하게, 떠다니는 힌트 애니메이션은 기본적으로 활성화되어 있습니다. 비활성화하려면 TextInputLayout 태그 내에 다음 속성을 추가해야 합니다. app:hintAnimationEnabled="false" 아래의 XML 코드는 activity_main.xml 레이아웃에서 가져온 것으로, 두 가지 경우 중 하나에 대한 EditText 필드가 포함되어 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/activity_horizontal_margin">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Floating Hint Enabled Default" />

        </android.support.design.widget.TextInputLayout>


        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:hintAnimationEnabled="false">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Hint Animation Disabled" />

        </android.support.design.widget.TextInputLayout>

</LinearLayout>
</ScrollView>

위의 코드의 출력은 아래에 표시되어 있습니다. 주목할 점은 두 번째 EditText 필드가 포커스될 때 떠다니는 힌트를 애니메이트하지 않는다는 것입니다.

힌트 TextAppearance 스타일링

사용자 정의 textColortextSize를 힌트에 적용하려면 다음 속성을 사용합니다: app:hintTextAppearance="@style/HintText". HintText 스타일은 다음과 같이 styles.xml 내부에 작성됩니다.

<style name="HintText" parent="TextAppearance.Design.Hint">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/colorPrimary</item>
    </style>

아래 XML 코드는 activity_main.xml 레이아웃에서 가져온 것으로, 힌트 텍스트가 있는지 여부에 따라 EditText 필드가 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/activity_horizontal_margin">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Floating Hint Enabled" />

        </android.support.design.widget.TextInputLayout>


        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:hintTextAppearance="@style/HintText">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Custom Hint TextAppearance" />

        </android.support.design.widget.TextInputLayout>

</LinearLayout>
</ScrollView>

위 코드의 출력은 아래와 같습니다.

글자 카운터

글자 카운터는 많은 애플리케이션에서 사용하는 기능입니다. (Twitter 글자 제한을 기억하십니까?). TextInputLayout에 표시할 최대 글자 수를 지정하려면 app:counterEnabledtrue로 설정하고 app:counterMaxLength를 원하는 최대 글자 수로 설정하십시오. 글자 카운터는 기본적으로 EditText 하단 오른쪽에 표시되며 이 튜토리얼을 작성하는 동안 위치를 변경하는 방법은 아직 없습니다. 카운터 스타일링은 힌트 텍스트 스타일링과 유사합니다. 이번에는 app:counterTextAppearance 속성이 사용됩니다. 프로젝트의 styles.xml 파일에 다음 스타일을 추가했습니다.

<style name="CounterText" parent="TextAppearance.Design.Counter">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/my_pink</item>
    </style>

아래 XML 코드는 activity_main.xml 레이아웃에서 가져온 것으로, 기본 글자 카운터와 사용자 정의 글자 카운터가 있는 EditText 필드가 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:hintTextAppearance="@style/HintText">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Character Counter Limit 10" />

        </android.support.design.widget.TextInputLayout>


        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:counterTextAppearance="@style/CounterText"
            app:hintTextAppearance="@style/HintText">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Character Counter Custom TextAppearance" />

        </android.support.design.widget.TextInputLayout>

</LinearLayout>
</ScrollView>

“위 코드의 출력은 다음과 같습니다. 위 출력을 주의 깊게 살펴보겠습니다.

  • 첫 번째 edittext 필드는 문자 수가 초과될 때 카운터 텍스트 색상, 힌트 텍스트 색상, 및 표시기 색상을 변경합니다.
  • 두 번째 edittext 필드도 동일하게 수행하지만 카운터 사용자 지정 텍스트 색상사용자 지정 텍스트 크기를 초과할 때 변경합니다.

문자 카운터가 제한을 초과하는 경우 스타일을 지정하려면 다음에 볼 counterflow 속성을 사용해야 합니다.

문자 카운터 오버플로우

위에서 보았듯이 문자 수가 정의된 제한을 초과하면 카운터 텍스트는 counterflow에서 정의된 속성을 사용합니다. 속성이 없으면 위의 출력에서 본 것처럼 기본 속성을 유지합니다. 다음 매개변수 app:counteroverflowtextappearance를 사용해야 합니다. counteroverflow의 스타일은 styles.xml 내에 있습니다 :

 <style name="CounterOverFlow" parent="TextAppearance.Design.Counter.Overflow">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/my_orange</item>
    </style>

이전 activity_main.xml 레이아웃에 아래 코드 스니펫을 추가하십시오.”

<android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:counterOverflowTextAppearance="@style/CounterOverFlow"
            app:counterTextAppearance="@style/CounterText"
            app:hintTextAppearance="@style/HintText">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="CounterOverflow CustomTextAppearance" />

        </android.support.design.widget.TextInputLayout>

애플리케이션을 다시 실행합시다.

Error Label

app:errorEnabledtrue로 설정하면 EditText 필드 아래 조건에 따라 오류 텍스트를 표시할 수 있습니다. 오류 텍스트를 스타일링하려면 app:errorTextAppearance 속성을 사용하고 styles.xml 파일 내에서 다음 코드를 추가합니다.

<style name="ErrorText" parent="TextAppearance.Design.Error">
        <item name="android:textSize">16sp</item>
        <item name="android:textColor">@color/my_black</item>
    </style>

아래의 XML 코드는 activity_main.xml 레이아웃에서 가져온 것으로 기본 오류 라벨과 사용자 지정 라벨에 대한 EditText 필드가 포함되어 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.design.widget.TextInputLayout
            android:id="@+id/errorInputLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:counterOverflowTextAppearance="@style/CounterOverFlow"
            app:counterTextAppearance="@style/CounterText"
            app:errorEnabled="true"
            app:hintTextAppearance="@style/HintText">

            <android.support.design.widget.TextInputEditText
                android:id="@+id/errorEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Default Error Label" />

        </android.support.design.widget.TextInputLayout>


        <android.support.design.widget.TextInputLayout
            android:id="@+id/customErrorInputLayout"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:counterOverflowTextAppearance="@style/CounterOverFlow"
            app:counterTextAppearance="@style/CounterText"
            app:errorEnabled="true"
            app:errorTextAppearance="@style/ErrorText"
            app:hintTextAppearance="@style/HintText">

            <android.support.design.widget.TextInputEditText
                android:id="@+id/customErrorEditText"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Custom Error Label" />

        </android.support.design.widget.TextInputLayout>

</LinearLayout>
</ScrollView>

오류 텍스트를 표시하려면 MainActivity.java 클래스에서 TextInputLayout의 인스턴스에서 setError(String) 메서드를 호출해야 합니다.

package com.journaldev.featuresoftextinputlayout;

import android.support.design.widget.TextInputEditText;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.text.Editable;
import android.text.TextWatcher;

public class MainActivity extends AppCompatActivity {


    TextInputLayout errorInputLayout, customErrorInputLayout;
    TextInputEditText errorEditText, customErrorEditText;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        errorEditText = (TextInputEditText) findViewById(R.id.errorEditText);
        errorInputLayout = (TextInputLayout) findViewById(R.id.errorInputLayout);

        customErrorEditText = (TextInputEditText) findViewById(R.id.customErrorEditText);
        customErrorInputLayout = (TextInputLayout) findViewById(R.id.customErrorInputLayout);

        errorEditText.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) {

                if (s.length() > errorInputLayout.getCounterMaxLength())
                    errorInputLayout.setError("Max character length is " + errorInputLayout.getCounterMaxLength());
                else
                    errorInputLayout.setError(null);

            }
        });

        customErrorEditText.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) {

                if (s.length() > customErrorInputLayout.getCounterMaxLength())
                    customErrorInputLayout.setError("Max character length is " + customErrorInputLayout.getCounterMaxLength());
                else
                    customErrorInputLayout.setError(null);

            }
        });


    }
}

위의 코드에서는 각 TextInputEditText 인스턴스에 TextChangedListener(TextWatcher를 구현한)를 추가합니다. 현재 문자 수가 카운터 최대 제한을 초과하면 오류 레이블을 표시합니다. 오류 레이블을 지우려면 setError() 내부에 값을 null로 설정합니다. 위의 코드가 생성하는 출력은: 참고: 텍스트 필드의 표시기는 오류 레이블과 동일한 색상을 사용합니다. 이는 counterOverflow에 의해 설정된 색상을 무시하므로 최우선 순위를 갖습니다.

비밀번호 가시성 토글

app:passwordToggleEnabledtrue로 설정하면 비밀번호를 표시/숨김할 수 있습니다. 아이콘 색상을 변경하려면 app:passwordToggleTint를 사용하세요. 아래 XML 코드는 비밀번호 가시성 토글을 위한 activity_main.xml 레이아웃에서 기본 아이콘 및 틴트가 있는 EditText 필드를 가지고 있습니다.

<?xml version="1.0" encoding="utf-8"?>
<ScrollView xmlns:android="https://schemas.android.com/apk/res/android"
    xmlns:app="https://schemas.android.com/apk/res-auto"
    xmlns:tools="https://schemas.android.com/tools"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    tools:context="com.journaldev.featuresoftextinputlayout.MainActivity">

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:orientation="vertical">

        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:counterOverflowTextAppearance="@style/CounterOverFlow"
            app:counterTextAppearance="@style/CounterText"
            app:hintTextAppearance="@style/HintText"
            app:passwordToggleEnabled="true">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Password Visibility Toggle"
                android:inputType="textPassword" />

        </android.support.design.widget.TextInputLayout>


        <android.support.design.widget.TextInputLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_margin="@dimen/activity_horizontal_margin"
            app:counterEnabled="true"
            app:counterMaxLength="5"
            app:counterOverflowTextAppearance="@style/CounterOverFlow"
            app:counterTextAppearance="@style/CounterText"
            app:hintTextAppearance="@style/HintText"
            app:passwordToggleEnabled="true"
            app:passwordToggleTint="@color/my_orange">

            <android.support.design.widget.TextInputEditText
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:hint="Password Visibility Toggle Tint"
                android:inputType="textPassword" />

        </android.support.design.widget.TextInputLayout>
</LinearLayout>
</ScrollView>

주의: app:passwordToggleDrawable를 사용하여 암호 표시 토글에서 자체 사용자 정의 아이콘을 사용할 수 있습니다. 이 튜토리얼은 여기서 끝납니다. TextInputLayout에 있는 모든 주요 기능을 다루었습니다. 아래 링크에서 Android TextInputLayout 예제 프로젝트를 다운로드할 수 있습니다. 이 링크에는 위의 각 코드 스니펫이 포함되어 있습니다.

Android TextInputLayout 프로젝트 다운로드

참고: Android 공식 문서

Source:
https://www.digitalocean.com/community/tutorials/android-textinputlayout-example