Освой Android играючи
/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000
AutoCompleteTextView
Пример для Kotlin
Стилизация
MultiAutoCompleteTextView
Компонент AutoCompleteTextView - это текстовое поле с автозаполнением и возможностью редактирования вводимого текста. Использование компонента удобно в том случае, когда требуется ускорить процесс ввода текста.
На панели инструментов элемент можно найти в разделе Texts.
AutoCompleteTextView является подклассом EditText, поэтому доступны все возможности форматирования и редактирования текста родительского класса.
Дополнительно, у AutoCompleteTextView есть свойство completionThreshold для указания минимального числа символов, которое должен ввести пользователь, чтобы включилась функция автозаполнения. Для связывания с данными необходимо задействовать адаптер, содержащий список значений через метод setAdapter().
Для упрощения создадим статический массив строк с именами котов и свяжем его через адаптер с нашим элементом в Java-коде. В реальных приложениях лучше использовать строковые ресурсы.
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""/>
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.autocomplete;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
public class MainActivity extends AppCompatActivity {
AutoCompleteTextView mAutoCompleteTextView;
final String[] mCats = { "Мурзик", "Рыжик", "Барсик", "Борис",
"Мурзилка", "Мурка" };
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAutoCompleteTextView = findViewById(R.id.autoCompleteTextView);
mAutoCompleteTextView.setAdapter(new ArrayAdapter<>(this,
android.R.layout.simple_dropdown_item_1line, mCats));
}
}
Запустите пример и начинайте вводить имена. Если вы напечатаете два символа му, то появится выпадающий список с вариантами слов для продолжения. Дальше текст можно не набирать, а просто коснуться нужного варианта и готовый текст сразу вставится в текстовое поле. Вот так все просто и работает.
Пример с строковыми ресурсами (res/values/string.xml).
<string-array name="cat_names">
<item>Барсик</item>
<item>Мурзик</item>
<item>Васька</item>
<item>Рыжик</item>
<item>Пыжик</item>
<item>Пушок</item>
<item>Пухлик</item>
<item>Снежок</item>
<item>Борис</item>
</string-array>
Получаем массив из ресурсов и используем в адаптере.
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.autocomplete;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import java.util.Arrays;
import java.util.List;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
AutoCompleteTextView autoCompleteTextView = findViewById(R.id.autoCompleteTextView);
String[] cats = getResources().getStringArray(R.array.cat_names);
List<String> catList = Arrays.asList(cats);
ArrayAdapter<String> adapter = new ArrayAdapter<>(
this, android.R.layout.simple_dropdown_item_1line, catList);
autoCompleteTextView.setAdapter(adapter);
}
}
Напишем аналогичный пример на Kotlin и добавим несколько новых слушателей.
// Если этот код работает, его написал Александр Климов,
// а если нет, то не знаю, кто его писал.
package ru.alexanderklimov.hellokot
import android.os.Bundle
import android.view.View
import android.widget.AdapterView
import android.widget.ArrayAdapter
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
class MainActivity : AppCompatActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val cats = arrayOf("Мурзик", "Рыжик", "Барсик", "Борис", "Мурзилка", "Мурка")
val adapter = ArrayAdapter<String>(
this, android.R.layout.simple_dropdown_item_1line, cats
)
autoCompleteTextView.setAdapter(adapter)
// Минимальное число символов для показа выпадающего списка
autoCompleteTextView.threshold = 2
// Обработчик щелчка
autoCompleteTextView.onItemClickListener = AdapterView.OnItemClickListener { parent, _,
position, id ->
val selectedItem = parent.getItemAtPosition(position).toString()
// Выводим выбранное слово
Toast.makeText(applicationContext, "Selected: $selectedItem", Toast.LENGTH_SHORT).show()
}
// Отслеживаем закрытие выпадающего списка
autoCompleteTextView.setOnDismissListener {
Toast.makeText(applicationContext, "Suggestion closed.", Toast.LENGTH_SHORT).show()
}
// Обработчик щелчка для корневого элемента макета (LinearLayout или др.)
root_layout.setOnClickListener {
val text = autoCompleteTextView.text
Toast.makeText(applicationContext, "Inputted: $text", Toast.LENGTH_SHORT).show()
}
// Если к компоненту перешёл фокус
autoCompleteTextView.onFocusChangeListener = View.OnFocusChangeListener { _, hasFocus ->
if (hasFocus) {
// Выводим выпадающий список
autoCompleteTextView.showDropDown()
}
}
}
}
Подготовим тему в styles.xml:
<style name="Autocomplete" parent="Widget.AppCompat.Light.AutoCompleteTextView">
<item name="android:background">@color/colorAccent</item>
<item name="colorControlNormal">@color/colorPrimary</item>
<item name="colorControlActivated">@color/greenColor</item>
</style>
Подключим тему к компоненту.
<AutoCompleteTextView
...
android:theme="@style/Autocomplete"/>
По умолчанию выпадающий список подсказок выводится сразу под текстовым полем. Но можно переопределить это поведение через атрибут android:dropDownAnchor, указав нужный идентификатор компонента.
Добавим кнопку под текстовым полем и будем выводить выпадающий список под кнопкой.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:dropDownAnchor="@+id/button"
android:text=""/>
<Button
android:id="@+id/button"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text="Кнопка"/>
</LinearLayout>
В примере используется готовый набор слов для подстановки. Можно модифицировать программу, чтобы список слов был динамическим. Когда пользователь напечатает новое слово и нажмёт ОК, то проверяем наличие данного слова в массиве. Если такого слова нет, то добавляем в массив. Для решения данной задачи обычный строковый массив нам не подойдёт, будем использовать List<String>.
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context=".MainActivity">
<AutoCompleteTextView
android:id="@+id/autoCompleteTextView"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:text=""/>
<Button
android:id="@+id/buttonOk"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:onClick="onClick"
android:text="OK"/>
<TextView
android:id="@+id/textViewAutoList"
android:layout_width="match_parent"
android:layout_height="wrap_content"/>
</LinearLayout>
Код:
package ru.alexanderklimov.autocomplete;
import android.os.Bundle;
import android.support.v7.app.AppCompatActivity;
import android.view.View;
import android.widget.ArrayAdapter;
import android.widget.AutoCompleteTextView;
import android.widget.TextView;
import java.util.ArrayList;
import java.util.List;
public class MainActivity extends AppCompatActivity {
private AutoCompleteTextView mAutoCompleteTextView;
private String[] mCats = {"Мурзик", "Рыжик", "Барсик", "Борис",
"Мурзилка", "Мурка"};
private List<String> mList;
private ArrayAdapter<String> mAutoCompleteAdapter;
private TextView mAutoListTextView;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mAutoCompleteTextView = (AutoCompleteTextView) findViewById(R.id.autoCompleteTextView);
prepareList();
mAutoCompleteAdapter = new ArrayAdapter<>(MainActivity.this,
android.R.layout.simple_dropdown_item_1line, mList);
mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
mAutoListTextView = (TextView) findViewById(R.id.textViewAutoList);
}
private void prepareList() {
// подготовим список для автозаполнения
mList = new ArrayList<>();
for (String mCat : mCats) {
mList.add(mCat);
}
}
public void onClick(View view) {
String newAdd = mAutoCompleteTextView.getText().toString();
if (!mList.contains(newAdd)) {
mList.add(newAdd);
// update the autocomplete words
mAutoCompleteAdapter = new ArrayAdapter<>(
MainActivity.this,
android.R.layout.simple_dropdown_item_1line, mList);
mAutoCompleteTextView.setAdapter(mAutoCompleteAdapter);
}
// display the words in mList for your reference
String s = "";
for (int i = 0; i < mList.size(); i++) {
s += mList.get(i) + "\n";
}
mAutoListTextView.setText(s);
}
}
Можно настроить свой адаптер для вывода подсказок, используя интерфейсы Filterable и ListAdapter. Можно наследоваться от ArrayAdapter, который уже имеет эти интерфейсы.
Попробуйте реализовать пример самостоятельно и пришлите его мне.
На панели инструментов компонент можно найти в том же разделе Texts.
Использование компонента удобно в том случае, когда требуется ускорить процесс ввода текста.
MultiAutoCompleteTextView - это текстовое поле с автозаполнением и возможностью редактирования вводимого текста, расширяющее функциональность AutoCompieteTextview, который может показывать автозаполнение для каждой из подстрок текста, разделенных знаком пунктуации. Разделитель задается явно вызовом метода setTokenizer().
textView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());
MultiAutoCompleteTextView является подклассом EditText и AutoCompleteTextView, поэтому доступны все возможности форматирования и редактирования текста родительских классов, описанных выше.
Пример практически не будет отличаться от предыдущего. Главная особенность - можно задать строковый массив в виде строк, разделенных запятой, например, так:
final String[] mContacts {
"Anderson, Jacob", "Duncan, Emily", "Fuller, Michael",
"Cotman, Matthew", "Lawson, 01ivia", "Chapman, Andrew",
"Godwin, Joseph", "Bush, Samantha", "Gateman, Christopher"};
Теперь, при наборе первых букв, будет выводиться не одно слово, а сразу пара слов.
// все тоже самое
mAutoCompleteTextView.setAdapter(new ArrayAdapter(this,
android.R.layout.simple_dropdown_item_1line, mContacts));
mAutoCompleteTextView.setTokenizer(new MultiAutoCompleteTextView.CommaTokenizer());