> 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:

  1. Declare variables for a custom timer, graphic objects, and other elements.
  2. Initialize the watch face elements in the Engine.onCreate() method.
  3. 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 theonDraw() method to redraw the watch face.

@Overridepublic 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.

The  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();}

@Overridepublic 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:

@Overridepublic 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);}

更多相关文章

  1. 代码中设置drawableleft
  2. android 3.0 隐藏 系统标题栏
  3. Android开发中activity切换动画的实现
  4. Android(安卓)学习 笔记_05. 文件下载
  5. Android中直播视频技术探究之—摄像头Camera视频源数据采集解析
  6. 技术博客汇总
  7. android 2.3 wifi (一)
  8. AndRoid Notification的清空和修改
  9. Android中的Chronometer

随机推荐

  1. php处理post传递json格式参数请求
  2. VUE---路由菜单Icon自定义的实现
  3. 基于Cocos SDKHub接入华为HMS Game服务—
  4. Kubernetes客户端和管理界面大集合
  5. 中小企业需要的报表工具一般具备什么功能
  6. Kubernetes集群管理容器实践(概念篇)
  7. php函数知识
  8. 语音也能做持续集成和持续部署?看 Jenkins
  9. 啤酒与***:培养***格调的6个建议
  10. 2021免费Phpstorm激活码送你——不用“剁