Опубліковано: 25 Жовтня 2017
Index

У цьому уроці ми розглянемо віджет індексації, навчимося його створювати і використовувати. Ми розглянемо тільки стиль circle для самого віджету індексації, в якому елементи розташовані на екрані по колу.

Важливо:

В емуляторі з версією Tizen 2.3.2 і менше віджет індексації зі стилем circle відображується не коректно, тому в цьому уроку для демонстрації ми використаємо емулятор з версією Tizen 3.0.0. Ця проблема пов’язана лише з темою емуляторів. На реальних пристроях індекс-віджет відображається коректно.

Опис віджету індексації

Віджет індексації використовується для індексації сторінок. У носимих пристроях з круглим дисплеєм він дозволяє відобразити від 1 до 20 індикаторів, підсвічуючи лише активний.

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

На даний момент на носимих пристроях з круглим дисплеєм, віджет індексації, загалом, використовується для відображення активної сторінки. Як уже було сказано, віджет може відображати 20 елементів.

nw_022_01_en

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

При наповненні індексу перший дуже важливий момент, це знати парна чи не парна кількість елементів має бути додана. Максимальна кількість непарних елементів в індексі дорівнює 19.

Для непарної кількості елементів використовується стиль з приставкою “item/odd_”, і в кінці ставиться порядковий номер елементу. Нижче перераховані всі можливі стилі для використання при непарній кількості елементів.

"item/odd_1"
"item/odd_2"

...

"item/odd_19"

Максимальна кількість парних елементів в індексі дорівнює 20.

Для парної кількості елементів використовується стиль з приставкою “item/even_”, в кінці також ставиться порядковий номер. Нижче перераховані всі можливі стилі для використання при парній кількості елементів.

"item/even_1"
"item/even_2"

...

"item/even_20"

Тепер давайте розглянемо вибір стилю для центрального елементу.

Для непарної кількості елементів – це стиль "item/odd_10", він завжди повинен встановлюватись середньому елементу. Наприклад, якщо у вас є три елементи, ви повинні їх додати і встановити їм стилі в наступному порядку:

"item/odd_9", "item/odd_10", "item/odd_11".

Для 5-ти:

"item/odd_8", "item/odd_9", "item/odd_10", "item/odd_11", "item/odd_12".

И так далі.

Для віджета з парною кількістю елементів, існує два центральних стилі: "item/even_10" і "item/even_11". Так, для віджета з двома елементами, додається лише ці два стилі, а для віджета з 4-ма:

"item/odd_9", "item/odd_10", "item/odd_11", "item/odd_12".

Як ви могли помітити, сусідні елементи повинні мати суфікси стилю, що відрізняються на 1.

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

nw_022_02_en

Тут були допущені наступні помилки із вибором стилів:

1. Вибрано набір стилів для непарної кількості елементів, хоча кількість елементів у даному випадку парна.

2. Переплутані порядкові номери стилів, не враховано, що сусідні стилі мають відрізнятись один від одного на 1 порядковий номер.

3. Неправильно вибрано стиль для центрального елементу.

4. Використані парні і непарні елементи одночасно.

Правильне використання стилів показано нижче на картинці.

nw_022_03_en

Тут ми використовували стилі "item/even_#" для парної кількості елементів, нумерація [7, 8, 9, 10, 11, 12, 13, 14].

Елементи повинні бути розташовані по контуру круга. Це стосується тільки стилю circle самого віджету-індексації, а не його елементів.

Підготовка додатку для додавання індексу

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

Додайте макет з двома областями. Одна з них (фонова) буде використовуватись для поміщення скроллеру з його контентом, а друга (передня) буде використовуватись індекс-віджетом. Для цього додатку згодиться макет зі стандартною темою elm/layout/application/default. Ми розбирали цей макет в 12-му уроку. Приклад ви можете подивитись на картинці знизу.

nw_022_04_en

Давайте перейдемо до коду.

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

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

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

   ...
}

Тепер в структуру з головними віджетами, додайте вказівник на макет.

Evas_Object *layout;

Вийде наступний зміст структури з графічними компонентами:

typedef struct _UIData {
     Evas_Object *win;
     Evas_Object *conform;
     Evas_Object *layout;
     Evas_Object *scroller;
     Evas_Object *box;
     Evas_Object *padding_start;
     Evas_Object *padding_end;
  } UIData;

