Статьи

Создание экрана входа в систему с помощью TextInputLayout

Что вы будете создавать

В этом уроке я снова расскажу о дизайне материалов. Google I / O 2015 был важным событием для каждого разработчика Android, и дизайн, конечно же, был частью обсуждения.

Google понял, что обратная совместимость — самая сложная часть реализации дизайна материала. Конечно, библиотеки поддержки, такие как appcompat-v4 и appcompat-v7 , являются частью решения. Однако Theme.AppCompat не реализует каждый элемент материала, используемый в официальных приложениях Google. Одной из функций, отсутствующих в теме AppCompat, является возможность размещать плавающую метку поверх виджета EditText . Вы можете видеть, что я имею в виду в следующем примере.

Официальная реализация материалов TextInputLayout реализация

Во время Google I / O 2015 команда Android выпустила новую библиотеку поддержки, Библиотеку поддержки дизайна . Это очень удобно для решения подобных проблем. Этот учебник покажет вам, как использовать новый виджет TextInputLayout который включен в Библиотека поддержки дизайна.

В Android Studio выберите « Новый»> «Новый проект» в меню « Файл» . Введите необходимую информацию для настройки проекта и создания проекта. В моем примере я нацелил проект на API 7 , который является минимальным уровнем API, поддерживаемым библиотекой поддержки проектирования. Благодаря такому низкому уровню API ваше приложение будет работать практически на всех устройствах Android. Я назвал основной вид деятельности LoginActivity и его файл макета activity_login.xml .

После настройки проекта удалите в основном упражнении onCreateOptionsMenu и метод onOptionsItemSelected который автоматически генерируется Android Studio. Экран входа в систему, который мы собираемся создать, не нуждается в меню, поэтому можно удалить эти методы. Не забудьте также удалить файл меню XML, который находится в папке res / menu .

Чтобы использовать виджет TextInputLayout , вам нужно импортировать две библиотеки. Первый — appcompat-v7 , который обеспечивает обратную совместимость стилей материала. Второй — библиотека поддержки дизайна .

В файле build.gradle вашего проекта добавьте следующие строки в зависимости проекта:

1
2
3
4
5
6
dependencies {
    compile fileTree(dir: ‘libs’, include: [‘*.jar’])
 
    compile ‘com.android.support:design:22.2.0’
    compile ‘com.android.support:appcompat-v7:22.2.0’
}

Если Gradle не просит автоматически синхронизировать ваш проект, выберите Make module ‘app’ в меню Build или нажмите F9 . Таким образом, система сборки Android Studio автоматически выберет необходимые ресурсы, и вы сможете импортировать любые необходимые классы.

Пользовательский интерфейс этого проекта очень прост. Он показывает приветственную метку (которую можно легко заменить на логотип, если он у вас есть) и два элемента EditText , один для имени пользователя и один для пароля. Макет также включает в себя кнопку, которая запускает последовательность входа в систему. Цвет фона приятный, ровный, светло-серый.

Еще одна важная деталь, о которой стоит помнить, — это правильная настройка атрибута inputType элементов EditText . Для inputType первого элемента EditText должно быть установлено значение textEmail а для второго textPassword . Вот как должен выглядеть макет.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
<LinearLayout xmlns:android=»https://schemas.android.com/apk/res/android»
    xmlns:tools=»http://schemas.android.com/tools»
    android:background=»#e3e3e3″
    android:layout_width=»match_parent»
    android:layout_height=»match_parent»
    android:padding=»@dimen/activity_horizontal_margin»
    tools:context=».LoginActivity»
    android:orientation=»vertical»>
 
    <RelativeLayout
        android:layout_width=»match_parent»
        android:layout_height=»wrap_content»
        android:layout_weight=»0.5″
        android:orientation=»vertical»>
 
        <TextView
            android:layout_width=»match_parent»
            android:layout_height=»wrap_content»
            android:layout_centerInParent=»true»
            android:gravity=»center»
            android:text=»Welcome»
            android:textSize=»30sp»
            android:textColor=»#333333″/>
 
    </RelativeLayout>
 
 
    <LinearLayout
        android:layout_width=»match_parent»
        android:layout_height=»wrap_content»
        android:layout_weight=»0.5″
        android:orientation=»vertical»>
 
        <EditText
            android:id=»@+id/username»
            android:layout_width=»match_parent»
            android:layout_height=»wrap_content»
            android:inputType=»textEmailAddress»/>
 
        <EditText
                android:id=»@+id/password»
                android:layout_width=»match_parent»
                android:layout_height=»wrap_content»
                android:inputType=»textPassword»/>
 
        <Button
            android:id=»@+id/btn»
            android:layout_marginTop=»4dp»
            android:layout_width=»match_parent»
            android:layout_height=»wrap_content»
            android:text=»Login»/>
 
    </LinearLayout>
 
