Опубліковано: 25 Жовтня 2017
Popup. Toast стиль. Типи подій скроллера

Продовжуємо написання нашого другого демо-додатку. У цьому уроку ми розкажемо, які події можна відловлювати в скроллері і покажемо, як їх можна використовувати. Далі ми розберемо, як можна створити спливаюче вікно (Toast) з відображенням повідомлення для інформування користувача. І в кінці уроку, ми подивимось, як перетворити даний додаток в простеньку гру.

Події скроллера

Скроллер – це контейнер бібліотеки Elementary і реалізовує свої смарт-колбеки. Це може бути зручно в деяких ситуаціях, наприклад, можна дізнатись, коли область прокрутки досягнула межі контенту чи закінчилась анімація прокрутки. У носимих пристроях підтримуються наступні види сигналів, які можна використовувати для обробки зв’язку з контейнером:

“edge,left” – подія, коли контент прокручений до лівої межі.

“edge,right” – подія, коли контент прокручений до правої межі.

“edge,top” – подія, коли контент прокручений до верхньої межі.

“edge,bottom” – подія, коли контент прокручений до нижньої межі.

“scroll” – подія викликається під час прокрутки контенту (викликається безліч разів).

“scroll,anim,start” – подія з таким сигналом буде викликатись у двох випадках. Перший – коли користувач зробить швидкий свайп в області прокрутки, то скроллер продовжить свій рух і поступово зупиниться. У цьому разі сигнал відбудеться, коли користувач забере палець зі скроллера. Другий випадок, коли для скроллера, в коді, буде викликана одна з наведених нижче функцій, яка, по заданих параметрах, плавно перемістить область прокручування.

void elm_scroller_region_bring_in(Evas_Object *obj, Evas_Coord x, Evas_Coord y, Evas_Coord w, Evas_Coord h);
void elm_scroller_page_bring_in(Evas_Object *obj, int h_pagenumber, int v_pagenumber);

“scroll,anim,stop” – подія викликається, коли анімація, описана в попередньому сигналі, завершилась.

“scroll,drag,start” – подія, яка викликається, коли користувач починає переміщувати контент в області прокручування.

“scroll,drag,stop” – подія, яка викликається, коли користувач перестає переміщувати контент в області прокручування.

Toast стиль для Popup (Спливаюче вікно)

Інколи в додатках виникає ситуація, коли для користувача необхідно вивести деяку текстову інформацію, наприклад, невелику підказку чи повідомлення про помилку. Для цього існує Toast спливаюче вікно. В Tizen, від Popup, який ми розглядали в 16 уроку, цей віджет відрізняється лише стилем. Додайте у ваш додаток спливаюче повідомлення, що якщо користувач проведе пальцем по екрані, він може перемістити зображення. Розширте вашу структуру з віджетами, додавши вказівник для нового віджету спливаючого вікна, який буде створено далі.

Evas_Object *toast_help;

Ви отримаєте наступний вміст вашої структури з віджетами:

typedef struct _UIData {
     Evas_Object *win;
     Evas_Object *conform;
     Evas_Object *toast_help;
     Evas_Object *scroller;
     Evas_Object *image;
  } UIData;

Для створення і роботи спливаючого вікна, напишіть дві функції, як на прикладі знизу.

static void
_toast_click_cb(void *data, Evas_Object *toast, void *event_info)
{
   evas_object_del(toast);
}

static void
_toast_create(UIData *ui)
{
   ui->toast_help = elm_popup_add(ui->conform);
   elm_object_style_set(ui->toast_help, "toast/circle");

   const float TIMEOUT_TIME = 5.0; // Секунди
   elm_popup_timeout_set(ui->toast_help, TIMEOUT_TIME);

   const char *MESSAGE = "Проведіть пальцем по екрану для переміщення...";
   elm_object_part_text_set(ui->toast_help, "elm.text", MESSAGE);

   evas_object_smart_callback_add(ui->toast_help, "block,clicked", _toast_click_cb, NULL);

   evas_object_show(ui->toast_help);
}

Давайте розглянемо, як створюється Toast.

Для створення об’єкту віджету використовується наступний виклик:

ui->toast_help = elm_popup_add(ui->conform);

Для встановлення стилю, як віджетам, так і контейнеру Elementary, викликається вказана нижче функція. Стиль Toast для носимого пристрою з круглим дисплеєм називається “toast/circle”. Як і для інших віджетів, першим параметром йде вказівник на об’єкт віджета, а другим – ім’я стилю, який необхідно встановити.

elm_object_style_set(ui->toast_help, "toast/circle");

Для спливаючого вікна можна встановити тимчасову затримку, після якої вікно закриється. Якщо вікно вже відображено, таймер затримки стартує під час виклику функції, якщо вікно ще не показане на екрані – таймер спрацює, коли буде викликана функція відображення об’єкту. Встановіть 5-ти секундну затримку у вашому спливаючому вікні.