Для створення макету напишіть окрему функцію. І перенесіть в неї створення і розміщення скроллера в нижню область, у цьому разі ця фонова область називається elm.swallow.bg.

static void
_layout_create(UIData *ui)
{
   ui->layout = elm_layout_add(ui->conform);
   elm_layout_theme_set(ui->layout, "layout", "application", "default");

   _scroller_create(ui);
   elm_object_part_content_set(ui->layout, "elm.swallow.bg", ui->scroller);

   evas_object_show(ui->layout);
}

Тепер замініть вміст вашого конформанта зі скроллера на макет.

static void
_conformant_create(UIData *ui)
{
   ...
     
   _layout_create(ui);
   elm_object_content_set(ui->conform, ui->layout);

     ...
}

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

static void
_scroller_create(UIData *ui)
{
   ui->scroller = elm_scroller_add(ui->layout);

   ...
}

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

Створіть константу, що вказує на кількість сторінок, яку необхідно створити. Далі вона буде також використана для правильного створення елементів індекс-віджету.

Додайте глобальну константу.

static const int PAGES_COUNT = 5;

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

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

   const int IMAGES_COUNT = 5;

   Evas_Object *page_layout;
   for (int i = 0; i < PAGES_COUNT; ++i)
     {
        page_layout = _page_layout_create(ui->box, i % IMAGES_COUNT);
        elm_box_pack_end(ui->box, page_layout);
     }

   ...
}

Тепер, наприклад, якщо кількість сторінок буде дорівнювати 6-ти, то сторінка з індексом 5 буде містити зображення 0.png замість неіснуючого 5.png.

Створення віджету індексації

Створіть індекс-віджет.

Evas_Object *index = elm_index_add(ui->layout);

Встановіть йому круглий стиль.

elm_object_style_set(index, "circle");

Налаштуйте індекс на горизонтальне відображення. Оскільки стиль заточений під горизонтальне використання, то і сторінки розташовані горизонтально.

elm_index_horizontal_set(index, EINA_TRUE);

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

elm_index_autohide_disabled_set(index, EINA_TRUE);

Додайте два масиви для парних і непарних конфігурацій.

// Стилі для парної кількості сторінок
static const char *even_style[] = {
   "item/even_1",
   "item/even_2",
   "item/even_3",
   "item/even_4",
   "item/even_5",
   "item/even_6",
   "item/even_7",
   "item/even_8",
   "item/even_9",
   "item/even_10",
   "item/even_11",
   "item/even_12",
   "item/even_13",
   "item/even_14",
   "item/even_15",
   "item/even_16",
   "item/even_17",
   "item/even_18",
   "item/even_19",
   "item/even_20",
};

// стилі для непарної кількості сторінок
static const char *odd_style[] = {
   "item/odd_1",
   "item/odd_2",
   "item/odd_3",
   "item/odd_4",
   "item/odd_5",
   "item/odd_6",
   "item/odd_7",
   "item/odd_8",
   "item/odd_9",
   "item/odd_10",
   "item/odd_11",
   "item/odd_12",
   "item/odd_13",
   "item/odd_14",
   "item/odd_15",
   "item/odd_16",
   "item/odd_17",
   "item/odd_18",
   "item/odd_19",
};

Додайте функціонал для визначення кількісті сторінок (парна чи не парна) і стартовий індекс елементу масиву стилів.

Eina_Bool is_even_count = PAGES_COUNT % 2 == 0;
const int CENTER_INDEX = is_even_count ? 10 : 9;
int start_index = CENTER_INDEX - PAGES_COUNT / 2;
const char **style = is_even_count ? even_style : odd_style;

Додайте елементи індексу і установіть їм необхідні стилі, у відповідності з кількістю сторінок.

for (int i = 0; i < PAGES_COUNT; ++i)
  {
     Elm_Object_Item *it = elm_index_item_append(index, NULL, NULL, (void *)i);
     elm_object_item_style_set(it, style[start_index + i]);
  }

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

Третій аргумент – вказівник на функцію-колбек, яка буде викликана при активації даного елементу. У цьому додатку вона також не потрібна. Останнім аргументом передайте порядковий номер сторінки, ці дані будуть прикріплені до елементу індексу. Ви можете прикріпити будь-які дані до елементів у своїх додатках, але в цьому разі вам достатньо зберігати лише індекс елементу.

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

