65.9K
CodeProject 正在变化。 阅读更多。
Home

Android Material Design:使用浮动标签 EditText

starIconstarIconstarIconstarIconemptyStarIcon

4.00/5 (6投票s)

2016年7月17日

CPOL

4分钟阅读

viewsIcon

24602

Android Material Design:使用浮动标签 EditText

为了获取用户输入,我们都会使用 EditText。我们可以向用户提供一个提示,说明在特定的 EditText 中应该输入什么。然而,一旦用户开始输入,提示就会消失。有时,这会导致应用程序用户混淆,忘记他们正在与哪个字段进行交互。不过,为了拯救 Android 开发者,Material Design 库引入了 **浮动标签 EditText**。它最初将标签显示为提示,但当用户开始在 EditText 中输入值时,如名称所示,该提示会变成一个浮动标签。

在本教程中,我们将讨论如何使用 Material Design 库实现 Android 浮动标签 EditText。

通过将 android.support.design.widget.TextInputLayout 包装在 EditText 周围来实现 **浮动标签 EditText**。TextInputLayout 是一个专门用于包装 EditText 并渲染浮动标签的控件。我们还使用它的函数来显示其包围的特定 EditText 的错误。

先决条件

  1. 您的 PC(Unix 或 Windows)上安装了 Android Studio。
  2. 一台配置了 Android Studio 的真实 Android 设备(智能手机或平板电脑)。

创建新项目并添加 Material Design 库

    compile 'com.android.support:design:23.0.0'
  1. 转到 **文件 → 新建 → 新建项目**,然后输入你的应用程序名称。
  2. 输入公司域名,这用于在全球范围内唯一标识你的应用程序包。
  3. 选择项目位置和最低 SDK,然后在下一个屏幕上选择 **空 Activity**,因为我们将自己添加大部分代码。然后,点击“下一步”。
  4. 选择一个 Activity 名称。确保“生成布局文件”复选框已选中,否则我们必须自己生成它。然后,点击“完成”。我们选择的 Activity 名称是 SignUpActivity,因为我们正在模仿几乎所有应用程序中使用的注册页面。这是 **浮动标签 EditText** 的最佳用例。
  5. 要为项目添加 TextInputLayout 支持,请在应用程序的 build.gradle 文件中添加以下依赖项。
  6. Gradle 将配置你的项目并解析依赖项。完成后,继续下一步。

我们将为这个 Android **浮动标签 EditText** 示例创建一个虚拟注册页面。我们将使用 EditTexts,每个 EditText 都将包装在 TextInputLayout 中。完成后,布局将如下图所示。

Floating Label Edit Text Tutorial

添加布局

打开 activity_sign_up.xml 并添加以下代码。

activity_sign_up.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center"
    android:orientation="vertical"
    android:padding="10dp" >

    <LinearLayout
        android:layout_width="match_parent"
        android:layout_height="wrap_content"
        android:layout_gravity="center"
        android:orientation="vertical"
        android:paddingLeft="20dp"
        android:paddingRight="20dp" >
        <android.support.design.widget.TextInputLayout
            android:id="@+id/signup_input_layout_name"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp">

            <EditText
                android:id="@+id/signup_input_name"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="10"
                android:hint="Name"/>
        </android.support.design.widget.TextInputLayout>
        <android.support.design.widget.TextInputLayout
            android:id="@+id/signup_input_layout_email"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp">
            <EditText
                android:id="@+id/signup_input_email"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="10"
                android:inputType="textEmailAddress"
                android:hint="Email" />
        </android.support.design.widget.TextInputLayout>
        <android.support.design.widget.TextInputLayout
            android:id="@+id/signup_input_layout_password"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp">
            <EditText
                android:id="@+id/signup_input_password"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="10"
                android:inputType="textPassword"
                android:hint="@string/hint_password" />
        </android.support.design.widget.TextInputLayout>
        <android.support.design.widget.TextInputLayout
            android:id="@+id/signup_input_layout_dob"
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:layout_centerHorizontal="true"
            android:layout_marginTop="10dp">
            <EditText
                android:id="@+id/signup_input_dob"
                android:layout_width="match_parent"
                android:layout_height="wrap_content"
                android:ems="10"
                android:singleLine="true"
                android:hint="@string/hint_dob"/>
        </android.support.design.widget.TextInputLayout>
        <RelativeLayout
            android:layout_width="match_parent"
            android:layout_height="wrap_content"
            android:paddingTop="20dp">
            <TextView
                android:id="@+id/gender_textview"
                android:paddingRight="15dp"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="@string/hint_gender"
                android:fontFeatureSettings="@string/hint_password"
                android:textSize="20dp"
                android:fontFamily="@string/hint_password"/>
            <RadioGroup
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:layout_toRightOf="@+id/gender_textview"
                android:orientation="horizontal"
                >
                <RadioButton
                    android:id="@+id/male_radio_btn"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text="@string/male"
                    android:checked="true"
                    />
                <RadioButton
                    android:id="@+id/female_radio_btn"
                    android:layout_width="wrap_content"
                    android:layout_height="wrap_content"
                    android:text = "@string/female"
                    />
            </RadioGroup>
        </RelativeLayout>
        <Button android:id="@+id/btn_signup"
            android:layout_width="fill_parent"
            android:layout_height="wrap_content"
            android:text="@string/btn_sign_up"
            android:background="@color/colorPrimaryDark"
            android:layout_marginTop="40dp"
            android:textColor="@android:color/white"/>
    </LinearLayout>
