В этом уроке речь пойдет о специальном виджете называемом bg который используется как графический элемент для фона в приложениях.
Как уже говорилось виджет используется в качестве фона приложения. На самом деле это не означает что вы должны его обязательно использовать, можно, например, использовать виджет изображения. Но мы рекомендуем использовать именно bg если вам нужен статический фон.
Преимущества виджета фона - это то, что вы можете ему задавать как изображение так и просто сплошной цвет. Таким образом, в отличие от виджета изображения, виджету фона можно ставить цвет при помощи специально созданного для этого интерфейса.
Особенностью виджета фона является способность задать режим отображения изображения. Это может быть растягивание по всей области или замощение всего пространства в случае если размер изображение меньше размера виджета.
Давайте добавим фон в наш циферблат который мы создали в предыдущем уроке.
Как обычно добавим поле для нашего нового виджета в структуру.
typedef struct _UIData
{
Evas_Object *win;
Evas_Object *bg;
Evas_Object *label;
} UIData;
Создадим функцию для создания виджета фона и разместим ее вызов до создания текстового виджета поскольку нам необходимо отобразить сначала фон, а затем цифры времени, в противном случае мы скроем фоном цифры.
static void
_bg_create(UIData *ui, int width, int height)
{
}
static void
_window_create(UIData *ui, int width, int height)
{
...
_bg_create(ui, width, height);
_label_create(ui, width, height);
...
}
Для создания самого объекта виджета делаем следующий вызов
ui->bg = elm_bg_add(ui->win);
Мы уже договорились, что в этом демо-приложении не используем контейнеров для размещения компонентов, поэтому теперь задаем размеры компоненту явно, используя переданные в функцию аргументы. И можно тут же отобразить виджет.
evas_object_resize(ui->bg, width, height);
evas_object_show(ui->bg);
Давайте установим темно зеленый цвет нашему фону. Для этого вызываем функцию.
elm_bg_color_set(ui->bg, 0, 80, 20);
Установим и запустим наш циферблат и посмотрим что получилось.
Как видно у нас получился циферблат с зеленым фоном и серыми цифрами отображающими время.
Давайте добавим разнообразие в наш циферблат и позволим изменять стиль нажатием на цифрах. Для этого нам нужно определить стили или как будет выглядеть наш циферблат, реализовать функцию установки фону нужного цвета или изображения, добавить в форматированную строку где мы задаем текст времени цвет тексту, и создать обработчик нажатия на цифры.
Для начала определим что в стиль у нас будет входить следующее:
- Тип стиля, тоесть будет использоваться изображение или сплошной цвет в качестве фона;
- Цвет текста описуемый HTML кодом цвета, поскольку так будет удобнее для использования;
- Три компоненты RGB для задания цвета фону, как мы видели функция принимает именно три параметра для трех цветовых каналов, а не HTML код.
- Имя файла изображения для фона в случае использования не цветового стиля циферблата.
Определив что нам нужно опишем структуру данных в коде
typedef struct _Style
{
Eina_Bool is_image;
char *digits_color;
int bg_r;
int bg_g;
int bg_b;
char *image_name;
} Style;
Определим набор стилей которые мы предоставим пользователю:
1. Желтые цифры (#edf8bd), темно-красный фон (104,0,32).
2. Светло-фиолетовые цифры (#9598bc), горчичный фон(117, 104, 0).
3. Светло-красные цифры (#eec4c7) и темно бюрюзовый фон (8,60,55).
4. Темно-бирюзовые цифры (#00332e) и зеленый фон (71,188,53).
5. Темно бирюзовые цифры (#005848) и следующее фоновое изображение
6. Белые цифры (#ffffff) и следующее фоновое изображение
Теперь добавим изображения в наш проект в папку res/ и определим стили в коде, что бы мы могли их использовать.
static Style styles[] = {
{EINA_FALSE, "edf8bd", 104, 0, 32},
{EINA_FALSE, "9598bc", 117, 104, 0},
{EINA_FALSE, "eec4c7", 8, 60, 55},
{EINA_FALSE, "00332e", 71, 188, 53},
{EINA_TRUE, "005848", 0, 0, 0, "bg1.png"},
{EINA_TRUE, "ffffff", 0, 0, 0, "bg2.png"},
};
Давайте добавим в нашу структуру с графическими компонентами поле, в котором мы будем хранить индекс текущего стиля.
typedef struct _UIData
{
Evas_Object *win;
Evas_Object *bg;
Evas_Object *label;
int style_index;
} UIData;
Добавляем изменение стиля цифер в соответствии со стилем. Для этого в месте генерации строки для текстового виджета необходимо добавить аттрибут color в блок <font> и через формат передавать туда цвет текста для текущего стиля.
static void
_ui_update(UIData *ui, watch_time_h watch_time)
{
...
Style *style = &styles[ui->style_index];
char *color = style->digits_color;
snprintf(text,
BUF_SIZE,
"<font font_size=80 color=#%s>"
"<align=center>%02d:%02d:%02d</align>"
"</font>",
color,
hour24,
minute,
second);
...
}
Теперь давайте реализуем функцию в которой будем менять внешний вид фонового виджета в соответствии с текущим стилем.
Для начала добавим функцию получения полного пути к файлу изображения на устройстве во время выполнения, это мы уже делали в уроке про создание изображения, виджет фона принимает путь к изображениям таким же образом.
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 void
_bg_apperance_set(UIData *ui)
{
Style *style = &styles[ui->style_index];
if (style->is_image == EINA_TRUE)
{
const int BUF_SIZE = 256;
char image_path[BUF_SIZE] = {0,};
_file_abs_resource_path_get(style->image_name, image_path, BUF_SIZE);
elm_bg_file_set(ui->bg, image_path, NULL);
}
else
{
char *image = NULL;
elm_bg_file_get(ui->bg, &image, NULL);
if (image)
elm_bg_file_set(ui->bg, NULL, NULL);
elm_bg_color_set(ui->bg, style->bg_r, style->bg_g, style->bg_b);
}
}
В этой функции мы берем текущий стиль, а затем устанавливаем виджету фоновое изображение или цвет.
Как вы могли заметить в случае цветового стиля используются две функции одновременно. Как говорилось виджет фона может использовать одновременно только одно, либо цвет либо изображение, причем приоритет идет на изображение. В результате программа должна выполнятся следующим образом.
Если стиль имеет изображение в качестве фона, то мы возьмем полный путь к изображению и установим его виджету.
Если стиль имеет цвет в качестве фона, то мы сначала должны убрать изображение если оно стояло. Удаление изображения у виджета фона производится той же функцией что и установка изображения, только вместо пути к файлу необходимо передать NULL.
Теперь можно заменить установку статического цвета для виджета фона на нашу функцию, теперь функция создания bg-виджета выглядит следующим образом.
static void
_bg_create(UIData *ui, int width, int height)
{
ui->bg = elm_bg_add(ui->win);
evas_object_resize(ui->bg, width, height);
_bg_apperance_set(ui);
evas_object_show(ui->bg);
}
Последним шагом шагом реализуем обработчик нажатия на текстовый виджет для последующего изменения стиля циферблата. У текстового виджета нет смарт колбека на событие клик, поэтому что бы не создавать отдельную кнопку сейчас, мы воспользуемся событийным колбеком начала касания виджета EVAS_CALLBACK_MOUSE_DOWN.
В реальном циферблать необходимо было бы создать отдельную кнопку поскольку событие начала касания не совсем отражает клик, но для нашего демо подойдет и такое решение.
static void
_label_create(UIData *ui, int width, int height)
{
...
evas_object_event_callback_add(ui->label, EVAS_CALLBACK_MOUSE_DOWN, down_cb, ui);
}
Реализуем сам обработчик
static void
down_cb(void *data, Evas *evas, Evas_Object *obj, void *event)
{
UIData *ui = data;
int styles_count = EINA_C_ARRAY_LENGTH(styles);
ui->style_index = (ui->style_index + 1) % styles_count;
_watch_update(ui, NULL);
_bg_apperance_set(ui);
}
В этой функции мы циклически изменяем индекс текущего стиля, и вызываем функцию для обновления цифер, где изменится и цвет цифер, а также вызываем функцию для обновления внешнего вида фона.
Теперь можем запусть наш циферблат.
У нас получился циферблат с множеством стилей. Изменение происходит по касанию в области цифер, в конце видео видно что если производить касания вне цифер, то ничего не происходит.
Мы упоминали что в виджете фона есть возможность настроить способ отображения изображения если оно размер изображения будет отличаться от размера виджета.
Для этих целей используется следующая функция.
elm_bg_option_set(Evas_Object *bg, Elm_Bg_Option option);
Вторым параметром передается сам способ отображения.
У вас также есть возможность узнать какой режим используется в данный момент, для этого воспользуйтесь такой функцией.
Elm_Bg_Option elm_bg_option_get(const Evas_Object *bg);
Давайте возьмем такое небольшое изображение и посмотрим что происходит при разных способах отображения.
ELM_BG_OPTION_CENTER — изображение будет распологаться по сeредине виджета:
ELM_BG_OPTION_SCALE — изображение будет растягиваться с сохранением отношения сторон, до тех пор пока сторона с меньшим размером не растянется до размера виджета:
ELM_BG_OPTION_STRETCH — изображение будет растягиваться бе сохранения соотношения сторон:
ELM_BG_OPTION_TILE — область виджета фона будет замощена изображениями:
Если вы не будете устанавливать режим виджету, то по-умолчанию будет использоваться режим ELM_BG_OPTION_SCALE.
Полный код этого урока вы можете скачать здесь WearLesson029.