Освой Android играючи

Сайт Александра Климова

Шкодим

/* Моя кошка замечательно разбирается в программировании. Стоит мне объяснить проблему ей - и все становится ясно. */
John Robbins, Debugging Applications, Microsoft Press, 2000

AutoCompieteTextview и MultiAutoCompleteTextView

AutoCompleteTextView
Пример для Kotlin
Стилизация
MultiAutoCompleteTextView

AutoCompleteTextView

Компонент 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));
    }
}

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

AutoCompleteTextView

Пример с строковыми ресурсами (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

Напишем аналогичный пример на 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"/>

AutoCompieteTextview

Место вывода выпадающего списка

По умолчанию выпадающий список подсказок выводится сразу под текстовым полем. Но можно переопределить это поведение через атрибут 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>

AutoCompieteTextview

Динамический подбор

В примере используется готовый набор слов для подстановки. Можно модифицировать программу, чтобы список слов был динамическим. Когда пользователь напечатает новое слово и нажмёт ОК, то проверяем наличие данного слова в массиве. Если такого слова нет, то добавляем в массив. Для решения данной задачи обычный строковый массив нам не подойдёт, будем использовать 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, который уже имеет эти интерфейсы.

Попробуйте реализовать пример самостоятельно и пришлите его мне.

MultiAutoCompleteTextView

На панели инструментов компонент можно найти в том же разделе 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()); 

Библиотеки

Реклама