</LinearLayout>

上面的布局非常直观,我们有用于姓名、电子邮件、密码和出生日期的 EditText,然后我们有一个 RadioGroup 用于获取性别输入。这些是你从用户那里获取以在你的应用程序或网站上注册她的典型输入。最后,我们有一个 **注册!!** 按钮,用于提交按钮。

添加功能

SignUpActivity.java 中,我们首先声明 EditTextTextInputLayout 的变量。

打开 SignUpActivity.java 并添加以下代码。

package com.androidtutorialpoint.floatinglabeledittext;

import android.content.Context;
import android.os.Bundle;
import android.os.Vibrator;
import android.support.design.widget.TextInputLayout;
import android.support.v7.app.AppCompatActivity;
import android.text.Editable;
import android.text.TextUtils;
import android.text.TextWatcher;
import android.view.View;
import android.view.WindowManager;
import android.view.animation.Animation;
import android.view.animation.AnimationUtils;
import android.widget.Button;
import android.widget.EditText;
import android.widget.Toast;


public class SignUpActivity extends AppCompatActivity {

    private static final String TAG = "RegisterActivity";
    private Vibrator vib;
    Animation animShake;
    private EditText signupInputName, signupInputEmail, signupInputPassword, signupInputDOB;
    private TextInputLayout signupInputLayoutName, signupInputLayoutEmail, 
                            signupInputLayoutPassword,signupInputLayoutDOB;
    private Button btnSignUp;

现在我们在 SignUpActvity.javaOnCreate() 方法中引用这些控件。

@Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_sign_up);
        signupInputLayoutName = (TextInputLayout) findViewById(R.id.signup_input_layout_name);
        signupInputLayoutEmail = (TextInputLayout) findViewById(R.id.signup_input_layout_email);
        signupInputLayoutPassword = (TextInputLayout) findViewById(R.id.signup_input_layout_password);
        signupInputLayoutDOB = (TextInputLayout) findViewById(R.id.signup_input_layout_dob);

        signupInputName = (EditText) findViewById(R.id.signup_input_name);
        signupInputEmail = (EditText) findViewById(R.id.signup_input_email);
        signupInputPassword = (EditText) findViewById(R.id.signup_input_password);
        signupInputDOB = (EditText) findViewById(R.id.signup_input_dob);
        btnSignUp = (Button) findViewById(R.id.btn_signup);

        animShake = AnimationUtils.loadAnimation(getApplicationContext(),R.anim.shake);
        vib = (Vibrator) getSystemService(Context.VIBRATOR_SERVICE);

        btnSignUp.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                submitForm();
            }
        });
    }

请注意,在输入无效的情况下,我们使用了动画来摇动 EditText。要添加动画,请在 values 文件夹中创建一个动画资源文件并添加以下文件

shake.xml

<?xml version="1.0" encoding="utf-8"?>
<set xmlns:android="http://schemas.android.com/apk/res/android"
    android:interpolator="@android:anim/overshoot_interpolator"
    android:fillAfter="true">

    <translate
        android:startOffset="100"
        android:fromXDelta="0%p"
        android:toXDelta="5%p"
        android:duration="100" />

    <translate
        android:startOffset="150"
        android:fromXDelta="0%p"
        android:toXDelta="-10%p"
        android:duration="160" />


    <translate
        android:startOffset="260"
        android:fromXDelta="0%p"
        android:toXDelta="10%p"
        android:duration="170" />


    <translate
        android:startOffset="380"
        android:fromXDelta="0%p"
        android:toXDelta="-10%p"
        android:duration="180" />


    <translate
        android:startOffset="510"
        android:fromXDelta="0%p"
        android:toXDelta="5%p"
        android:duration="140" />

</set>

当输入无效时,EditText 将会晃动,手机也会震动以提醒用户错误。要添加 **震动** 功能,请在 AndroidManifest.xml 中添加以下权限。

AndroidManifest.xml

    <uses-permission android:name="android.permission.VIBRATE"></uses-permission>

OnClickListener 中,我们调用 submitForm() 函数,该函数将验证用户输入并在发现无效数据时抛出错误。

SignUpActvity.javaonCreate() 方法之后添加以下代码。

SignUpActivity.java