elm_index_level_go(index, 0);

Відобразіть віджет.

evas_object_show(index);

У вас має вийти наступна функція для створення індексу:

static Evas_Object *
_index_create(UIData *ui)
{
   Evas_Object *index = elm_index_add(ui->layout);

   elm_object_style_set(index, "circle");
   elm_index_horizontal_set(index, EINA_TRUE);
   elm_index_autohide_disabled_set(index, EINA_TRUE);

   Eina_Bool is_even_count = PAGES_COUNT % 2 == 0;
   const int CENTER_INDEX = is_even_count ? 10 : 9;
   int start_index = CENTER_INDEX - PAGES_COUNT / 2;
   const char **style = is_even_count ? even_style : odd_style;
   for (int i = 0; i < PAGES_COUNT; ++i)
     {
        Elm_Object_Item *it = elm_index_item_append(index, NULL, NULL, (void *)i);
        elm_object_item_style_set(it, style[start_index + i]);
     }

   elm_index_level_go(index, 0);
   evas_object_show(index);

   return index;
}

Викличте її і помістіть індекс у попередню область макету, що був створений раніше.

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

   ui->index = _index_create(ui);
   elm_object_part_content_set(ui->layout, "elm.swallow.content", ui->index);

   ...
}

Запустіть і подивіться на результат.

Як ви можете бачити, віджет-індексації відобразився, але нічого не було вибрано і не відбувається для гортання.

Активізуємо елементи виджета-індексації

Оскільки стандартної функції не передбачено, створіть функцію для активації елементу, передаючи як аргумент віджет-індекс і порядковий номер елемента, який необхідно активувати.

static void
_page_indicator_selected_set(Evas_Object *index, int page_index)
{
   Elm_Object_Item *item_to_select = elm_index_item_find(index, (void *)page_index);
   elm_index_item_selected_set(item_to_select, EINA_TRUE);
}

Тут була використана функція для пошуку елемента по прикріпленим до нього даним(знаючи, що прикріплений був порядковий номер). Тепер аби активувати перший елемент, викличте створену вами функцію для активації, яка спрацьовує після додавання всіх елементів.

static Evas_Object *
_index_create(UIData *ui)
{
   ...

   _page_indicator_selected_set(index, 0);

   ...
}

При зміні активної сторінки, необхідно активувати різні елементи. Створіть власні події для індексу, які будуть симулювати із обробника скроллера на зміну сторінки. Назвемо цей сигнал "active_page,changed".

Створіть для цього константу.

#define PAGE_CHANGED_EVENT "active_page,changed"

Створіть окремий обробник для індексу, де в залежності від поточної сторінки скроллера, будуть активуватись елементи. І підпишіть індекс на цю подію.

static void
_active_page_changed_cb(void *data, Evas_Object *index, void *event)
{
   UIData *ui     = data;
   int cur_h_page = 0;
   elm_scroller_current_page_get(ui->scroller, &cur_h_page, NULL);
   _page_indicator_selected_set(ui->index, cur_h_page);
}

static Evas_Object *
_index_create(UIData *ui)
{
   ...

   evas_object_smart_callback_add(index, PAGE_CHANGED_EVENT, _active_page_changed_cb, ui);

   ...
}

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

void evas_object_smart_callback_call(Evas_Object *obj, const char *event, void *info);

Вона буде використана з обробника події прокручування скроллера, що був створений в минулому уроку.

Там де ви виводили повідомлення в логування, тепер можна помістити емуляцію події зміни сторінки для індексу. Тепер колбек буде виглядати так:

static void
_scroll_cb(void *data, Evas_Object *scroller, void *event)
{
   static int prev_h_page = 0;
   int cur_h_page         = 0;
   elm_scroller_current_page_get(scroller, &cur_h_page, NULL);
   if (cur_h_page != prev_h_page)
     {
        UIData *ui = data;
        evas_object_smart_callback_call(ui->index, PAGE_CHANGED_EVENT, NULL);
        prev_h_page = cur_h_page;
     }
}

Тепер можете запустити ваш додаток і подивитись на результат.

Все повинно запрацювати. Повний код додатку ви можете скачати тут WearLesson022.

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

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

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