Опубликовано: 25 Октября 2017
(Демо приложение №5)
Приложение-циферблат

Начинаем создавать 5-е демо-приложение. В нем мы создадим циферблат в котором будет возможность изменять стиль, а также предусмотрим возможность сохранять информацию о настройках циферблата в системе при помощи специального модуля.

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

Что такое приложение-циферблат

Итак, до этого момента мы создавали UI приложения в наших демо, в этом уроке создадим приложение-циферблат.

Как понятно из названия, приложение должно нести собой смысл индикатора времени. Но это не запрещает вам превращать циферблат в полноценное приложение с интересными дополнительными функциями, будь то отображение карты на фоне или какой-либо другой не свойственный циферблату функционал.

На первый взгляд может показаться, что будут какие-то серъезные различия между ui-приложением и приложеним-циферблатом, но на самом деле это не так.

Приложение-циферблат создается таким же образом как и обычные приложения с пользовательским интерфейсом, немного отличается только создание базового окна для циферблата, поскольку оно находится в специальном месте в графической оболочке часов, в остальном можно сказать что это обычное приложение, здесь вы можете использовать всё те же виджеты, сервисы и датчики (GPS, датчик освещения и др.), вызывать вибрацию устройства, посылать уведомления и т.д.

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

Жизненный цикл циферблата предусматривает специальное событие Time Tick, оно срабатывает каждую секунду. Таким образом в обработчике этого события мы должны осуществить обновление графического интерфейса в соответствии с текущим временем (обновить цифры или изменить углы стрелок если циферблат имеет аналоговый стиль).

Создание шаблона циферблата

В Tizen студии есть шаблон приложения-циферблата.

Создадим его.

Открываем File → New → Tizen Project.

Дальше выбераем Template и жмем Next>.

nw_028_01_en

Выбираем Native Application и жмем Next>.

nw_028_02_en

Выбираем профиль Wearable и версию платформы 2.3.2 и жмем Next>.

nw_028_03_en

Далее выбираем проект шаблон циферблата Watch и жмем Next>.

nw_028_04_en

Последним шагом вводим имя проекта и имя пакета с которым будет собираться циферблат жмем Finish.

nw_028_05_en
Запуск приложений-циферблатов

В отличие от UI-приложений которые мы уже создавали в предыдущих уроках, приложения-циферблаты не запускаются сразу после установки на устройство или эмулятор. На эмуляторах циферблаты устанавливаются через меню циферблатов в приложении настроек как показано ниже.

На реальных часах требуется зажать на экране с циферблатом, после этого отобразится окно выбора циферблата, где вы можете установить свой, ниже продемонстрировано.

Подготовка циферблата для демо-приложения

Как уже замечалось некоторые шаблоны имеют лишние элементы. Поэтому для нашего демо изменим код, и максимально упростим его для лучшего понимания.

Мы удалили заголовочный файл из проекта и необходимые файлы для включения перенесли в файл реализации. Удалили конформант и лишние пустые обработчики событий, они нам не нужны для этого демо.

#include <watch_app.h>
#include <Elementary.h>
#include <watch_app_efl.h>

typedef struct _UIData
{
   Evas_Object *win;
   Evas_Object *label;
} UIData;

static void
_ui_update(UIData *ui, watch_time_h watch_time)
{
   const int BUF_SIZE  = 256;
   char text[BUF_SIZE] = {0,};
   int hour24          = 0;
   int minute          = 0;
   int second          = 0;

   watch_time_get_hour24(watch_time, &hour24);
   watch_time_get_minute(watch_time, &minute);
   watch_time_get_second(watch_time, &second);

   snprintf(text,
            BUF_SIZE,
            "<font font_size=80><align=center>%02d:%02d:%02d</align></font>",
            hour24,
            minute,
            second);

   elm_object_text_set(ui->label, text);
}

static void
_watch_update(UIData *ui, watch_time_h watch_time)
{
   if (watch_time == NULL)
     {
        watch_time_get_current_time(&watch_time);
        _ui_update(ui, watch_time);
        watch_time_delete(watch_time);
     }
   else
     _ui_update(ui, watch_time);
}

static void
_label_create(UIData *ui, int width, int height)
{
   ui->label = elm_label_add(ui->win);

   const int label_heigh = 80;
   evas_object_resize(ui->label, width, label_heigh);
   evas_object_move(ui->label, 0, height / 2 - label_heigh / 2);

   evas_object_show(ui->label);
}

static void
_window_create(UIData *ui, int width, int height)
{
   watch_app_get_elm_win(&ui->win);

   evas_object_resize(ui->win, width, height);

   _label_create(ui, width, height);

   evas_object_show(ui->win);
}

static bool
_app_create(int width, int height, void *data)
{
   UIData *ui = data;

   _window_create(ui, width, height);

   _watch_update(ui, NULL);

   return true;
}

static void
_app_terminate(void *data)
{
   UIData *ui = data;
   evas_object_del(ui->win);
}

static void
_app_time_tick(watch_time_h watch_time, void *data)
{
   UIData *ui = data;
   _watch_update(ui, watch_time);
}

int
main(int argc, char *argv[])
{
   UIData ui = {0,};

   watch_app_lifecycle_callback_s lifecycle_callbacks = {0,};

   lifecycle_callbacks.create    = _app_create;
   lifecycle_callbacks.terminate = _app_terminate;
   lifecycle_callbacks.time_tick = _app_time_tick;

   return watch_app_main(argc, argv, &lifecycle_callbacks, &ui);
}

Итак у нас получилось 8 небольших функций, давайте разберем что делает каждая.

Как и в любой программе все начинается с функции main().

int
main(int argc, char *argv[])
{
   UIData ui = {0,};

   watch_app_lifecycle_callback_s lifecycle_callbacks = {0,};

   lifecycle_callbacks.create    = _app_create;
   lifecycle_callbacks.terminate = _app_terminate;
   lifecycle_callbacks.time_tick = _app_time_tick;

   return watch_app_main(argc, argv, &lifecycle_callbacks, &ui);
}

В ней мы создаем объект структуры с элементами интерфейса, инициализируем обработчики некоторых событий жизненного цикла циферблата, а именно: создание, событие изменения времени, завершение. И в конце запускаем главный цикл приложения-циферблата вызовом watch_app_main().

В обработчике _app_terminate() мы удаляем окно, являясь корневым виджетом оно позаботится об удалении всей иерархии виджетов которые будут создаваться.

static void
_app_terminate(void *data)
{
   UIData *ui = data;
   evas_object_del(ui->win);
}

В обработчике _app_create() мы создаем наше корневое окно и все виджеты циферблата, а после этого вызываем обновление циферблата в соответствии с текущим временем. Как говорилось ранее создание окна циферблата отличается от создания его в UI приложении. Здесь нам необходимо вызвать функцию watch_app_get_elm_win() вместо elm_win_util_standard_add(). И в нее передать указатель на указатель объекта Evas в который необходимо сохранить созданное окно.

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

static void
_window_create(UIData *ui, int width, int height)
{
   watch_app_get_elm_win(&ui->win);

   evas_object_resize(ui->win, width, height);

   _label_create(ui, width, height);

   evas_object_show(ui->win);
}

static bool
_app_create(int width, int height, void *data)
{
   UIData *ui = data;

   _window_create(ui, width, height);

   watch_time_h watch_time = NULL;
   watch_time_get_current_time(&watch_time);
   _watch_update(ui, watch_time);
   watch_time_delete(watch_time);

   return true;
}

Функция в которой мы создаем текстовый виджет для отображения в нем времени.

static void
_label_create(UIData *ui, int width, int height)
{
   ui->label = elm_label_add(ui->win);

   const int label_heigh = 80;
   evas_object_resize(ui->label, width, label_heigh);
   evas_object_move(ui->label, 0, height / 2 - label_heigh / 2);

   evas_object_show(ui->label);
}

В этом демо приложении мы не будем пользоваться контейнерами для разметки, а будем явно задавать геометрию виджетам, поскольку наш интерфейс прост и будет состоять из виджета фона и текстового виджета.

Мы установили текстовому виджету высоту в 80 пикселей и разместили его посредине экрана на основе его высоты и ширины.

После создания виджетов вызывается созданная нами функция обновления циферблата в которой мы вызываем обновление интерфейса с переданным временем или в противном случае с текущим временем. В функции обновления интерфейса мы обновляем текстовый виджет в соответствии с переданным туда объектом времени. Текстовая строка формируется с указанием некоторых параметров стиля, для увеличения размера текста и центровки его по горизонтали, подробно о стилях для виджета текста мы рассказывали в 16-м уроке.

static void
_ui_update(UIData *ui, watch_time_h watch_time)
{
   const int BUF_SIZE  = 256;
   char text[BUF_SIZE] = {0,};
   int hour24          = 0;
   int minute          = 0;
   int second          = 0;

   watch_time_get_hour24(watch_time, &hour24);
   watch_time_get_minute(watch_time, &minute);
   watch_time_get_second(watch_time, &second);

   snprintf(text,
            BUF_SIZE,
            "%02d:%02d:%02d",
            hour24,
            minute,
            second);

   elm_object_text_set(ui->label, text);
}

static void
_watch_update(UIData *ui, watch_time_h watch_time)
{
   if (watch_time == NULL)
     {
        watch_time_get_current_time(&watch_time);
        _ui_update(ui, watch_time);
        watch_time_delete(watch_time);
     }
   else
     _ui_update(ui, watch_time);
}

Заметьте что для работы со временем используется специальный объект типа watch_time_h, для работы с ним предусмотрен удобный интерфейс, хотя вам никто не запрещает работать с struct tm из "time.h".

Последняя функция _app_time_tick() является обработчиком события изменения времени, она вызывается каждую секунду. Таким образом в ней мы можем поворачивать стрелки или изменять цифры отображающие время. Так мы и сделаем, воспользовавшись функцией обновления циферблата созданной выше.

static void
_app_time_tick(watch_time_h watch_time, void *data)
{
   UIData *ui = data;
   _watch_update(ui, watch_time);
}

В этот обработчик первым параметром приходит информация о текущем времени системы, его мы передаем в функцию обновления циферблата.

Давайте установим и запустим наше приложение и посмотрим что получилось.

Полный код нашего примера вы можете скачать здесь WearLesson028.

В дальнейшем мы будем реализовывать другие циферблаты в качестве демо-приложений и нам может не понадобиться текстовый виджет поэтому мы его удалили и подготовили пустой шаблон для демо приложений-циферблатов, его можно скачать здесь WearWatchTemplate. Вы также можете его использовать для создания собственных циферблатов вместо стандартного шаблона среды разработки.

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *