android wear-Drawing Watch Faces
> Drawing Watch Faces
After you have configured your project and added a class that implements the watch face service, you can start writing code to initialize and draw your custom watch face.
When the system loads your service, you should allocate and initialize most of the resources that your watch face needs, including loading bitmap resources, creating timer objects
to run custom animations, configuring paint styles, and performing other computations. You can usually perform these operations only once and reuse their results.
>To initialize your watch face, follow these steps:
- Declare variables for a custom timer, graphic objects, and other elements.
- Initialize the watch face elements in the
Engine.onCreate()
method. - Initialize the custom timer in the
Engine.onVisibilityChanged()
method.
private class Engine extends CanvasWatchFaceService.Engine { static final int MSG_UPDATE_TIME = 0; Calendar mCalendar; // device features boolean mLowBitAmbient; // graphic objects Bitmap mBackgroundBitmap; Bitmap mBackgroundScaledBitmap; Paint mHourPaint; Paint mMinutePaint; ... // handler to update the time once a second in interactive mode final Handler mUpdateTimeHandler = new Handler() { @Override public void handleMessage(Message message) { switch (message.what) { case MSG_UPDATE_TIME: invalidate(); if (shouldTimerBeRunning()) { long timeMs = System.currentTimeMillis(); long delayMs = INTERACTIVE_UPDATE_RATE_MS - (timeMs % INTERACTIVE_UPDATE_RATE_MS); mUpdateTimeHandler .sendEmptyMessageDelayed(MSG_UPDATE_TIME, delayMs); } break; } } }; // receiver to update the time zone final BroadcastReceiver mTimeZoneReceiver = new BroadcastReceiver() { @Override public void onReceive(Context context, Intent intent) { mCalendar.setTimeZone(TimeZone.getDefault()); invalidate(); } }; // service methods (see other sections) ... }
In the example above, the custom timer is implemented as a Handler
instance that sends and
processes delayed messages using the thread's message queue. For this particular watch face, the custom timer ticks once every second. When the timer ticks, the handler calls the invalidate()
method
and the system then calls the<a href="http://developer.android.com/reference/android/support/wearable/watchface/CanvasWatchFaceService.Engine.html#onDraw(android.graphics.Canvas, android.graphics.Rect)"
onDraw() method to redraw the watch face.
@Override public void onCreate(SurfaceHolder holder) { super.onCreate(holder); // configure the system UI (see next section) ... // load the background image Resources resources = AnalogWatchFaceService.this.getResources(); Drawable backgroundDrawable = resources.getDrawable(R.drawable.bg, null); mBackgroundBitmap = ((BitmapDrawable) backgroundDrawable).getBitmap(); // create graphic styles mHourPaint = new Paint(); mHourPaint.setARGB(255, 200, 200, 200); mHourPaint.setStrokeWidth(5.0f); mHourPaint.setAntiAlias(true); mHourPaint.setStrokeCap(Paint.Cap.ROUND); ... // allocate a Calendar to calculate local time using the UTC time and time zone mCalendar = Calendar.getInstance(); }
The background bitmap is loaded only once when the system initializes the watch face. The graphic styles are instances of the Paint
class.
Use these styles to draw the elements of your watch face inside theEngine.onDraw()
method,
as described in Drawing Your Watch Face.
AnalogWatchFaceService
class schedules the next timer tick if required
as follows:
private void updateTimer() { mUpdateTimeHandler.removeMessages(MSG_UPDATE_TIME); if (shouldTimerBeRunning()) { mUpdateTimeHandler.sendEmptyMessage(MSG_UPDATE_TIME); } } private boolean shouldTimerBeRunning() { return isVisible() && !isInAmbientMode(); }
@Override public void onVisibilityChanged(boolean visible) { super.onVisibilityChanged(visible); if (visible) { registerReceiver(); // Update time zone in case it changed while we weren't visible. mCalendar.setTimeZone(TimeZone.getDefault()); } else { unregisterReceiver(); } // Whether the timer should be running depends on whether we're visible and // whether we're in ambient mode, so we may need to start or stop the timer updateTimer(); }> The
registerReceiver()
and unregisterReceiver()
methods
are implemented as follows:
private void registerReceiver() { if (mRegisteredTimeZoneReceiver) { return; } mRegisteredTimeZoneReceiver = true; IntentFilter filter = new IntentFilter(Intent.ACTION_TIMEZONE_CHANGED); AnalogWatchFaceService.this.registerReceiver(mTimeZoneReceiver, filter); } private void unregisterReceiver() { if (!mRegisteredTimeZoneReceiver) { return; } mRegisteredTimeZoneReceiver = false; AnalogWatchFaceService.this.unregisterReceiver(mTimeZoneReceiver); }
The following snippet shows how to implement the onDraw()
method:
@Override public void onDraw(Canvas canvas, Rect bounds) { // Update the time mCalendar.setTimeInMillis(System.currentTimeMillis()); // Constant to help calculate clock hand rotations final float TWO_PI = (float) Math.PI * 2f; int width = bounds.width(); int height = bounds.height(); canvas.drawBitmap(mBackgroundScaledBitmap, 0, 0, null); // Find the center. Ignore the window insets so that, on round watches // with a "chin", the watch face is centered on the entire screen, not // just the usable portion. float centerX = width / 2f; float centerY = height / 2f; // Compute rotations and lengths for the clock hands. float seconds = mCalendar.get(Calendar.SECOND) + mCalendar.get(Calendar.MILLISECOND) / 1000f; float secRot = seconds / 60f * TWO_PI; float minutes = mCalendar.get(Calendar.MINUTE) + seconds / 60f; float minRot = minutes / 60f * TWO_PI; float hours = mCalendar.get(Calendar.HOUR) + minutes / 60f; float hrRot = hours / 12f * TWO_PI; float secLength = centerX - 20; float minLength = centerX - 40; float hrLength = centerX - 80; // Only draw the second hand in interactive mode. if (!isInAmbientMode()) { float secX = (float) Math.sin(secRot) * secLength; float secY = (float) -Math.cos(secRot) * secLength; canvas.drawLine(centerX, centerY, centerX + secX, centerY + secY, mSecondPaint); } // Draw the minute and hour hands. float minX = (float) Math.sin(minRot) * minLength; float minY = (float) -Math.cos(minRot) * minLength; canvas.drawLine(centerX, centerY, centerX + minX, centerY + minY, mMinutePaint); float hrX = (float) Math.sin(hrRot) * hrLength; float hrY = (float) -Math.cos(hrRot) * hrLength; canvas.drawLine(centerX, centerY, centerX + hrX, centerY + hrY, mHourPaint); }
相關文章
- android wear-Showing Information in Watch Faces and Creating InteractiveWatch Faces, Providing ConfiAndroidORM
- adroid Wear-Designing Watch Faces and Building a Watch Face ServiceUI
- JavaServer Faces Note(1)JavaServer
- JavaServer Faces Note(2)JavaServer
- ORL Faces Database介紹Database
- ADF FACES 佈局
- 用JavaServer Faces開發Web應用(4) (轉)JavaServerWeb
- 用JavaServer Faces開發Web應用(3) (轉)JavaServerWeb
- 谷歌Android Wear 2.0功能曝光:HUAWEI Watch首批支援谷歌Android
- 將Oracle ADF Faces整合到Appfuse裡面OracleAPP
- javax.faces.FacesException: Nested form found on the page. The form action elemeJavaExceptionORM
- 人臉識別資料集 - Labeled Faces in the Wild Home (LFW)
- StopWatch使用
- 想要佔領可穿戴裝置市場,Apple Watch需要相容Android?APPAndroid
- computed watcher和user watcher的區別
- Apple Watch 學習之路 初見Watch 應用APP
- vue 3 學習筆記 (六)——watch 、watchEffect 新用法Vue筆記
- WatchKit程式設計指南:WatchKit Apps–表格程式設計APP
- tmpwatch 命令整理
- Vue watch選項Vue
- linux watch命令Linux
- FileSystemWatch使用示例
- [Bash] watch command
- PHP的Ev教程二(watcher和watche回撥等)PHP
- 華為Watch 3智慧手錶曝光:或將命名為Watch X
- vue3如何進行資料監聽watch/watchEffectVue
- 【Zookeeper】原始碼分析之Watcher機制(二)之WatchManager原始碼
- 蘋果手錶APPLE WATCH露出 iwatch又添新功能蘋果APP
- WatchKit程式設計指南:WatchKit Apps–App概要程式設計APP
- Apple Watch軟體更新將帶來“Find my Watch”功能APP
- Apple Watch watch OS 3更新 九大新特性彙總APP
- watchOS 4釋出,我們來聊聊Apple Watch設計APP
- apple watch升級watch os3教程(圖文詳解)APPS3
- WatchKit程式設計指南:WatchKit Apps–介面導航程式設計APP
- 華碩釋出ZenWatch 2手錶 多處效仿Apple WatchAPP
- apple watch 2有哪些功能 apple watch 2功能介紹APP
- [nodemon] Internal watch failed: watch ENOSPC錯誤解決辦法AI
- PostgreSQL DBA(185) - watchSQL