const float TIMEOUT_TIME = 5.0; // Секунди
elm_popup_timeout_set(ui->toast_help, TIMEOUT_TIME);

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

const char *MESSAGE = "Проведіть пальцем по екрану для переміщення… ";
elm_object_part_text_set(ui->toast_help, "elm.text", MESSAGE);

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

Віджет спливаючого вікна реалізує смарт-подію натискання (сигнал “block,clicked”). Сигнатура функції така, як і в стандартному смарт-колбеці: перший параметр – вказівник на дані користувача, другий – сам смарт-колбек для якого викликається подія(у даному випадку – спливаюче вікно), третій – вказівник на дані з параметрами події.

static void
_toast_click_cb(void *data, Evas_Object *toast, void *event_info)
{
   evas_object_del(toast);
}

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

   evas_object_smart_callback_add(ui->toast_help, "block,clicked", _toast_click_cb, NULL);

   ...
}

Після всіх дій з підготовки, відобразіть ваш Toast, після чого запустіть 5-ти секундний таймер, який ви встановили для спливаючого повідомлення.

evas_object_show(ui->toast_help);

Додайте виклик функції для створення Toast віджету, після того, як створений скроллер і його вміст було поміщено в конформант.

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

   _scroller_create(ui);
   elm_object_content_set(ui->conform, ui->scroller);

   _toast_create(ui);

   ...
}

Оскільки на даний момент, при натисканні на апаратну кнопку Назад, ваш додаток згортає головне вікно, а спливаюче вікно, як і всі віджети, створюється один раз при першому запуску, то воно буде відображено тільки один раз. Для того аби ви бачили підказку в Toast кожного разу, необхідно згортання вікна замінити на закриття додатку, для цього змініть наступний колбек, що зареєстрований на натискання кнопки Назад.

static void
_win_back_cb(void *data, Evas_Object *obj, void *event_info)
{
   ui_app_exit();
}

Ще один варіант – це створення Toast перенести в колбек події resume життєвого циклу додатку. Але в цьому прикладі ми цього робити не будемо.

Тепер подивіться, що у вас має вийти:

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

Робимо міні-гру з нашого демо-додатку

Як і було сказано раніше, зараз ми покажемо вам, як перетворити ваш демо-додаток у міні-гру, на основі вивченого в цьому уроку матеріалу. Умови гри: користувач знаходиться на великій карті, де переміщуючи карту по екрану, повинен знайти скарб. На карті буде лінія, що допомагатиме користувачу.

Для початку необхідно замість поточного зображення використовувати зображення з картою. Ми намалювали ось таку карту і пропонуємо вам використати її у вашій грі.

nw_019_02_uk

Зображення карти досить велике, одна клітинка має розмір: 360x360.

Помістіть її у ваш проект за наступним шляхом: res/images/map.jpg.

Тепер вкажіть вашому віджету шлях до цього зображення.

Для цього замініть “images/image_big.png” на “images/map.jpg”

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

   char abs_path_to_image[PATH_MAX] = {0,};
   _file_abs_resource_path_get("images/map.jpg", abs_path_to_image, PATH_MAX);
    
   ...
}

По горизонталі і по вертикалі, вкажіть на вашій карті координати, де знаходиться скарб:

nw_019_03

Припустимо, що X=3908, а Y=943.

Оскільки, кожного разу, коли відбувається переміщення області прокручування, ви будете перевіряти чи увійшла точка зі скарбом в область скроллера, вам необхідно зареєструвати колбек для скроллера на подію "scroll". Для цього, додайте наступний виклик функції створення скроллера:

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

   evas_object_smart_callback_add(ui->scroller, "scroll", _scroll_cb, ui);

   ...
}

Як і при реєстрації будь-якого смарт колбеку, перший параметр – це вказівник на об’єкт віджет, другий – ім’я сигналу/події, третій – вказівник на смарт колбек, функцію, що має бути викликана, і четвертий – дані, які ви хочете далі використовувати всередині функції під час виклику колбеку.

Далі створіть саму функцію-колбек.

static void
_scroll_cb(void *data, Evas_Object *scroller, void *event_info)
{
   UIData *ui = data;
}

Перший аргумент був перетворений до того типу, який ви використовували в якості додаткових даних колбеку, під час його реєстрації.

Як уже було сказано, у цьому колбеці буде проходити перевірка умови: знайдено скарб чи ні. Спочатку визначте, де зараз знаходиться зона прокрутки відносно контенту. Для отримання цих даних у скроллера є наступна функція:

Evas_Coord x = 0;
Evas_Coord y = 0;
Evas_Coord w = 0;
Evas_Coord h = 0;
elm_scroller_region_get(ui->scroller, &x, &y, &w, &h);

Функція останніми 4-ма параметрами приймає 4 вказівники на тип Evas_Coord (перевизначений int). Аргументи йдуть в наступному порядку: спочатку положення верхнього лівого кута по горизонталі, потім положення верхнього лівого кута по вертикалі, ширина і останньою - висота області.

