У цьому уроку ми розберемо, як створювати скроллер-контейнер; як заповнити контейнер-коробку, що був створений в попередньому уроку, сторінками із зображеннями. У якості сторінки буде використано стандартний макет. Далі розмістимо коробок у створений скроллер. І потім ми навчимо вас використовувати властивості скроллера для реалізації посторінкового перегляду.
Спочатку додайте скроллер і помістіть його в конформант замість коробка, а сам коробок помістіть в скроллер для його подальшого прокручування.
Додайте вказівник на скроллер в структуру з віджетами.
Evas_Object *scroller;
У вас має вийти наступна структура з графічними компонентами:
typedef struct _UIData {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *scroller;
Evas_Object *box;
} UIData;
Реалізуйте наступну функцію для створення скроллера і розміщення в ньому коробки. Подібне ви вже робили в попередніх уроках.
static void
_scroller_create(UIData *ui)
{
ui->scroller = elm_scroller_add(ui->conform);
_box_create(ui);
elm_object_content_set(ui->scroller, ui->box);
evas_object_show(ui->scroller);
}
Тепер замініть батьківський елемент для коробки. Оскільки у разі видалення скроллера, потрібно автоматично видаляти коробку – необхідно зберігати правильну ієрархію, для чого слід замінити конформант на скроллер. Зробіть зміни в наступній функції:
static void
_box_create(UIData *ui)
{
ui->box = elm_box_add(ui->scroller);
...
}
А тепер змініть контент конформанта, замінивши коробок на скроллер.
static void
_conformant_create(UIData *ui)
{
...
_scroller_create(ui);
elm_object_content_set(ui->conform, ui->scroller);
...
}
Перейдемо до додавання контенту в коробок. Візьміть наступні 5 зображень і використайте їх в якості контенту.
Створіть дві функції для завантаження і відображення віджетів-зображень, як це вже було зроблено в 18 уроку.
Функція для отримання повного шляху по заданому імені зображення в папці res/ проекту. изображения в папке res/ проекта.
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 *image = elm_image_add(parent);
char abs_path_to_image[PATH_MAX] = {0,};
_file_abs_resource_path_get(image_name, abs_path_to_image, PATH_MAX);
elm_image_file_set(image, abs_path_to_image, NULL);
evas_object_size_hint_weight_set(image, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(image, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_show(image);
return image;
}
Тепер створіть макет зі одним із стандартних стилів. Наприклад, використайте elm/layout/body_thumbnail/default стиль, який був описаний у 12 уроку. Підготуйте наступну функцію, яка буде створювати об’єкт макету і зображення, а також розміщувати його в elm.icon.
static Evas_Object *
_page_layout_create(Evas_Object *parent, int image_index)
{
Evas_Object *page_layout = elm_layout_add(parent);
elm_layout_theme_set(page_layout, "layout", "body_thumbnail", "default");
evas_object_size_hint_weight_set(page_layout, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(page_layout, EVAS_HINT_FILL, EVAS_HINT_FILL);
evas_object_show(page_layout);
const int MAX_NAME_LENGTH = 10;
char image_name[MAX_NAME_LENGTH] = {0,};
snprintf(image_name, MAX_NAME_LENGTH, "%d.png", image_index);
Evas_Object *image = _image_create(page_layout, image_name);
elm_object_part_content_set(page_layout, "elm.icon", image);
return page_layout;
}
Назвіть ваші зображення: 0.png, 1.png … 4.png. Для створення необхідного зображення, функція приймає індекс зображення другим параметром. Далі, використовуючи цю функцію, у циклі будуть створюватись сторінкові елементи і тоді буде зручно передавати лічильник циклу. Перейдемо до самого додавання елементів у коробку. Для цього використайте функцію:
elm_box_pack_end();
Додайте всі 5 сторінок у вашу коробку.
static void
_box_create(UIData *ui)
{
...
for (int i = 0; i <= 4; ++i)
{
Evas_Object *page_layout = _page_layout_create(ui->box, i);
elm_box_pack_end(ui->box, page_layout);
}
...
}
Запустіть додаток і подивіться, що у вас вийшло.
Як бачимо, вміст контейнеру розташовано зліва, це тому, що ви не вказали коробку вагові параметри. Через це він автоматично займає мінімальний розмір, який в цьому випадку, дорівнює ширині макету, який використовується, як вміст для коробка.
Крім того, необхідно змінити орієнтацію вмісту з вертикальної на горизонтальну.
Відразу після створення коробка необхідно викликати дві наступні функції:
static void
_box_create(UIData *ui)
{
...
elm_box_horizontal_set(ui->box, EINA_TRUE);
evas_object_size_hint_weight_set(ui->box, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
...
}
Нижче показано, що у вас має вийти.
Вже майже ідеально. Але тут видно, що перше і останнє зображення не доходять до центру екрану. Для того аби це виправити, необхідно додати деякі відступи на початок і в кінець коробка. Реалізуйте відступи з допомогою створення двох простих прозорих прямокутників. Потім встановіть їм розмір, який буде розраховуватись динамічно під час події зміни розміру сторінкового макету. Нижче схематично показано, для чого необхідні відступи (зелені прямокутники).
Додайте функцію, яка буде створювати такий прямокутник, а потім використайте її для додавання відступів на початку і в кінці коробка.
static Evas_Object *_padding_item_create(Evas_Object *parent)
{
Evas_Object *padding = evas_object_rectangle_add(evas_object_evas_get(parent));
evas_object_size_hint_weight_set(padding, EVAS_HINT_EXPAND, EVAS_HINT_EXPAND);
evas_object_size_hint_align_set(padding, EVAS_HINT_FILL, EVAS_HINT_FILL);
return padding;
}
Для додавання прямокутника, використайте наступну функцію:
evas_object_rectangle_add();
Ця функція, на відміну від функції Elementary, створює примітивний об’єкт, який не має особливої поведінки, такої як у кнопки чи списків, які підтримують смарт колбеки. Хоча примітивні об’єкти підтримують прості події, на кшталт EVAS_CALLBACK_MOUSE_DOWN чи EVAS_CALLBACK_SHOW.
На основі контенту, задайте розмір цим відступам. Оскільки при створенні об’єктів для відступу, ви не можете знати який розмір необхідно задати, ви повинні дочекатися події зміни розміру сторінки(макета зображення) і після цього взяти розмір.
Для поміщення відступу в коробок, використовуйте наведену вище функцію для створення і поміщення віджетів. Після створення всіх сторінок, встановіть прямокутники, скориставшись функцією для додавання контенту на початок і в кінець коробка.
Аби у колбеку, встановленому на подію зміни розміру, отримати доступ до вказівників на віджети відступу, їх необхідно помістити у структуру з головними віджетами.
Evas_Object *padding_start;
Evas_Object *padding_end;
Ви повинні отримати наступний вміст вашої структури з графічними компонентами:
typedef struct _UIData {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *scroller;
Evas_Object *box;
Evas_Object *padding_start;
Evas_Object *padding_end;
} UIData;
Тепер створіть і додайте самі відступи.
static void
_box_create(UIData *ui)
{
...
// Створення сторінок із зображеннями
ui->padding_start = _padding_item_create(ui->box);
elm_box_pack_start(ui->box, ui->padding_start);
ui->padding_end = _padding_item_create(ui->box);
elm_box_pack_end(ui->box, ui->padding_end);
...
}
Тепер реалізуйте функцію зворотного виклику для події зміни розміру останньої сторінки.
static void
_layout_resize_cb(void *data , Evas *e, Evas_Object *page_layout, void *event_info)
{
int page_width;
int page_height;
int container_width;
int container_height;
UIData *ui = data;
evas_object_geometry_get(page_layout, NULL, NULL, &page_width, &page_height);
evas_object_geometry_get(ui->scroller, NULL, NULL, &container_width, &container_height);
int padding_size = (container_width - page_width) / 2;
evas_object_size_hint_min_set(ui->padding_start, padding_size, container_height);
evas_object_size_hint_min_set(ui->padding_end, padding_size, container_height);
}
Коротко кажучи, потрібно отримати різницю між шириною контейнеру і шириною сторінки, отриманий результат поділити навпіл. Це і буде розмір відступів. Необхідно використати наведену нижче функцію для отримання геометрії об’єкту (x, y координати верхнього лівого кутка, висота і ширина).
evas_object_geometry_get(object, &x, &y, &width, &height);
Ну і нарешті, зареєструйте обробник на подію зміни розміру останньої сторінки. Відредагуйте вашу функцію створення коробка і його контенту.
static void
_box_create(UIData *ui)
{
...
Evas_Object *page_layout;
for (int i = 0; i <= 4; ++i)
{
page_layout = _page_layout_create(ui->box, i);
elm_box_pack_end(ui->box, page_layout);
}
evas_object_event_callback_add(page_layout, EVAS_CALLBACK_RESIZE, _layout_resize_cb, ui);
...
}
Подивіться на результат.
Контейнер скроллер може використовуватись для посторінкового перегляду, це означає, що при прокручуванні, він завжди буде зупиняти зону прокручування на початку сторінки. Ви можете створювати різні розміри і ліміт прокручування сторінок.
Наприклад, у цьому додатку можна зупинити прокручування так, як показано на наступному скріншоті, тобто - у будь-якому місці контенту.
Налаштуйте скроллер для посторінкового прокручування, щоб контент сторінок завжди залишався посередині області.
Для цього використайте функцію:
elm_scroller_page_size_set(Evas_Object *obj, Evas_Coord width, Evas_Coord height);
Функція, як аргумент приймає розмір сторінки для прокручування. У цьому разі ви можете додати виклик цієї функції під час події зміни колбека зареєстрованого на зміну розміру останньої сторінки, де раніше розраховувались розміри відступів. Додайте виклик у кінець функції обробника, де у вас вже є розмір сторінки.
static void
_layout_resize_cb(void *data , Evas *e, Evas_Object *page_layout, void *event_info)
{
...
elm_scroller_page_size_set(ui->scroller, page_width, page_height);
}
Отриманий результат відповідає очікуванням.
Інколи виникає необхідність отримати подію зміни поточної сторінки. Оскільки, в реалізації скроллера для носимих пристроїв не передбачено цього сигналу, вам доведеться реалізувати його самостійно. Для цього вам потрібно підписатись на подію scroll скроллера, а в самому обробнику перевіряти чи змінилась поточна сторінка. У вас має вийти наступний обробник події:
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)
{
dlog_print(DLOG_DEBUG, "Lesson21", "Нова активна сторінка: %d", cur_h_page);
prev_h_page = cur_h_page;
}
}
Тут була використана функція отримання порядкового номеру поточної сторінки скроллеру.
elm_scroller_current_page_get(const Evas_Object *obj, int *h_number, int *v_number);
Функція приймає скроллер, для якого потрібно отримати значення і вказівники на цілочисельні змінні, в які необхідно записати порядкові номери сторінки по горизонталі і по вертикалі.
У результаті виведіть в логування інформацію про зміни поточної сторінки, оскільки вам зараз немає до чого прикріпити цю подію. Не забутьте включити заголовний файл для використання логування.
#include <dlog.h>
Тепер після створення цього віджету, зареєструйте обробник для скроллера.
static void
_scroller_create(UIData *ui)
{
...
evas_object_smart_callback_add(ui->scroller, "scroll", _scroll_cb, ui);
...
}
Ось, що ви маєте отримати в результаті.
У наступному уроку ми прив’яжемо цю подію для скроллера до зміни індикатора сторінки.
Завантажити повний код даного уроку ви можете тут WearLesson021.