Опубликовано: 25 Октября 2017
(Демо приложение №1)
Всплывающее окно с элементами управления (Popup)

В этом уроке рассмотрим всплывающие окна, цель и способ их использования.

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

Описание виджета

Часто в приложениях возникает необходимость отображать важную информацию поверх всего пользовательского интерфейса, или запрашивать подтверждение и/или отмену действия. Для этого можно использовать всплывающее окно (Popup).

Для создания виджета используется следующая функция:

Evas_Object *elm_popup_add(Evas_Object *parent);

Как и с другими виджетами, что бы отобразить всплывающее окно необходимо вызвать функцию evas_object_show().

Этот виджет поддерживает исчезновение с задержкой, таким образом можно отобразить информацию и через несколько секунд автоматически свернуть popup. Для установки такой задержки и ее величины используется следующая функция.

void elm_popup_timeout_set(Evas_Object *obj, double timeout);

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

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

void elm_popup_dismiss(Evas_Object *obj);

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

Если же вы вызовите функцию evas_object_hide(), то окно исчезнет мгновенно без всякого эфекта.

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

elm_object_style_set(popup, "circle");
Стили макетов для всплывающих окон

Стили для всплывающих окон реализовываются немного иначе чем в других виджетах, поскольку popup является в некоторой степени контейнером. В общем случае процесс установки стиля происходит следующим образом: создается объект макета, затем ему устанавливается один из стандартных стилей предусмотренных для всплывающих окон. И потом в зависимости от выбранного стиля, всплывающее окно наполняется содержимым.

Рассмотрим стили макетов для использования во всплывающих окнах.

Стиль "layout/popup/content/circle":

Имя стиля макета составное, оно состоит из класса, группы и стиля. У каждого представленного стиля класс - это "layout", далее следуют группа "popup" и стиль "content/circle". Установить данный стиль для макета можно с помощью следующей функции:

elm_layout_theme_set(layout, "layout", "popup", "content/circle");

Мы уже делали эту процедуру в 12-м уроке для макетов.

Данный стиль представляет собой две области в которые можно установить текст ("elm.text" – имя области для основного текста, "elm.text.title" – имя области для текста заголовка), а также одну область для установки кнопки, которая будет находится внизу экрана.

nw_017_01_ru

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

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

elm_object_part_content_set(popup, "button1", button);

В версии виджета для носимых устройств с круглым экраном, бывает две такие области для кнопок. Как вы могли догадаться их названия "button1" и "button2".

Стиль "layout/popup/content/circle/buttons1":

Это расширенный за счет анимаций области кнопки стиль "layout/popup/content/circle". Структурно эти два стиля ничем не отличаются.

Стиль "layout/popup/content/circle/buttons2":

Как и макет "content/circle" и "content/circle/buttons1" этот стиль имеет текстовую зону и заголовок. Но отличается тем, что имеет две кнопки слева (button1) и справа (button2), вместо одной внизу. Мы уже рассматривали в уроке 14 стили кнопок ("popup/circle/left" и "popup/circle/right") предусмотренные специально для этих областей.

nw_017_03_ru

Вслывающее окно с таким стилем мы и добавим в наше демо приложение для подтверждения завершения его работы.

Смарт события всплывающего окна

Виджет поддерживает следующие смарт события:

"timeout" – событие срабатывает по истечению времени заданного вызовом функции elm_popup_timeout_set() когда всплывающее окно автоматически скрывается.

"block,clicked". Некоторые стили всплывающих окон, имеют область которая перекрывает основной пользовательский интерфейс во избежании действий с ним. Когда пользователь нажимает на эту область данное событие и срабатывает.

Так во всплывающем окне со стилем "circle/toast" такая область размещена поверх всего пользовательского интерфейса и поверх самого виджета. Таким образом если пользователь нажмет в любом месте всплывающего окна, сработает данное событие. Обычно при таком действии стоит закрывать popup.

"show,finished" – после указания отобразить всплывающее окно, происходит некоторая анимация появления, данное событие происходит после завершения такой анимации.

"dismissed" – данное событие подобно предыдущему, только срабатывает после анимации исчезновения всплывающего окна, в результате вызова функции elm_popup_dismiss() которую мы рассмотрели ранее в этом уроке.

"language,changed" – поскольку всплывающее окно наследуюется от макета, этот сигнал также поддерживается. При изменении языка в системе вы сможете обработать зарегестрировав колбек на данный сигнал.

Добавляем всплывающее окно в демо-приложение

Перейдем к практике и закончим наше демо-приложение. Мы будем создавать всплывающее окно с двумя кнопками: отмена и подтверждение. Также будет отображаться вопрос о закрытии приложения. В случае подтверждения мы будем закрывать приложение, иначе просто удалять всплывающее окно по нажатию кнопки отмена или аппаратной кнопки назад.

Добавим указатель на всплывающее окно в нашу структуру с виджетами.

Evas_Object *popup;

Теперь получилась такая структура.

typedef struct _UIData {
   Evas_Object *win;
   Evas_Object *conform;
   Evas_Object *layout;
   Evas_Object *button;
   Evas_Object *label;
   Evas_Object *popup;

   int click_count;
} UIData;

Подготовим новую функцию с помощью которой мы будем создавать всплывающие окна.

static void
_exit_popup_create(UIData *ui)
{
}

Создаем объект всплывающего окна и устанавливаем его круглый стиль.

ui->popup = elm_popup_add(ui->layout);
elm_object_style_set(ui->popup, "circle");

Теперь создадим макет для содержимого со стилем "content/circle/buttons2" и установим его как содержимое для popup.

Evas_Object *popup_layout = elm_layout_add(ui->popup);
elm_layout_theme_set(popup_layout, "layout", "popup", "content/circle/buttons2");
elm_object_content_set(ui->popup, popup_layout);

После создания макета можно установить основной текст и заголовок.

elm_object_part_text_set(popup_layout, "elm.text", "Закрыть приложение?");
elm_object_part_text_set(popup_layout, "elm.text.title", "Подтверждение");

Теперь необходимо разобраться с кнопками для всплывающего окна.

Будем использовать две кнопки со стилями "popup/circle/left" и "popup/circle/right". Нам нужно будет добавить иконки (крестик и галочку) в эти кнопки, посредством виджета-изображения.

Можете воспользоваться нашими ресурсами скачав эти картинки ниже и поместив их в папку res/ вашего проекта.

nw_017_04 nw_017_05

Мы сейчас не будем останавливаться подробно на виджете для отображения изображений, можете просто скопировать две следующие функции для создания виджета с указанным изображением в ваш код.

static void
_file_abs_resource_path_get(char *res_file_path, char *abs_path, int buf_size)
{
   char *res_dir_path = app_get_resource_path();

   if (res_dir_path)
     {
        snprintf(abs_path, buf_size, "%s%s", res_dir_path, res_file_path);
        free(res_dir_path);
     }
}

static Evas_Object *
_image_create(Evas_Object *parent, char *image_name)
{
   Evas_Object *icon = elm_image_add(parent);

   char image_path[PATH_MAX] = {0,};
   _file_abs_resource_path_get(image_name, image_path, PATH_MAX);
   elm_image_file_set(icon, image_path, NULL);

   evas_object_show(icon);

   return icon;
}

Вызов последней функции создаст и вернет объект виджета-изображения на основании переданного родительского виджета и названия изображения находящегося в папке res/ вашего проекта.

Создадим функцию которой будем пользоваться для создания кнопок для всплывающего окна, будем передавать родительский виджет, стиль для кнопки и имя иконки которую необходимо использовать в кнопке.

static Evas_Object *
_popup_button_create(Evas_Object *parent, char *style, char *icon_name)
{
   Evas_Object *button = elm_button_add(parent);

   elm_object_style_set(button, style);

   Evas_Object *btn_icon = _image_create(button, icon_name);
   elm_object_content_set(button, btn_icon);

   evas_object_show(button);

   return button;
}

Мы подробно рассматривали кнопку и ее создание в 14-м уроке.

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

Создаем левую кнопку для отмены выхода из приложения и помещаем ее в область "button1" всплывающего окна. И сразу зарегистрируем обработчик нажатия этой кнопки.

static void
_exit_popup_create(UIData *ui)
{
   ...

   Evas_Object *left_button  = _popup_button_create(popup_layout, "popup/circle/left", "cancel.png");
   elm_object_part_content_set(ui->popup, "button1", left_button);
   evas_object_smart_callback_add(left_button, "clicked", _cancel_exit_cb, ui);

   ...
}

Создаем правую кнопку для подтверждения выхода из приложения и помещаем ее в область "button2" всплывающего окна. И сразу зарегистрируем обработчик нажатия этой кнопки.

static void
_exit_popup_create(UIData *ui)
{
   ...

   Evas_Object *right_button = _popup_button_create(popup_layout, "popup/circle/right", "apply.png");
   elm_object_part_content_set(ui->popup, "button2", right_button);
   evas_object_smart_callback_add(right_button, "clicked", _apply_exit_cb, ui);

   ...
}

Реализуем небольшую функцию для удаления всплывающего окна.

static void
_remove_popup(UIData *ui)
{
   evas_object_del(ui->popup);
   ui->popup = NULL;
}

Мы устанавливаем указателю значение NULL после удаления объекта, поскольку функционал метода evas_object_del() не позволяет это сделать автоматически, а нам далее предстоит следить создано ли всплывающее окно как-раз по состоянию указателя на виджет.

Теперь реализуем функционал самих обработчиков для созданных кнопок.

static void
_cancel_exit_cb(void *data, Evas_Object *obj, void *info)
{
   UIData *ui = data;

   _remove_popup(ui);
}

static void
_apply_exit_cb(void *data, Evas_Object *obj, void *info)
{
   ui_app_exit();
}

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

Последним шагом отображаем всплывающее окно уже знакомой функцией.

static void
_exit_popup_create(UIData *ui)
{
   ...

   evas_object_show(ui->popup);
}

Теперь переделаем функцию обработчик нажатия аппаратной кнопки назад. Нам нужно создавать и отображать popup если он еще не был создан, в противном случае удалять виджет. Обработчик должен выглядеть таким образом.

static void
_win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
   UIData *ui = data;

   if (!ui->popup)
     {
        _exit_popup_create(ui);
     }
   else
     {
        _remove_popup(ui);
     }
}

Запустим наше приложение и посмотрим как оно работает.

На этом создание всплывающего окна и нашего демо-приложения завершено.

Полный исходный код этого урока вы можете скачать здесь WearLesson017.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *