Pebble:7セグメントウォッチフェイスの作成例を使用した静的グラフィックスの操作

Pebbleウォッチのすべてのアプリケーションは、アプリケーションとwatchfaceの 2つのwatchappカテゴリに分類されます。ウォッチアプリケーションは、名前に基づいてデバイスの顔です。 「フェイス」の違いは、「UP」と「DOWN」がインストールされたウォッチフェイスを循環するために使用されるため、ハードウェアボタンに対する反応がないことです。

しかし、おそらく、画面の解像度が144x168ピクセルであるため、時計のデザインに合ったウォッチフェイスを見つけることはかなり困難であり、同時に主要な機能である時間をカウントします。

このような画面では、7セグメントインジケーターのスタイルの数字が最もよく見えるようです。

以下に、 ウォッチフェイスにエレガントなミニマリズム、個性、ユニークな機能を追加する方法について詳しく説明します。

そのため、いくつかの写真、コードのスニペット、そしてその結果、完成したプロジェクトへのリンク。





ウォッチフェイスの作成、プロジェクトの構造および構築については、 Build Your Own Watchface [1]ドキュメントの対応するセクションで詳しく説明されています。 繰り返しはしませんが、すぐに行きます



特徴



私たちのアプリケーションを例から十数半、 mypebblefacesから数百と区別するもの:



まず最初に:



7セグメントフォント



数字を表示するには、2つのセット、メインの大きな(20x38px桁)が必要です。







そして、日付と秒用の特別な小さなもの(数字8x16px):







両方のセットは、グラフィカルエディターで2色のpngファイルとしてレンダリングされます。

それらをappinfo.jsonのリソースとして接続します。

"resources": { "media": [ { "type": "png", "name": "DIGITS", "file": "images/digits.png" }, { "type": "png", "name": "DIGITS_MIDI", "file": "images/digits_midi.png" } ]
      
      





グラフィカルフレームワークについては、 ドキュメント[2]で説明されていますラスター画像の操作に関するセクションに興味があります[3]

ラスターを操作するための準備アクション、別の関数で取り出すリソースからの作成:

 /*...*/ static GBitmap *bmp_digits; static GBitmap *bmp_digits_midi; /*..*/ static void load_resources() { bmp_digits = gbitmap_create_with_resource(RESOURCE_ID_DIGITS); bmp_digits_midi = gbitmap_create_with_resource(RESOURCE_ID_DIGITS_MIDI); } /*..*/ static void window_load(Window *window) { load_resources(); }
      
      





リソースを解放することを忘れないでください:

 static void destroy_resources() { gbitmap_destroy(bmp_digits); gbitmap_destroy(bmp_digits_midi); } /*..*/ static void window_unload(Window *window) { destroy_resources(); }
      
      





数値のセットはリソースから読み取られ、メモリ内のラスターとして作成されます。関数を呼び出すときに、別の図を描画する機能が必要になります。

 /* ctx -  ; sources -  ; bounces -      ; number -     . */ static void draw_picture(GContext* ctx, GBitmap **sources, GRect bounces, int number) { GPoint origin = bounces.origin; bounces.origin = GPoint(bounces.size.w*number, 0); GBitmap* temp = gbitmap_create_as_sub_bitmap(*sources, bounces); bounces.origin = origin; graphics_draw_bitmap_in_rect(ctx, temp, bounces); gbitmap_destroy(temp); }
      
      





そして、例えば、コンテキストの座標(10、0)でトリプルを描くには:

  draw_picture(ctx, &bmp_digits, GRect(10, 0, 20, 38), 3);
      
      





コンテンツへ



2つの画面



それぞれに独自のコンテンツを持つ2つの独立した画面があるため、それらを個別のレイヤーの形で、時計の画面のサイズで実装します。

 /*..*/ static Layer *standby_layer; static Layer *info_layer; /*..*/ static void window_load(Window *window) { Layer *window_layer = window_get_root_layer(window); GRect bounds = layer_get_bounds(window_layer); load_resources(); standby_layer = layer_create(bounds); layer_add_child(window_layer, standby_layer); info_layer = layer_create(bounds); layer_add_child(window_layer, info_layer); }
      
      





「ティックタイマー」サービスハンドラー間で画面を切り替えます。

 /*..*/ int current_screen = 0; /*..*/ static void tick_handler(struct tm *tick_time, TimeUnits units_changed) { //    "standby"   if (units_changed & MINUTE_UNIT) { layer_mark_dirty(standby_layer); }; switch (current_screen) { case 0: //   "standby" ,      "info" if (layer_get_hidden(standby_layer)) { layer_set_hidden(info_layer, true); layer_set_hidden(standby_layer, false); }; break; case 1: layer_mark_dirty(info_layer); //   "info" ,      "standby" if (layer_get_hidden(info_layer)) { layer_set_hidden(standby_layer, true); layer_set_hidden(info_layer, false); //         "standby" if (settings.s_auto) { standby_timer = app_timer_register(30000, timer_callback, NULL); }; }; break; }; } static void init(void) { /*..*/ tick_timer_service_subscribe(SECOND_UNIT, tick_handler); }
      
      





そのため、画面にコンテンツを描画する必要があることになりました。 たとえば、スタンバイ画面にコンテンツを表示するためのコードはデジタルダイヤルです。

最初に、必要なときに自動的に呼び出される「standby_layer」レイヤーのレンダリング関数を設定します。

 static void window_load(Window *window) { standby_layer = layer_create(bounds); layer_add_child(window_layer, standby_layer); layer_set_update_proc(standby_layer, update_standby); }
      
      





コンテンツレンダリングの実装:

update_standby
 static void update_standby(Layer *layer, GContext* ctx) { GRect bounds = layer_get_bounds(layer); //   -  graphics_context_set_fill_color(ctx, GColorBlack); //   -  graphics_context_set_compositing_mode(ctx, GCompOpAssignInverted); //   graphics_fill_rect(ctx, bounds, 0, GCornerNone); time_t temp = time(NULL); struct tm *tick_time = localtime(&temp); int hour_dicker = tick_time->tm_hour/10; int hour_unit = tick_time->tm_hour%10; int min_dicker = tick_time->tm_min/10; int min_unit = tick_time->tm_min%10; //   draw_picture(ctx, &bmp_digits, GRect(20, 55, 20, 38), hour_dicker); draw_picture(ctx, &bmp_digits, GRect(42, 55, 20, 38), hour_unit); draw_picture(ctx, &bmp_digits, GRect(78, 55, 20, 38), min_dicker); draw_picture(ctx, &bmp_digits, GRect(100, 55, 20, 38), min_unit); //   graphics_context_set_fill_color(ctx, GColorWhite); GRect frame = (GRect) { .origin = GPoint(bounds.size.w/2-4, 63), .size = GSize(4, 4) }; graphics_fill_rect(ctx, frame, 0, GCornerNone); frame = (GRect) { .origin = GPoint(bounds.size.w/2-4, 81), .size = GSize(4, 4) }; graphics_fill_rect(ctx, frame, 0, GCornerNone); }
      
      







結果:



同様に、 draw_pictureを使用して、情報画面描画します。

結果:



コンテンツへ



画面を切り替える



画面を切り替えるには、組み込みの加速度計[4]を使用します。 これを行うには、「タップイベントサービス」に登録します。



 static void tap_handler(AccelAxisType axis, int32_t direction) { current_screen = !current_screen; } static void init(void) { /*...*/ tick_timer_service_subscribe(SECOND_UNIT, tick_handler); accel_tap_service_subscribe(tap_handler); }
      
      





コンテンツへ



スタンバイに入る



スタンバイ画面に自動的に切り替えるには、 タイマー[4]を使用します。



 /*..*/ AppTimer *standby_timer = NULL; /*..*/ static void timer_callback() { current_screen = 0; } static void tick_handler(struct tm *tick_time, TimeUnits units_changed) { /*..*/ case 1: layer_mark_dirty(info_layer); //   "info" ,      "standby" if (layer_get_hidden(info_layer)) { layer_set_hidden(standby_layer, true); layer_set_hidden(info_layer, false); //         "standby" if (settings.s_auto) { standby_timer = app_timer_register(30000, timer_callback, NULL); }; }; break; /*..*/ }
      
      





コンテンツへ



バッテリーとBluetoothのステータス



バッテリーの状態[6]を表示するには、数十パーセントに対応する画像でリソースを作成します(このような精度で、APIは充電量を提供します)。



 "resources": { "media": [ /*..*/ { "type": "png", "name": "BATTERY", "file": "images/battery.png" }, /*..*/ ] }
      
      





適切な画面に描画します。

  /*..*/ BatteryChargeState charge_state = battery_state_service_peek(); int bat_percent = charge_state.charge_percent/10; if (charge_state.is_charging) { bat_percent = 110/10; }; draw_picture(ctx, &bmp_battery, GRect(0, 0, 8, 15), bat_percent); /*..*/
      
      





Bluetooth [7]のステータスは、対応するアイコンによって表示されます。

 "resources": { "media": [ /*..*/ { "type": "png", "name": "BT", "file": "images/bluetooth.png" }, /*..*/ ] }
      
      





  if (bluetooth_connection_service_peek()) { draw_picture(ctx, &bmp_bt, GRect(0, 0, 8, 15), 0); };
      
      







コンテンツへ



要するに、ほとんどの場合冗長な情報に悩まされることのないウォッチフェイスは、読み取り可能であり、必要に応じて拡張情報を共有できます。



興味のある方へ:

Bitbucket プロジェクトコード

Pebble App Storeのアプリ



1. Pebble Developers //独自のウォッチフェイスを作成する

2.ペブル開発者//グラフィックス

3.ペブル開発者//グラフィックスの種類

4. Pebble Developers //加速の検出

5. Pebble Developers //タイマー

6. Pebble Developers //バッテリーレベルの測定

7. Pebble Developers // Bluetoothイベントの管理



All Articles