private void submitForm() {

        if (!checkName()) {
            signupInputName.setAnimation(animShake);
            signupInputName.startAnimation(animShake);
            vib.vibrate(120);
            return;
       }
        if (!checkEmail()) {
            signupInputEmail.setAnimation(animShake);
            signupInputEmail.startAnimation(animShake);
            vib.vibrate(120);
            return;
        }
        if (!checkPassword()) {
            signupInputPassword.setAnimation(animShake);
            signupInputPassword.startAnimation(animShake);
            vib.vibrate(120);
            return;
        }
        if (!checkDOB()) {
            signupInputDOB.setAnimation(animShake);
            signupInputDOB.startAnimation(animShake);
            vib.vibrate(120);
            return;
        }
        signupInputLayoutName.setErrorEnabled(false);
        signupInputLayoutEmail.setErrorEnabled(false);
        signupInputLayoutPassword.setErrorEnabled(false);
        signupInputLayoutDOB.setErrorEnabled(false);
        Toast.makeText(getApplicationContext(), 
        "You are successfully Registered !!", Toast.LENGTH_SHORT).show();
    }

    private boolean checkName() {
        if (signupInputName.getText().toString().trim().isEmpty()) {

            signupInputLayoutName.setErrorEnabled(true);
            signupInputLayoutName.setError(getString(R.string.err_msg_name));
            signupInputName.setError(getString(R.string.err_msg_required));
            return false;
        }
        signupInputLayoutName.setErrorEnabled(false);
        return true;
    }

    private boolean checkEmail() {
        String email = signupInputEmail.getText().toString().trim();
        if (email.isEmpty() || !isValidEmail(email)) {

            signupInputLayoutEmail.setErrorEnabled(true);
            signupInputLayoutEmail.setError(getString(R.string.err_msg_email));
            signupInputEmail.setError(getString(R.string.err_msg_required));
            requestFocus(signupInputEmail);
            return false;
        }
        signupInputLayoutEmail.setErrorEnabled(false);
        return true;
    }

    private boolean checkPassword() {
        if (signupInputPassword.getText().toString().trim().isEmpty()) {

            signupInputLayoutPassword.setError(getString(R.string.err_msg_password));
            requestFocus(signupInputPassword);
            return false;
        }
            signupInputLayoutPassword.setErrorEnabled(false);
           return true;
    }

    private boolean checkDOB() {

        try {
            boolean isDateValid = false;
            String[] s = signupInputDOB.getText().toString().split("/");
            int date = Integer.parseInt(s[0]);
            int month = Integer.parseInt(s[1]);

            if (date < 32 && month < 13)
                isDateValid = true;

            if (signupInputDOB.getText().toString().trim().isEmpty() && isDateValid) {

                signupInputLayoutDOB.setError(getString(R.string.err_msg_dob));
                requestFocus(signupInputDOB);
                signupInputDOB.setError(getString(R.string.err_msg_required));

                return false;
            }
        }catch(Exception ex){
            signupInputLayoutDOB.setError(getString(R.string.err_msg_dob));
            requestFocus(signupInputDOB);
            return false;
        }

        signupInputDOB.setError(null);
        return true;
    }

    private static boolean isValidEmail(String email) {
        return !TextUtils.isEmpty(email) && 
        android.util.Patterns.EMAIL_ADDRESS.matcher(email).matches();
    }

    private void requestFocus(View view) {
        if (view.requestFocus()) {
            getWindow().setSoftInputMode(WindowManager.LayoutParams.SOFT_INPUT_STATE_ALWAYS_VISIBLE);
        }
    }

submitForm() 方法使用辅助方法 checkName()checkEmail()checkPassword()checkDOB() 来检查姓名、电子邮件、密码和出生日期是否存在。它还检查输入的电子邮件和出生日期是否有效。

让我们简要讨论一下这些方法。

  1. checkName() – 检查必需的姓名字段是否存在。否则,它会在 signupInputLayoutName 上调用 setErrorEnabled(true) 来通知有错误,并调用 setError(getString(R.string.err_msg_name)) 来为 signupInputLayoutName 设置错误消息。此外,我们还使用 setError(getString(R.string.err_msg_required)) 方法为 EditText 设置了错误。然后,我们向 submitForm() 返回 false,以便它调用摇动动画。
  2. checkEmail() – 此方法与 checkName() 方法类似,它额外调用 isValidEmail() 来检查输入的电子邮件是否有效。
  3. checkPassword() – 此方法也与 checkName() 方法类似。它检查 Password 字段是否为空。如果为空,它将引发错误并返回 false
  4. checkDOB() – 此方法检查用户输入的出生日期是否有效。

我们使用了以下 string 资源。

strings.xml

<resources>
    <string name="app_name">FloatingLabelEditText</string>
    <string name="hint_dob">Enter D.O.B (DD/MM/YYYY)</string>
    <string name="hint_password">Password</string>
    <string name="hint_gender">I am</string>
    <string name="male">Male</string>
    <string name="female">Female</string>
    <string name="btn_sign_up">Sign Up !!</string>
    <string name="err_msg_name">Please enter a Name</string>
    <string name="err_msg_required">Valid Input Required</string>
    <string name="err_msg_email">Please enter a Valid Email</string>
    <string name="err_msg_password">Enter a Password</string>
    <string name="err_msg_dob">Enter a valid D.O.B</string>
</resources>

现在运行应用程序并测试所有验证是否触发。你必须测试不同的测试用例,以测试电子邮件和出生日期验证是否正确。希望你喜欢这个 Material Design 浮动标签编辑文本示例教程。

© . All rights reserved.