</LinearLayout>

Вы также можете избавиться от панели приложения, ранее известной как панель действий, отредактировав файл style.xml, как показано ниже.

1
2
<style name=»AppTheme» parent=»Theme.AppCompat.Light.NoActionBar»>
</style>

Мы наконец добрались до самой интересной части этого урока. Виджет TextInputLayout ведет себя точно так же, как и LinearLayout , это просто оболочка. TextInputLayout принимает только один дочерний элемент, похожий на ScrollView . Дочерний элемент должен быть элементом EditText .

01
02
03
04
05
06
07
08
09
10
11
12
13
<android.support.design.widget.TextInputLayout
    android:id=»@+id/usernameWrapper»
    android:layout_width=»match_parent»
    android:layout_height=»wrap_content»>
 
    <EditText
        android:id=»@+id/username»
        android:layout_width=»match_parent»
        android:layout_height=»wrap_content»
        android:inputType=»textEmailAddress»
        android:hint=»Username»/>
 
</android.support.design.widget.TextInputLayout>

Обратите внимание, что я указал другой параметр в элементе EditText , hint . Как вы уже знаете, этот атрибут позволяет отображать пользовательскую подсказку, когда в EditText нет содержимого. Как только пользователь начинает печатать, подсказка исчезает. Это не здорово, потому что они теряют контекст информации, которую они вводят.

Благодаря TextInputLayout это больше не будет проблемой. В то время как один только EditText будет скрывать подсказку после ввода первого символа, при переносе в TextInputLayout подсказка станет плавающей меткой над EditText . Хорошая анимация материала тоже включена.

Далее, давайте сделаем то же самое для поля пароля.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
<android.support.design.widget.TextInputLayout
    android:id=»@+id/passwordWrapper»
    android:layout_width=»match_parent»
    android:layout_height=»wrap_content»
    android:layout_below=»@id/usernameWrapper»
    android:layout_marginTop=»4dp»>
 
    <EditText
        android:id=»@+id/password»
        android:layout_width=»match_parent»
        android:layout_height=»wrap_content»
        android:inputType=»textPassword»
        android:hint=»Password»/>
 
</android.support.design.widget.TextInputLayout>

Если вы запустите приложение сейчас, ничего не произойдет. Конечно, атрибут подсказки EditText будет вести себя как положено. Однако нет анимации материала и плавающих надписей. Это почему? Нам все еще не хватает кода, чтобы все работало.

Ниже метода setContentView инициализируйте ссылки на представления TextInputLayout .

1
2
final TextInputLayout usernameWrapper = (TextInputLayout) findViewById(R.id.usernameWrapper);
final TextInputLayout passwordWrapper = (TextInputLayout) findViewById(R.id.passwordWrapper);

Чтобы анимировать плавающую метку, вам просто нужно установить подсказку, используя метод setHint .

1
2
usernameWrapper.setHint(«Username»);
passwordWrapper.setHint(«Password»);

И вы сделали. Теперь ваш экран входа в систему соответствует правилам оформления материалов. Запустите приложение, чтобы увидеть ваш красивый экран входа в систему.

Экран входа

Еще одна приятная особенность TextInputLayout — способ обработки ошибок. Проверяя введенные данные, вы не позволяете пользователям неправильно вводить свой адрес электронной почты или вводить слишком короткий пароль.

При проверке входных данных серверная часть будет обрабатывать неверные учетные данные, ошибки будут генерироваться и отправляться клиенту, а затем показываться (ожидающему) пользователю. Значительная потеря времени и плохой пользовательский опыт. Вы должны проверить ввод пользователя перед отправкой его на сервер.

Сначала вы должны обработать нажатие кнопки. Есть много способов обрабатывать нажатия кнопок. Одним из них является написание собственного метода и указание его в XML-файле с помощью атрибута onClick . Я предпочитаю setOnClickListener , но это действительно вопрос личного вкуса.

1
2
3
4
5
6
btn.setOnClickListener(new View.OnClickListener() {
    @Override
    public void onClick(View v) {
        // STUB
    }
});

Мы знаем, что если этот метод вызывается, пользователю больше не нужна клавиатура. К сожалению, Android не скрывает виртуальную клавиатуру автоматически, если вы не скажете это. Вызовите hideKeyboard в теле метода hideKeyboard .

1
2
3
4
5
6
7
private void hideKeyboard() {
    View view = getCurrentFocus();
    if (view != null) {
        ((InputMethodManager) getSystemService(Context.INPUT_METHOD_SERVICE)).
            hideSoftInputFromWindow(view.getWindowToken(), InputMethodManager.HIDE_NOT_ALWAYS);
    }
}

Прежде чем устанавливать метки ошибок, мы должны определить, что является ошибкой, а что нет. Мы предполагаем, что имя пользователя должно быть адресом электронной почты, и мы хотим запретить пользователям вводить неверный адрес электронной почты.

Проверка адреса электронной почты немного сложна. Мы должны полагаться на регулярные выражения. Вы также можете использовать библиотеку Apache Commons, если хотите.

Я написал следующее регулярное выражение, используя рекомендации, предложенные Википедией относительно достоверности электронной почты.

1
/^[a-zA-Z0-9#_~!$&'()*+,;=:.»(),:;<>@\[\]\\]+@[a-zA-Z0-9-]+(\.[a-zA-Z0-9-]+)*$/

Смысл этого регулярного выражения довольно прост. Он состоит из трех групп захвата. Первый соответствует буквам алфавита (верхний и нижний регистр), числам и серии принятых символов. Из-за квантификатора + эта группа соответствует строке, состоящей как минимум из одного символа.

Далее, есть символ @ , который, конечно, требуется в каждом адресе электронной почты. Вторая группа принимает только буквы, цифры и дефисы. Длина также должна быть не менее одного ( ]+ ).

Наконец, есть последняя группа, которая содержит точку и целью которой является сопоставление поддоменов и TLD. Его квантификатором является звезда * , что означает, что эта группа ищет строку, длина которой может быть равна нулю или более. Фактически, адреса электронной почты с доменом, но без TLD, действительно действительны.

Поскольку мы хотим проверить String , мы должны полагаться на классы Pattern и Matcher , включенные в пакет java.util.regex . Импортируйте эти классы в свою деятельность, а затем реализуйте следующий метод:

1
2
3
4
5
6
7
8
private static final String EMAIL_PATTERN = «^[a-zA-Z0-9#_~!$&'()*+,;=:.\»(),:;<>@\\[\\]\\\\]+@[a-zA-Z0-9-]+(\\.[a-zA-Z0-9-]+)*$»;
private Pattern pattern = Pattern.compile(EMAIL_PATTERN);
private Matcher matcher;
 
public boolean validateEmail(String email) {
    matcher = pattern.matcher(email);
    return matcher.matches();
}

Проверка поля пароля намного проще. В большинстве организаций применяются разные политики для проверки правильности пароля, но для каждой из них установлена ​​минимальная длина. Разумное правило заключается в том, что пароль никогда не должен быть короче шести символов.

1
2
3
public boolean validatePassword(String password) {
    return password.length() > 5;
}

Как я уже сказал, TextInputLayout — это просто оболочка, но в отличие от LinearLayout и ScrollView , вы можете получить его дочерний элемент с помощью специального метода getEditText . Нет необходимости использовать findViewById .

Если TextInputLayout не содержит EditText , getEditText возвращает null поэтому будьте осторожны с NullPointException .

01
02
03
04
05
06
07
08
09
10
public void onClick(View v) {
    hideKeyboard();
     
    String username = usernameWrapper.getEditText().getText().toString();
    String password = usernameWrapper.getEditText().getText().toString();
     
    // TODO: Checks
     
    // TODO: Login
}

Обработка ошибок TextInputLayout легко и быстро. Обязательные методы — setErrorEnabled и setError .

setError устанавливает красное сообщение об ошибке, которое будет отображаться под EditText . Если переданный параметр является null , сообщение об ошибке очищается. Он также меняет цвет всего виджета EditText на красный.

setErrorEnabled включает функцию ошибки. Это напрямую влияет на размер макета, увеличивая нижний отступ, чтобы освободить место для метки ошибки. Включение этой функции перед установкой сообщения об ошибке с помощью setError означает, что этот макет не изменит размер при отображении ошибки. Вы должны сделать несколько тестов, комбинирующих эти два метода, чтобы вы на самом деле видели   о чем я говорю

Еще одним интересным фактом является то, что если функция ошибок еще не была включена и вы вызываете setError передавая ненулевой параметр, то setErrorEnabled(true) будет вызываться автоматически.

Теперь, когда мы определили, что правильно, а что нет, и мы знаем, как извлекать данные и отображать возможные ошибки, реализация метода onClick становится тривиальной.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
public void onClick(View v) {
    hideKeyboard();
 
    String username = usernameWrapper.getEditText().getText().toString();
    String password = usernameWrapper.getEditText().getText().toString();
    if (!validateEmail(username)) {
        usernameWrapper.setError(«Not a valid email address!»);
    } else if (!validatePassword(password)) {
        passwordWrapper.setError(«Not a valid password!»);
    } else {
        usernameWrapper.setErrorEnabled(false);
        passwordWrapper.setErrorEnabled(false);
        doLogin();
    }
}

Я добавил метод doLogin , но в настоящее время он пуст, поскольку это выходит за рамки данного руководства.

1
2
3
4
public void doLogin() {
    Toast.makeText(getApplicationContext(), «OK! I’m performing login.», Toast.LENGTH_SHORT).show();
    // TODO: login procedure;
}

Возможно, вы захотите сделать еще одну вещь, изменив цвет виджета TextInputLayout . По умолчанию тема AppCompact устанавливает зеленый цвет, но довольно часто этот цвет конфликтует с вашей цветовой палитрой.

Google очень хорошо написал Библиотеку поддержки дизайна. Цвет каждого виджета рисуется непосредственно из цветов темы, указанных в вашем файле style.xml . Просто откройте его и добавьте элемент colorAccent в вашу активную тему, чтобы изменить цветовую схему формы.

1
2
3
<style name=»AppTheme» parent=»Theme.AppCompat.Light.NoActionBar»>
    <item name=»colorAccent»>#3498db</item>
</style>

Экран входа в систему с другим цветом

В этом уроке мы увидели, как реализовать новый элемент макета TextInputLayout , благодаря только что представленной библиотеке поддержки проектирования.

Парадигма дизайна, которую реализует этот виджет, позволяет пользователям никогда не терять контекст вводимой ими информации, и она была фактически представлена ​​Google в прошлом году вместе с Material Design.

В то время не было библиотеки поддержки, предоставляющей разработчикам возможность задействовать этот виджет в своих проектах до Google I / O 2015. Теперь, если ваше приложение ожидает какой-то ввод данных, вы, наконец, будете по-настоящему совместимы с дизайном материалов. ,