В этом уроке мы переходим к созданию нашего второго демо приложения. Сначала мы добавим изображение, затем мы поместим его в контейнер с прокручиваемой областью (Scroller). В следующем уроке мы добавим немного логики и превратим наше приложение в мини игру.
В нативной разработке Tizen для отображения изображения на экране обычно используется Image виджет. Этот виджет позволяет показывать изображение, а также отображать анимационные изображения .gif и проигрывать их.
Этот виджет позволяет использовать файл с изображением или напрямую область в памяти в которой хранится изображение. Последнее удобно, когда вы загружаете изображение из интернета, и вам нет нужды его сохранять.
Базовый проект который мы будем использовать в этом уроке можно взять здесь.
Это обычный UI приложение для носимого устройства в котором создаются окно и конформант.
Для начала мы создадим Image и сделаем его содержимым контейнера конформанта как показано на схеме ниже.
Мы возьмем следующее изображение и загрузим его в наше приложение.
Ресурсы приложения графические, аудио и другие советуется помещать в директорию res/ вашего проекта, к этой папке доступ имеется только у вашего приложения. Все содержимое этой папки во время сборки приложения попадает в .tpk пакет. Мы создали внутри директорию images/ и поместили изображение внутрь.
Расширим нашу структуру с виджетами указателем для нового виджета, который мы создадим дальше. Так как и все виджеты в EFL указатель на изображение будет иметь тип Evas_Object.
Evas_Object *image;
Получим следующее содержимое нашей структуры с виджетами.
typedef struct _UIData {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *image;
} UIData;
Создадим функцию в которой будем реализовывать работу с виджетом изображений.
static void
_image_create(UIData *ui)
{
}
Для создания нового виджета изображения используем следующую функцию:
ui->image = elm_image_add(ui->conform);
В функцию для создания изображения мы передаем указатель на виджет который будет предком для изображения. В результате метод вернет указатель на вновь созданное изображение.
Теперь нам нужно указать путь к изображению которое мы будем отображать в нашем виджете. Для этого используется следующая функция.
Eina_Bool elm_image_file_set(Evas_Object *obj, const char *file, const char *group);
Эта функция принимает полный путь к файлу изображения на устройстве вторым параметром, этот путь возможно получить во время выполнения приложения. В момент компиляции нам известен только путь к изображению относительно корня проекта, или подкаталога res/. Например в нашем случае мы знаем что наше изображение имеет следующий путь images/image.jpg внутри каталога res/ нашего проекта. Но нам необходимо получить абсолютный путь во время выполнения. В tizen есть функции для получения полного пути к некоторым директориям вашего приложения во время выполнения. Следовательно мы можем получить путь к директории и склеить его с путем к файлу от директории.
Следующая функция позволяет получить абсолютный путь к директории res/ вашего приложения во время его выполнения.
char *app_get_resource_path();
Давайте реализуем функцию которая будет генерировать нам из относительного пути – полный путь.
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);
}
}
Следующая функция принимает относительный путь к изображению первым параметром, указатель на буфер куда поместить абсолютный путь – вторым, и размер буфера – третим параметром.
Теперь можно использовать эту функцию. Добавляем следующий код после создания объекта виджета.
char abs_path_to_image[PATH_MAX] = {0,};
_file_abs_resource_path_get("images/image.jpg", abs_path_to_image, PATH_MAX);
Вы сможете использовать эту функцию таким путем, всегда когда будет необходимость получить полный путь к какому-либо ресурсу вашего приложения.
Теперь мы можем уже загрузить изображение в наш виджет.
elm_image_file_set(ui->image, abs_path_to_image, NULL);
Теперь осталось отобразить виджет.
evas_object_show(ui->image);
Теперь вызываем нашу функцию создания виджета изображения и помещаем его в конформант.
static void
_conformant_create(UIData *ui)
{
...
_image_create(ui);
elm_object_content_set(ui->conform, ui->image);
...
}
Теперь можем запустить наше приложение и посмотреть что получилось.
Как было сказано ранее Image виджет поддерживает .gif анимации для отображения. Но по умолчанию если вы укажете путь к такой анимации виджет отобразит файл как статическое изображение, для старта анимации необходимо вызвать несколько дополнительных функций.
Давайте попробуем использовать следующую анимацию в качестве ресурса.
Поместим ее по следующему пути res/images/animation.gif.
Теперь укажем путь к этой анимации нашему виджету.
Для этого заменим “images/image.jpg” на “images/animation.gif”
_file_abs_resource_path_get("images/animation.gif", abs_path_to_image, PATH_MAX);
Для виджета изображений есть функция которая проверяет поддерживает ли указанный ресурс анимации, ее необходимо вызывать после того как вы установили изображение в виджет.
Eina_Bool is_animated = elm_image_animated_available_get(ui->image);
Поскольку по умолчанию виджет использует любой ресурс как статическое изображение то нам нужно указать ему явно, что в случае поддержки ресурсом анимации виджет должен использовать ее. После этого, мы можем запустить анимацию.
if (is_animated)
{
elm_image_animated_set(ui->image, EINA_TRUE);
elm_image_animated_play_set(ui->image, EINA_TRUE);
}
Вы также можете останавливать анимацию в любой момент вызвав последнюю функцию со значением EINA_FALSE второго параметра.
Итак, теперь если указанное изображение будет поддерживать анимации то ее проигрывание начнеться автоматически. Давайте посмотрим что нам покажет наше приложение.
В случае когда у вас большое количество содержимого должно быть размещено на экране, вы можете использовать скроллер который имеет область прокрутки.
Далее мы расширим наше демо приложение скроллером, добавив его как прослойку между конформантом и изображением, таким образом, если размер исходного изображения будет больше чем размер дисплея, мы сможем прокручивать изображение в области которые не попали в границы дисплея.
Скроллер будет помещен в конформант, а изображение будет помещено в скроллер как показано на схеме ниже.
Расширим нашу структуру с виджетами указателем для нового контейнера, который мы создадим дальше. Так как и все виджеты в EFL указатель на скроллер будет иметь тип Evas_Object.
Evas_Object *scroller;
Получим следующее содержимое нашей структуры с виджетами.
typedef struct _UIData {
Evas_Object *win;
Evas_Object *conform;
Evas_Object *scroller;
Evas_Object *image;
} UIData;
Добавим функцию в которой будем реализовывать работу со скроллером.
static void
_scroller_create(UIData *ui)
{
}
Для создания нового скроллера используем следующую функцию:
ui->scroller = elm_scroller_add(ui->conform);
В функцию для создания скроллера мы передаем указатель на конформант который будет предком для него. В результате метод вернет указатель на вновь созданный скроллер.
Изменим помещение скроллера в конформант вместо изображения которое мы ранее напрямую вставляли в конформант.
static void
_conformant_create(UIData *ui)
{
...
_scroller_create(ui);
elm_object_content_set(ui->conform, ui->scroller);
...
}
Теперь необходимо поменять виджету изображений родителя, что бы сохранить иерархию виджетов, в случае удаления скроллера наше изображение не появится где попало, а будет корректно удалено вместе со скроллером.
ui->image = elm_image_add(ui->scroller);
По умолчанию виджет Image отображает изображение которое отмасштабировано по размеру самого виджета, то есть если вы используете изображение с размером 720x360 в виджете с размерами 360x360 то изображение будет отмасштабировано к размеру 360x180 и отцентрировано. Как показано на схеме ниже.
Нам необходимо сделать размер Image виджета таким же как и размер исходного изображения.
Для начала возьмем объект изображения нижнего уровня который находится на уровне Evas модуля. Из него мы дальше сможем получить размер ресурса. Не путайте изображение (elm_image) из модуля Elementary и изображение Evas (evas_object_image), последний хранит более подробную информацию объекта, а первый же – это смарт объект который имеет дополнительные функции например для анимации, или для получения сигнала о том что произошло событие “клик” на виджете.
Evas_Object *evas_image = elm_image_object_get(ui->image);
Теперь получаем сам размер изображения:
int w = 0;
int h = 0;
evas_object_image_size_get(evas_image, &w, &h);
Последним шагом указываем виджету изображения полученный размер в качестве минимального и максимального, таким образом при загрузке изображений виджет будет принимать точно тот же размер что и файл.
evas_object_size_hint_min_set(ui->image, w, h);
evas_object_size_hint_max_set(ui->image, w, h);
Теперь мы добавим следующее изображение которое будет больше чем размер экрана часов (в нашем случае экран 360x360).
Поместим его в res/images/image_big.png.
Теперь укажем путь к этому изображению нашему виджету.
Для этого заменим “images/animation.gif” на “images/image_big.png”
_file_abs_resource_path_get("images/image_big.png", abs_path_to_image, PATH_MAX);
Теперь вызываем функцию для отображения скроллера.
evas_object_show(ui->scroller);
Помещаем виджет изображений в скроллер следующей функцией.
elm_object_content_set(ui->scroller, ui->image);
Ниже то что у нас в итоге получилось в этом уроке.
Полный исходный код этого урока вы можете скачать здесь WearLesson018.