网上看过很多人写的AnalogClock,但是很多都不完整或无法运行,于是自己结合DeskClock源码,写了一个小的demo,步骤大致入如下:
1、自定义View,通过AnalogClock extend View,在其中定义一些时分秒的图片显示和获取系统当前时分秒时间的变量,通过handle进行更新
package cn.anglogclock.demo; import android.content.Context; import android.content.res.Resources; import android.graphics.Canvas; import android.graphics.drawable.Drawable; import android.os.Handler; import android.text.format.Time; import android.util.AttributeSet; import android.view.View; public class AnalogClock extends View { private Time mJavaTime; private Drawable mHourDrawable;//时钟的图片显示 private Drawable mMinuteDrawable;//分钟的图片显示 private Drawable mSecondDrawable;//秒钟的图片显示 private Drawable mDialDrawable;//盘面的图片显示 private int mDialWidth; private int mDialHeight; private boolean mAttached; private Handler mHandler; private float mMinutes; private float mHours; private float mSeconds; private boolean mChanged; public AnalogClock(Context context) { this(context, null); } public AnalogClock(Context context, AttributeSet attrs) { this(context, attrs, 0); } public AnalogClock(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); initViews(context); } private void initViews(Context context) { Resources r = context.getResources(); mDialDrawable = r.getDrawable(R.drawable.clock_white); mHourDrawable = r.getDrawable(R.drawable.appwidget_clock_hour); mMinuteDrawable = r.getDrawable(R.drawable.appwidget_clock_minute); mSecondDrawable = r.getDrawable(R.drawable.appwidget_clock_second); mJavaTime = new Time(); mDialWidth = mDialDrawable.getIntrinsicWidth(); mDialHeight = mDialDrawable.getIntrinsicHeight(); } private void updateHandler() { mHandler = new Handler(); mHandler.post(mtimeRunnable); } private Runnable mtimeRunnable = new Runnable() { @Override public void run() { timeChanged(); postInvalidate(); mHandler.postDelayed(mtimeRunnable, 1000);//每隔1s刷新时间 }// run }; @Override protected void onAttachedToWindow() { super.onAttachedToWindow(); if (!mAttached) { mAttached = true; }// if mJavaTime = new Time(); timeChanged(); updateHandler(); } @Override protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) { int widthMode = MeasureSpec.getMode(widthMeasureSpec); int widthSize = MeasureSpec.getSize(widthMeasureSpec); int heightMode = MeasureSpec.getMode(heightMeasureSpec); int heightSize = MeasureSpec.getSize(heightMeasureSpec); float widthScale = 1.0f; float heightScale = 1.0f; if (widthMode != MeasureSpec.UNSPECIFIED && widthSize < mDialWidth) { widthScale = (float) widthSize / (float) mDialWidth; } if (heightMode != MeasureSpec.UNSPECIFIED && heightSize < mDialHeight) { heightScale = (float) heightSize / (float) mDialHeight; } float scale = Math.min(widthScale, heightScale); setMeasuredDimension( resolveSize((int) (scale * mDialWidth), widthMeasureSpec), resolveSize((int) (scale * mDialHeight), heightMeasureSpec)); } @Override protected void onSizeChanged(int w, int h, int oldw, int oldh) { // TODO Auto-generated method stub super.onSizeChanged(w, h, oldw, oldh); mChanged = true; } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); boolean changed = mChanged; if (changed) { mChanged = false; } int availableWidth = mDialDrawable.getIntrinsicWidth(); int availableHeight = mDialDrawable.getIntrinsicHeight(); int centerX = availableWidth / 2;//中心点x的位置 int centerY = availableHeight / 2;//中心点Y的位置 final Drawable dial = mDialDrawable; int w = dial.getIntrinsicWidth(); int h = dial.getIntrinsicHeight(); boolean scaled = false; if (availableWidth < w || availableHeight < h) { scaled = true; float scale = Math.min((float) availableWidth / (float) w, (float) availableHeight / (float) h); canvas.save(); canvas.scale(scale, scale, centerX, centerY); } if (changed) { dial.setBounds(centerX - (w / 2), centerY - (h / 2), centerX + (w / 2), centerY + (h / 2)); } dial.draw(canvas); canvas.save(); canvas.rotate(mHours / 12.0f * 360.0f, centerX, centerY); // 计算时针旋转的角度 final Drawable hourDrawable = mHourDrawable; if (changed) { w = hourDrawable.getIntrinsicWidth(); h = hourDrawable.getIntrinsicHeight(); hourDrawable.setBounds(centerX - (w / 2), centerY - (h / 2), centerX + (w / 2), centerY + (h / 2)); } hourDrawable.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mMinutes / 60.0f * 360.0f, centerX, centerY); //分针旋转的角度 final Drawable minuteDrawable = mMinuteDrawable; if (changed) { w = minuteDrawable.getIntrinsicWidth(); h = minuteDrawable.getIntrinsicHeight(); minuteDrawable.setBounds(centerX - (w / 2), centerY - (h / 2), centerX + (w / 2), centerY + (h / 2)); } minuteDrawable.draw(canvas); canvas.restore(); canvas.save(); canvas.rotate(mSeconds / 60.f * 360.0f, centerX, centerY); //秒针旋转的角度 final Drawable secondDrawable = mSecondDrawable; if (changed) { w = secondDrawable.getIntrinsicWidth(); h = secondDrawable.getIntrinsicHeight(); secondDrawable.setBounds(centerX - (w / 2), centerY - (h / 2), centerX + (w / 2), centerY + (h / 2)); } secondDrawable.draw(canvas); canvas.restore(); // canvas.save(); if (scaled) { canvas.restore(); } } private void timeChanged() { mJavaTime.setToNow(); int hour = mJavaTime.hour; int minute = mJavaTime.minute; int second = mJavaTime.second; mSeconds = second; mMinutes = minute + second / 60.f; mHours = hour + minute / 60.f; mChanged = true; } @Override protected void onDetachedFromWindow() { super.onDetachedFromWindow(); if (mAttached) { mAttached = false; } if (null != mtimeRunnable) { mtimeRunnable = null; } } }
2、将AnalogClock 加载在layout布局中
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" android:gravity="center" > <cn.anglogclock.demo.AnalogClock android:layout_width="wrap_content" android:layout_height="wrap_content" /> </LinearLayout>
3、在MainActivity中加载main布局文件
package cn.anglogclock.demo; import android.os.Bundle; import android.support.v7.app.ActionBarActivity; import android.view.Menu; import android.view.MenuItem; public class MainActivity extends ActionBarActivity { @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } @Override public boolean onOptionsItemSelected(MenuItem item) { // Handle action bar item clicks here. The action bar will // automatically handle clicks on the Home/Up button, so long // as you specify a parent activity in AndroidManifest.xml. int id = item.getItemId(); if (id == R.id.action_settings) { return true; } return super.onOptionsItemSelected(item); } }4、mainfest中进行注册
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="cn.anglogclock.demo" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="21" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="cn.anglogclock.demo.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest>