Опубліковано: 25 Жовтня 2017
Спливаюче вікно з елементами управління (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_uk

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

Встановлення кнопок у спливаючому вікні відбувається не напряму в макет, як це було з текстом, а представленим нижче викликом, прямо в 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_uk

Далі ми розглянемо, як додати спливаюче вікно з таким стилем до демо-додатку для підтвердження завершення його роботи.

Смарт подія спливаючого вікна

Віджет підтримує наступні смарт події:

"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);
     }
}

Запустіть додаток і подивіться як він працює.

На цьому створення спливаючого вікна у вашому демо-додатку pзавершено.

Повний початковий код цього уроку ви можете знайти тут WearLesson017.

Залишити відповідь

Ваша e-mail адреса не оприлюднюватиметься. Обов’язкові поля позначені *