Автоматическое заполнение форм, часто сокращаемое до автоматического заполнения, является функцией, которую браузеры поддерживают уже много лет. Большинство из нас используют это все время. Я, например, считаю это необходимым во время таких задач, как заполнение регистрационной формы или завершение процесса оформления заказа.
Последний выпуск Android, Android O , предоставляет аналогичную функциональность приложениям Android. Другими словами, Android теперь может помочь пользователям заполнять формы, которые принадлежат всем приложениям, установленным на их устройствах. Это была очень долгожданная функция, потому что печатать с помощью виртуальной клавиатуры на маленьком экране, как правило, довольно сложно.
Как разработчик приложения вы можете использовать новую среду автозаполнения для создания собственной настраиваемой службы автозаполнения, которая решает, как заполнять поля ввода приложения. В этом уроке я покажу как.
Предпосылки
Чтобы следовать этому руководству, вам понадобится:
- Android Studio 2.4 Preview 7 или выше
- Эмулятор или устройство под управлением Android O или выше
1. Создайте новый проект
Запустите Android Studio и создайте новый проект с пустым действием. Вы, конечно, не забудьте выбрать Android 7+ в диалоговом окне Target Android Devices .
Для этого проекта потребуются несколько виджетов, принадлежащих библиотеке поддержки проектирования, поэтому откройте файл build.gradle модуля app
и добавьте в него следующую зависимость compile
:
1
|
compile ‘com.android.support:design:26.+’
|
Наконец, нажмите кнопку « Синхронизировать сейчас» , чтобы обновить проект.
2. Создайте действие настроек
В этом руководстве мы создадим приложение, содержащее очень простую службу автозаполнения, предназначенную только для тех полей ввода, в которые пользователь должен ввести адрес электронной почты. Поскольку почти все другие приложения в Google Play сегодня запрашивают адрес электронной почты, эта услуга будет весьма полезна.
Наш сервис, очевидно, должен знать, какие адреса электронной почты пользователя. Поэтому давайте теперь создадим действие, в котором пользователь сможет ввести и сохранить два адреса электронной почты.
Шаг 1: Определите макет
Как и следовало ожидать, макет действия будет содержать два виджета EditText
где пользователь может вводить свои адреса электронной почты. Если вы хотите, чтобы он придерживался принципов дизайна материалов, размещение виджетов EditText
внутри контейнеров TextInputLayout
является хорошей идеей.
Кроме того, в макете должен быть виджет « Button
пользователь может нажать для сохранения адресов электронной почты.
Вы можете разместить виджеты где угодно. Тем не менее, на данный момент я предлагаю вам поместить их все в LinearLayout
, ориентация которого вертикальная.
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
|
<?xml version=»1.0″ encoding=»utf-8″?>
<LinearLayout
xmlns:android=»http://schemas.android.com/apk/res/android»
android:layout_width=»match_parent»
android:layout_height=»match_parent»
android:orientation=»vertical»
android:padding=»16dp»>
<android.support.design.widget.TextInputLayout
android:layout_width=»match_parent»
android:layout_height=»wrap_content»>
<EditText
android:layout_width=»match_parent»
android:layout_height=»wrap_content»
android:id=»@+id/primary»
android:hint=»Your primary email address»
android:inputType=»textEmailAddress»/>
</android.support.design.widget.TextInputLayout>
<android.support.design.widget.TextInputLayout
android:layout_width=»match_parent»
android:layout_height=»wrap_content»>
<EditText
android:layout_width=»match_parent»
android:layout_height=»wrap_content»
android:id=»@+id/secondary»
android:hint=»Your other email address»
android:inputType=»textEmailAddress»/>
</android.support.design.widget.TextInputLayout>
<Button
android:layout_width=»match_parent»
android:layout_height=»wrap_content»
android:id=»@+id/save_button»
style=»@style/Widget.AppCompat.Button.Colored»
android:text=»Save»
android:onClick=»saveEmailAddresses»/>
</LinearLayout>
|
В приведенном выше коде вы можете видеть, что виджет Button
имеет атрибут onClick
указывающий на метод. Нажмите на желтую лампочку рядом с этим атрибутом в Android Studio, чтобы сгенерировать для него заглушку в связанном классе Activity
.
1
2
3
|
public void saveEmailAddresses(View view) {
// More code will be added here
}
|
Шаг 2. Сохраните адреса электронной почты
Мы будем использовать файл общих настроек EMAIL_STORAGE для сохранения наших данных. Вы можете использовать метод getSharedPreferences()
вашего класса Activity
для доступа к файлу. Кроме того, чтобы иметь возможность записи в файл, необходимо вызвать его метод edit()
, который генерирует объект SharedPreferences.Editor
.
Соответственно, добавьте следующий код в метод saveEmailAddresses()
:
1
2
|
SharedPreferences.Editor editor =
getSharedPreferences(«EMAIL_STORAGE», MODE_PRIVATE).edit();
|
Чтобы получить адреса электронной почты, которые пользователь ввел в виджеты EditText
, сначала нужно получить ссылки на них с findViewById()
метода findViewById()
, а затем вызвать их getText()
.
1
2
3
4
5
6
7
|
String primaryEmailAddress =
((EditText)findViewById(R.id.primary))
.getText().toString();
String secondaryEmailAddress =
((EditText)findViewById(R.id.secondary))
.getText().toString();
|
На этом этапе вы можете вызвать метод редактора putString()
чтобы добавить адреса электронной почты в файл настроек в виде двух пар ключ-значение. После этого не забудьте вызвать метод commit()
чтобы сделать ваши изменения постоянными.
1
2
3
|
editor.putString(«PRIMARY_EMAIL», primaryEmailAddress);
editor.putString(«SECONDARY_EMAIL», secondaryEmailAddress);
editor.commit();
|
Шаг 3: Создайте файл метаданных
Задание настроек, которое мы создали на предыдущем шаге, в настоящее время является обычным действием Чтобы платформа Android знала, что это действие по настройке для службы автозаполнения, мы должны создать XML-файл метаданных, сообщив об этом.
Создайте новый XML-файл с именем email_address_filler.xml в папке проекта res / xml . Внутри него добавьте <autofill-service>
и установите в качестве значения его атрибута settingsActivity
имя вашего класса Activity
.
1
2
3
4
|
<?xml version=»1.0″ encoding=»utf-8″?>
<autofill-service
xmlns:android=»http://schemas.android.com/apk/res/android»
android:settingsActivity=»com.tutsplus.simplefill.MainActivity»/>
|
Теперь вы можете запустить приложение, ввести два адреса электронной почты и нажать кнопку Сохранить , чтобы сохранить их.
3. Создайте сервис автозаполнения
Любой класс, который расширяет абстрактный класс AutoFillService
может служить в качестве службы автозаполнения. Итак, начните с создания нового Java-класса с помощью File> New> Java Class . В появившемся диалоговом окне назовите класс EmailAddressFiller и убедитесь, что в поле Superclass установлено значение AutoFillService
.
Android Studio теперь предложит вам создать заглушки для двух абстрактных методов: onSaveRequest()
и onFillRequest()
. В этом руководстве мы сосредоточимся только на onFillRequest()
, который автоматически вызывается всякий раз, когда пользователь открывает действие любого приложения, содержащее поля ввода.
1
2
3
4
5
6
7
8
9
|
@Override
public void onFillRequest(AssistStructure assistStructure,
Bundle bundle,
CancellationSignal cancellationSignal,
FillCallback fillCallback) {
// More code goes here
}
|
Шаг 1. Анализ иерархий представлений
Служба автозаполнения должна проанализировать пользовательский интерфейс приложения и определить поля ввода, которые оно может заполнить. Вот почему метод onFillRequest()
получает объект AssistStructure
, который содержит сведения обо всех виджетах, которые в данный момент видны на экране. Точнее, он содержит дерево объектов ViewNode
.
Если вы никогда не видели такое дерево, я предлагаю вам использовать инструмент uiautomatorviewer , который является частью Android SDK, для анализа иерархии макетов некоторых приложений. Например, вот как выглядит иерархия макетов почтового приложения Android по умолчанию:
Естественно, чтобы проанализировать все узлы дерева, вам нужен рекурсивный метод. Давайте создадим один сейчас:
1
2
3
4
|
void identifyEmailFields(AssistStructure.ViewNode node,
List<AssistStructure.ViewNode> emailFields) {
// More code goes here
}
|
Как видите, этот метод имеет ViewNode
и List
качестве параметров. Мы будем использовать List
для хранения всех полей ввода, которые ожидают адреса электронной почты.
Теперь вам может быть интересно, как программно определить, ожидает ли поле ввода адрес электронной почты. Ну, на самом деле нет надежного подхода, которому вы можете следовать. Сейчас мы предполагаем, что все разработчики приложений всегда предоставляют значимые идентификаторы ресурсов своим полям ввода. Исходя из этого предположения, мы можем просто выбрать все поля ввода, идентификаторы ресурсов которых содержат строки, такие как «электронная почта» и «имя пользователя».
Соответственно, добавьте следующий код в метод:
1
2
3
4
5
6
7
8
|
if(node.getClassName().contains(«EditText»)) {
String viewId = node.getIdEntry();
if(viewId!=null && (viewId.contains(«email»)
||
emailFields.add(node);
return;
}
}
|
Затем, когда мы сталкиваемся с объектом ViewNode
который содержит больше объектов ViewNode
, мы должны рекурсивно вызывать метод ViewNode
identifyEmailFields()
для анализа всех его дочерних ViewNode
. Следующий код показывает вам, как:
1
2
3
|
for(int i=0; i<node.getChildCount();i++) {
identifyEmailFields(node.getChildAt(i), emailFields);
}
|
На этом этапе мы можем вызвать метод onFillRequest()
внутри метода onFillRequest()
и передать ему корневой узел иерархии представления.
1
2
3
4
5
6
7
|
// Create an empty list
List<AssistStructure.ViewNode> emailFields = new ArrayList<>();
// Populate the list
identifyEmailFields(assistStructure
.getWindowNodeAt(0)
.getRootViewNode(), emailFields);
|
Если наш сервис не может определить какие-либо поля ввода для электронных писем, он ничего не должен делать. Поэтому добавьте в него следующий код:
1
2
|
if(emailFields.size() == 0)
return;
|
Шаг 2. Создание и заполнение удаленных представлений
Если наш сервис идентифицирует поле ввода, которое он может заполнить, он должен заполнить раскрывающийся список, который будет отображаться под полем ввода. Однако сделать это непросто, поскольку ни поле ввода, ни раскрывающийся список не принадлежат нашему приложению.
Чтобы заполнить раскрывающийся список, мы должны использовать объекты RemoteViews
. Как следует из названия, объект RemoteViews
представляет собой набор представлений, которые могут отображаться в другом приложении.
Для инициализации объекта RemoteViews
вам понадобится XML-файл макета. Давайте создадим один, теперь называемый email_suggestion.xml . На данный момент он может содержать только один виджет TextView
для отображения адреса электронной почты.
Соответственно, добавьте следующий код в email_suggestion.xml :
1
2
3
4
5
6
7
8
9
|
<?xml version=»1.0″ encoding=»utf-8″?>
<TextView xmlns:android=»http://schemas.android.com/apk/res/android»
android:layout_width=»wrap_content»
android:layout_height=»wrap_content»
android:id=»@+id/email_suggestion_item»
android:textSize=»18sp»
android:textStyle=»bold»
android:padding=»5dp»>
</TextView>
|
Теперь вы можете вернуться к onFillRequest()
и создать два объекта RemoteViews
: один для основной электронной почты, а другой для дополнительной.
1
2
3
4
5
6
7
|
RemoteViews rvPrimaryEmail =
new RemoteViews(getPackageName(),
R.layout.email_suggestion);
RemoteViews rvSecondaryEmail =
new RemoteViews(getPackageName(),
R.layout.email_suggestion);
|
Виджеты TextView
внутри объектов RemoteViews
должны отображать два адреса электронной почты, которые мы сохранили в файле общих настроек ранее. Чтобы открыть файл, снова используйте метод getSharedPreferences()
. Открыв его, вы можете использовать его метод getString()
для получения обоих адресов электронной почты.
Наконец, чтобы установить содержимое удаленных виджетов TextView
, вы должны использовать метод setTextViewText()
.
01
02
03
04
05
06
07
08
09
10
11
12
13
14
|
// Load the email addresses from preferences
SharedPreferences sharedPreferences =
getSharedPreferences(«EMAIL_STORAGE», MODE_PRIVATE);
String primaryEmail =
sharedPreferences.getString(«PRIMARY_EMAIL», «»);
String secondaryEmail =
sharedPreferences.getString(«SECONDARY_EMAIL», «»);
// Update remote TextViews
rvPrimaryEmail.setTextViewText(R.id.email_suggestion_item,
primaryEmail);
rvSecondaryEmail.setTextViewText(R.id.email_suggestion_item,
secondaryEmail);
|
Шаг 3: Создание наборов данных
Теперь мы можем использовать удаленные представления для создания наборов данных автозаполнения, которые можно отправлять в любое приложение. Чтобы этот учебник не стал слишком длинным, мы будем создавать наборы данных только для первого поля ввода электронной почты, с которым мы столкнемся. Следующий код показывает, как выбрать только первое поле ввода электронной почты:
1
|
AssistStructure.ViewNode emailField = emailFields.get(0);
|
Набор данных автозаполнения — это не что иное, как экземпляр класса Dataset
, и его можно построить с Dataset.Builder
класса Dataset.Builder
.
Когда пользователь выбирает один из адресов электронной почты, которые наша служба показывает в раскрывающемся списке, он должен установить содержимое соответствующего поля ввода с помощью setValue()
класса Dataset.Builder
. Однако вы не можете передать объект setValue()
метод setValue()
. Фактически он ожидает идентификатор автозаполнения, который должен быть получен путем вызова getAutoFillId()
объекта ViewNode
.
Кроме того, чтобы указать текст, который должен быть записан в поле ввода, необходимо использовать метод AutoFillValue.forText()
. Следующий код показывает вам, как:
01
02
03
04
05
06
07
08
09
10
11
12
13
|
Dataset primaryEmailDataSet =
new Dataset.Builder(rvPrimaryEmail)
.setValue(
emailField.getAutoFillId(),
AutoFillValue.forText(primaryEmail)
).build();
Dataset secondaryEmailDataSet =
new Dataset.Builder(rvSecondaryEmail)
.setValue(
emailField.getAutoFillId(),
AutoFillValue.forText(secondaryEmail)
).build();
|
Перед отправкой наборов данных в приложение вы должны добавить их в объект FillResponse
, который можно создать с FillResponse.Builder
класса FillResponse.Builder
. Вызовите его addDataset()
дважды, чтобы добавить оба набора данных.
Как FillResponse
объект FillResponse
будет готов, передайте его в качестве аргумента onSuccess()
объекта FillCallback
, который является одним из параметров метода onFillRequest()
.
1
2
3
4
5
6
|
FillResponse response = new FillResponse.Builder()
.addDataset(primaryEmailDataSet)
.addDataset(secondaryEmailDataSet)
.build();
fillCallback.onSuccess(response);
|
Шаг 4: Обновите манифест
Как и все сервисы, сервис автозаполнения также должен быть объявлен в файле AndroidManifest.xml проекта. При этом вы должны убедиться, что он защищен разрешением android.permission.BIND_AUTO_FILL
.
Этому сервису также нужен <intent-filter>
который позволяет ему реагировать на действие android.service.autofill.AutoFillService
, и <meta-data>
который указывает на файл XML метаданных, который мы создали на предыдущем шаге. ,
Соответственно, добавьте следующие строки в ваш файл манифеста:
1
2
3
4
5
6
7
8
|
<service android:name=».EmailAddressFiller»
android:permission=»android.permission.BIND_AUTO_FILL»>
<meta-data android:name=»android.autofill»
android:resource=»@xml/email_address_filler»/>
<intent-filter>
<action android:name=»android.service.autofill.AutoFillService»/>
</intent-filter>
</service>
|
Наш сервис автозаполнения и приложение теперь готовы. Создайте проект и установите приложение на свое устройство.
4. Активируйте и используйте сервис автозаполнения
Чтобы активировать службу автозаполнения, откройте приложение « Настройки» своего устройства и выберите « Приложения и уведомления»> «Дополнительно»> «Приложения по умолчанию»> «Автозаполнение» . На следующем экране выберите свое приложение из списка доступных приложений автозаполнения.
Теперь вы можете открыть любое приложение, которое запрашивает адрес электронной почты, чтобы увидеть вашу службу автозаполнения в действии. Например, вот что вы увидите на экранах входа в Instagram и Pinterest:
Вывод
Теперь вы знаете, как создать и использовать собственный сервис автозаполнения для Android. Не стесняйтесь расширять его для поддержки других общих полей, таких как имя или номер телефона. Вы также можете попробовать определить поля ввода, используя другие атрибуты, такие как метки и подсказки.
Чтобы узнать больше об Autofill Framework, обратитесь к его официальной документации . А пока, посмотрите другие наши посты о разработке приложений для Android и Android!