Урок 14. Наполнение Toolbar вложенными элементами на экране SearchUsersActivity

Код начала урока:

gitzip

Структура урока:

Нам необходимо сделать тулбар такого вида:

search_users_toolbar.png

Добавление Toolbar-компонента

Здесь стандартным меню не обойтись, т.к. здесь уже присутствует более сложная логика пользовательского интерфейса – элемент поиска. Поэтому нам понадобится файл toolbar_search_user.xml, который мы создавали в одном из прошлых уроков.

Сперва, как и с предыдущим тулбаром в файле activity_user_info.xml, добавим его в файл activity_search_users.xml:

activity_search_users.xml

<?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.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        style="@style/Toolbar">

    </android.support.v7.widget.Toolbar>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/users_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

Мы изменили корневой элемент с FrameLayout на LinearLayout, т.к. у нас появился второй вложенный элемент. Мы указали свойство android:orientation="vertical", чтобы элементы располагались вертикально.

А теперь просто добавим содержимое файла toolbar_search_user.xml (немного его изменив) внутрь элемента Toolbar. Toolbar является ViewGroup, поэтому в него можно помещать элементы, как и в любой другой контейнер. Единственный нюанс – Toolbar располагает элементы один над одним по умолчанию (как FrameLayout).

activity_search_users.xml

<?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.support.v7.widget.Toolbar
        android:id="@+id/toolbar"
        style="@style/Toolbar">

        <RelativeLayout
            xmlns:android="http://schemas.android.com/apk/res/android"
            android:layout_width="match_parent"
            android:layout_height="match_parent"
            android:padding="8dp">

            <EditText
                android:id="@+id/search_edit_text"
                android:layout_width="match_parent"
                android:layout_marginEnd="20dp"
                android:layout_toStartOf="@+id/search_button"
                android:layout_height="wrap_content"
                android:hint="Введите имя"/>

            <Button
                android:id="@+id/search_button"
                android:layout_alignParentEnd="true"
                android:layout_width="wrap_content"
                android:layout_height="wrap_content"
                android:text="Поиск"/>

        </RelativeLayout>

    </android.support.v7.widget.Toolbar>

    <android.support.v7.widget.RecyclerView
        android:id="@+id/users_recycler_view"
        android:layout_width="match_parent"
        android:layout_height="match_parent"/>

</LinearLayout>

Единственное, что изменилось – атрибут android:layout_height="match_parent" у контейнера RelativeLayout. Т.к. нам необходимо, чтобы контейнер занимал всю высоту parent элемента (им является Toolbar).

Запустим приложение и перейдём на экран поиска пользователей:

SearchUsersToolbarRaw.png

Видим, что данные отобразились, но визуально они выглядят не очень.

Стилизация Toolbar-компонента

Нам надо поменять стили у наших элементов EditText и Button.

Давайте усовершенствуем наш EditText:

activity_search_users.xml

<EditText
    android:id="@+id/query_edit_text"
    android:layout_width="match_parent"
    android:layout_height="wrap_content"
    android:layout_centerVertical="true"
    android:layout_marginEnd="10dp"
    android:layout_toStartOf="@+id/search_button"
    android:background="@null"
    android:maxLines="1"
    android:imeOptions="actionSearch"
    android:inputType="text"
    android:hint="@string/search_query_hint"/>

Объясним новые атрибуты:

  • android:maxLines="1" – означает, что EditText не будет поддерживать многострочный режим и весь текст будет располагаться в одну строку.
  • android:imeOptions="actionSearch" и android:inputType="text" добавляют в клавиатуру пользователя кнопку поиска, нажатие по которой в дальнейшем мы сможем обработать.
  • android:background="@null" убирает нижнюю линию, которая по умолчанию присутствует в EditText.

Также некоторые изменения претерпела кнопка поиска.

Добавление иконки шрифта Ionicons

Перед тем, как добавить кнопку, нам необходимо по аналогии со шрифтом font_awesome в проект добавить шрифт ionicons.

После этого нам нужно добавить строковый ресурс иконки поиска, которая располагается на сайте. Найти её можно используя название ion-android-search. После того, как нашли её, необходимо скопировать иконку, которая находится в блоке selectable, как показано на скриншоте:

IoniconsIcon.png

Затем просто создаём новый строковый ресурс с именем ion_search и вставляем то значение, которое мы скопировали:

strings.xml

<resources>

    <!-- Остальные элементы выше не изменились -->

    <string name="ion_search"></string>
</resources>

Видим, что иконка отобразилась корректно.

Вот как выглядит наша кнопка со всеми атрибутами:

activity_search_users.xml

<Button
    android:id="@+id/search_button"
    android:layout_width="wrap_content"
    android:layout_height="wrap_content"
    android:minWidth="0dp"
    android:minHeight="0dp"
    android:padding="10dp"
    android:layout_alignParentEnd="true"
    android:background="@drawable/transparent_gfx"
    android:fontFamily="@font/ionicons"
    android:text="@string/ion_search"
    android:textColor="@color/white"
    android:textSize="23sp"/>

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

Также мы используем атрибут android:background="@drawable/transparent_gfx". Пользовательский интерфейс должен быть интуитивно понятен для пользователя, поэтому он должен показывать некую реакцию на действия пользователя. В данном случае при нажатии на кнопку поиска её фон должен видоизменяться, тем самым показывая отзывчивость кнопки на действия пользователя. Более подробно об этом эффекте можно узнать из отрывка курса Material Design в Android. Ниже приведены файлы эффекта:

Нам нужно создать файл с названием transparent_gfx в папке drawable. Для этого кликните по папке правой кнопкой, выбрав элементы New -> Drawable resource file.

drawable/transparent_gfx.xml

<?xml version="1.0" encoding="utf-8"?>
<selector xmlns:android="http://schemas.android.com/apk/res/android">

    <item android:state_pressed="true">
        <shape android:shape="oval">
            <solid android:color="@color/white_alpha" />
        </shape>
    </item>

    <item>
        <shape android:shape="oval">
            <solid android:color="@android:color/transparent" />
        </shape>
    </item>

</selector>

Обработка событий Toolbar-компонента

Теперь мы можем работать с элементами тулбара как и с любыми другими элементами экрана. Давайте добавим Toolbar и его вложенные элементы в SearchUsersActivity.

SearchUsersActivity.java

public class SearchUsersActivity extends AppCompatActivity {

    // остальные элементы выше не изменились
    private Toolbar toolbar;
    private EditText queryEditText;
    private Button searchButton;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_search_users);
        initRecyclerView();

        toolbar = findViewById(R.id.toolbar);
        queryEditText = toolbar.findViewById(R.id.query_edit_text);
        searchButton = toolbar.findViewById(R.id.search_button);

        searchUsers();
    }
    // остальные элементы ниже не изменились

}

Ничего необычного. Только вложенные элементы мы ищем используя toolbar.findViewById(). Это сделано для оптимизации поиска элементов. Поиск будет проходить только внутри Toolbar элемента, а не во всех элементах SearchUsersActivity.

Теперь давайте будем производить поиск пользователей не в методе onCreate, а добавим слушателей на нажатие кнопки поиска и на нажатие кнопки search внутри клавиатуры:

SearchUsersActivity.java

public class SearchUsersActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // остальной код выше не изменился

        searchButton.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                searchUsers();
            }
        });

        queryEditText.setOnEditorActionListener(new TextView.OnEditorActionListener() {
            @Override
            public boolean onEditorAction(TextView v, int actionId, KeyEvent event) {
                if (actionId == EditorInfo.IME_ACTION_SEARCH) {
                    searchUsers();
                    return true;
                }
                return false;
            }
        });
    }
}

Если вы сейчас запустите приложение, то не увидите в тулбаре кнопки «Назад» в левой его части. Её мы можем добавить, используя стандартный механизм тулбара:

SearchUsersActivity.java

public class SearchUsersActivity extends AppCompatActivity {

    @Override
    protected void onCreate(Bundle savedInstanceState) {

        // остальной код выше не изменился

        setSupportActionBar(toolbar);
        getSupportActionBar().setDisplayHomeAsUpEnabled(true);
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        switch (item.getItemId()) {
            case android.R.id.home:
                onBackPressed();
                return true;
        }

        return super.onOptionsItemSelected(item);
    }
}

Таким образом, мы сообщаем Activity о необходимости отобразить кнопку «Назад». По умолчанию кнопка назад не будет работать. Мы хотим, чтобы она работала как аппаратная кнопка «Назад». Для этого мы перехватываем нажатием кнопки в тулбаре и вызываем метод Activity onBackPressed().

Посмотрим, что у нас получилось в итоге:

Result.png

.

Проблема повторения элементов в списке

У нас появилась небольшая проблема: если мы несколько раз нажмём на кнопку поиска, то элементы в списке будут повторяться. Для избежания этой проблемы мы можем при каждом вызове метода searchUsers удалять старые элементы из адаптера. Давайте так и сделаем:

SearchUsersActivity.java

public class SearchUsersActivity extends AppCompatActivity {

    // Остальной код выше не изменился

    private void searchUsers() {
        Collection<User> users = getUsers();
        usersAdapter.clearItems();
        usersAdapter.setItems(users);
    }

    // Остальной код ниже не изменился
}

Проблема решена. Можете запустить приложение и убедиться в этом.

Отлично, поздравляем вас!

Кстати, мы можем удалить файл toolbar_search_user.xml, т.к. он нам больше не понадобится.

В результате данного урока мы:

  • отработали навыки работы с Toolbar;
  • узнали, каким образом наполнить Toolbar пользовательскими элементами.

Ссылки:

Полезные материалы:

Полный листинг изменений кода:

Code diff

УВИДЕТЬ ВСЕ Добавить заметку
ВЫ
Добавить ваш комментарий