На контенті, визначте центр цієї області, використовуючи наступні дії:

int center_x = x + w / 2;
int center_y = y + h / 2;

Додайте константи для координати скарбу, які ви отримали для вашої карти.

const int TREASURE_X = 3908;
const int TREASURE_Y = 943;
const int AREA_RADIUS = 150;

Третя константа буде використовуватись в якості радіусу круглої зони, на потрапляння бажаної точки в яку, ви будете чекати. Оскільки скроллер, розмір якого становить 360х360, розтягнений на весь екран, значить радіус круглого екрану становить 180. Візьміть круг трохи меншого розміру, щоб хрестик на карті спочатку повністю увійшов в екран, після чого ви будете повідомляти, що скарб знайдено.

Для визначення чи знаходиться точка в кругу, напишіть наступну функцію:

static Eina_Bool
_is_point_in_circle(double area_center_x,
                    double area_center_y,
                    double area_radius,
                    double checking_point_x,
                    double checking_point_y)
{
   double delta_x = fabs(area_center_x - checking_point_x);
   double delta_y = fabs(area_center_y - checking_point_y);
   double distance = sqrt(delta_x * delta_x + delta_y * delta_y);

   Eina_Bool is_in_circle = EINA_FALSE;
   if (distance < area_radius)
     {
        is_in_circle = EINA_TRUE;
     }

   return is_in_circle;
}

Перші три параметри функції – це координати центру окружності і радіус, останні два – координати точки, яку потрібно перевірити. Іншими словами, вам потрібно знайти відстань між центром окружності і точкою, яка перевіряється на входження в радіус. Якщо відстань менша ніж радіус окружності, то точка входить в окружність.

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

static void
_win_toast_create(UIData *ui)
{
   Evas_Object *toast_win = elm_popup_add(ui->conform);
   elm_object_style_set(toast_win, "toast/circle");
   const char *MESSAGE = "Вітаємо! Ви знайшли скарб!! ";
   elm_object_part_text_set(toast_win, "elm.text", MESSAGE);
   evas_object_smart_callback_add(toast_win, "block,clicked", _toast_click_cb, NULL);
   evas_object_show(toast_win);
}

Функцію-колбек, яка буде використовуватись для натискання користувачем на Toast, візьміть туж, що і для спливаючого вікна допомоги, тому аби уникнути помилок, переконайтесь, що функція _toast_click_cb() оголошена в коді вище, ніж щойно створена _win_toast_create(). Допоміжні функції готові, тепер ви можете використати їх.

Перевірте чи увійшла точка з скарбом в область прокручування і якщо так, то створіть і відобразіть спливаюче вікно з привітанням. Це необхідно зробити в колбеку скроллера на подію прокручування.

static void
_scroll_cb(void *data, Evas_Object *scroller, void *event_info)
{
   ...

   if (_is_point_in_circle(center_x, center_y, AREA_RADIUS, TREASURE_X, TREASURE_Y))
     {
        _win_toast_create(ui);
     }
}

Поведінка скроллера дозволяє різко двинути область прокрутки і вона по інерції буде прокручуватись в заданому напрямку ще деякий час. Тут може виникнути ситуація, що ви створили дуже багато спливаючих вікон, тому якщо область знайдена, необхідно явно зупинити скроллер. У бібліотеці немає спеціальної функції аби просто зупинити скроллер, але є функція, яка встановлює регіон, який необхідно показати скроллеру. При цьому, ні анімація, ні будь-який колбек скроллеру не викликається, а це якраз те, що необхідно в даній ситуації. Для цього одразу після створення спливаючого вікна, яке повідомляє, що скарб знайдено, викличте наступну функцію:

elm_scroller_region_show(ui->scroller, x, y, w, h);

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

elm_object_scroll_lock_x_set(ui->image, EINA_TRUE);
elm_object_scroll_lock_y_set(ui->image, EINA_TRUE);

Якщо ви хочете «розморозити» прокручування віджету, то вам необхідно викликати ці функції з другим параметром: EINA_FALSE.

Наостанок видаліть вбудовані індикаційні віджети скроллера (сині полоси зліва і знизу). Для цього скористайтесь наступною функцією:

elm_scroller_policy_set(ui->scroller, ELM_SCROLLER_POLICY_OFF, ELM_SCROLLER_POLICY_OFF);

У цій функції 2-й і 3-й параметри відносяться до горизонтального і вертикального віджета відповідно. У якості цих параметрів можна передати наступні аргументи:

ELM_SCROLLER_POLICY_AUTO – автоматично показувати індикатор тільки під час прокручування, в інший час- ховати.

ELM_SCROLLER_POLICY_ON – завжди показувати індикатор. ELM_SCROLLER_POLICY_OFF – ніколи не показувати індикатор.

Тепер подивіться на відео, яка гра у вас має вийти.

Завантажити повний початковий код даного уроку ви можете тут WearLesson019.

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

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