├── images
├── 0.jpg
└── 1.jpg
├── ic_launcher-web.png
├── libs
└── android-support-v4.jar
├── res
├── drawable-xhdpi
│ ├── btn_clock.png
│ ├── ic_launcher.png
│ ├── clock_hand_hour.png
│ ├── clock_hand_minute.png
│ └── clock_hand_second.png
├── drawable-hdpi
│ └── ic_launcher.png
├── drawable-mdpi
│ └── ic_launcher.png
├── drawable-xxhdpi
│ └── ic_launcher.png
├── values-sw600dp
│ └── dimens.xml
├── values
│ ├── dimens.xml
│ ├── strings.xml
│ └── styles.xml
├── menu
│ └── main.xml
├── values-sw720dp-land
│ └── dimens.xml
├── values-v11
│ └── styles.xml
├── values-v14
│ └── styles.xml
└── layout
│ └── activity_main.xml
├── .settings
└── org.eclipse.jdt.core.prefs
├── README.md
├── src
└── com
│ └── example
│ ├── android_clock
│ └── MainActivity.java
│ └── widget
│ └── AnalogClock.java
├── .classpath
├── project.properties
├── proguard-project.txt
├── .project
└── AndroidManifest.xml
/images/0.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/images/0.jpg
--------------------------------------------------------------------------------
/images/1.jpg:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/images/1.jpg
--------------------------------------------------------------------------------
/ic_launcher-web.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/ic_launcher-web.png
--------------------------------------------------------------------------------
/libs/android-support-v4.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/libs/android-support-v4.jar
--------------------------------------------------------------------------------
/res/drawable-xhdpi/btn_clock.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-xhdpi/btn_clock.png
--------------------------------------------------------------------------------
/res/drawable-hdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-hdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-mdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-mdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-xhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xxhdpi/ic_launcher.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-xxhdpi/ic_launcher.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/clock_hand_hour.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-xhdpi/clock_hand_hour.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/clock_hand_minute.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-xhdpi/clock_hand_minute.png
--------------------------------------------------------------------------------
/res/drawable-xhdpi/clock_hand_second.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/xuningjack/CustomClock/HEAD/res/drawable-xhdpi/clock_hand_second.png
--------------------------------------------------------------------------------
/.settings/org.eclipse.jdt.core.prefs:
--------------------------------------------------------------------------------
1 | eclipse.preferences.version=1
2 | org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
3 | org.eclipse.jdt.core.compiler.compliance=1.6
4 | org.eclipse.jdt.core.compiler.source=1.6
5 |
--------------------------------------------------------------------------------
/res/values-sw600dp/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
8 |
--------------------------------------------------------------------------------
/res/values/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | 16dp
5 | 16dp
6 |
7 |
--------------------------------------------------------------------------------
/res/values/strings.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 | Android_clock
5 | Settings
6 | Hello world!
7 |
8 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # CustomClock
2 | The clock is painted by canvas, with a hour,minute and second hand (手画的时钟,带有时、分、秒针)
3 | 效果图:
4 | 
5 |
6 | 
7 |
--------------------------------------------------------------------------------
/res/menu/main.xml:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/res/values-sw720dp-land/dimens.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 | 128dp
8 |
9 |
--------------------------------------------------------------------------------
/res/values-v11/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
10 |
11 |
--------------------------------------------------------------------------------
/src/com/example/android_clock/MainActivity.java:
--------------------------------------------------------------------------------
1 | package com.example.android_clock;
2 |
3 | import android.os.Bundle;
4 | import android.app.Activity;
5 | import android.view.Menu;
6 |
7 | public class MainActivity extends Activity {
8 |
9 | @Override
10 | protected void onCreate(Bundle savedInstanceState) {
11 | super.onCreate(savedInstanceState);
12 | setContentView(R.layout.activity_main);
13 |
14 | }
15 | }
16 |
--------------------------------------------------------------------------------
/res/values-v14/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
8 |
11 |
12 |
--------------------------------------------------------------------------------
/.classpath:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 |
9 |
10 |
--------------------------------------------------------------------------------
/project.properties:
--------------------------------------------------------------------------------
1 | # This file is automatically generated by Android Tools.
2 | # Do not modify this file -- YOUR CHANGES WILL BE ERASED!
3 | #
4 | # This file must be checked in Version Control Systems.
5 | #
6 | # To customize properties used by the Ant build system edit
7 | # "ant.properties", and override values to adapt the script to your
8 | # project structure.
9 | #
10 | # To enable ProGuard to shrink and obfuscate your code, uncomment this (available properties: sdk.dir, user.home):
11 | #proguard.config=${sdk.dir}/tools/proguard/proguard-android.txt:proguard-project.txt
12 |
13 | # Project target.
14 | target=android-19
15 |
--------------------------------------------------------------------------------
/res/values/styles.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
7 |
14 |
15 |
16 |
19 |
20 |
--------------------------------------------------------------------------------
/proguard-project.txt:
--------------------------------------------------------------------------------
1 | # To enable ProGuard in your project, edit project.properties
2 | # to define the proguard.config property as described in that file.
3 | #
4 | # Add project specific ProGuard rules here.
5 | # By default, the flags in this file are appended to flags specified
6 | # in ${sdk.dir}/tools/proguard/proguard-android.txt
7 | # You can edit the include path and order by changing the ProGuard
8 | # include property in project.properties.
9 | #
10 | # For more details, see
11 | # http://developer.android.com/guide/developing/tools/proguard.html
12 |
13 | # Add any project specific keep options here:
14 |
15 | # If your project uses WebView with JS, uncomment the following
16 | # and specify the fully qualified class name to the JavaScript interface
17 | # class:
18 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview {
19 | # public *;
20 | #}
21 |
--------------------------------------------------------------------------------
/res/layout/activity_main.xml:
--------------------------------------------------------------------------------
1 |
10 |
11 |
18 |
19 |
--------------------------------------------------------------------------------
/.project:
--------------------------------------------------------------------------------
1 |
2 |
3 | Android_clock
4 |
5 |
6 |
7 |
8 |
9 | com.android.ide.eclipse.adt.ResourceManagerBuilder
10 |
11 |
12 |
13 |
14 | com.android.ide.eclipse.adt.PreCompilerBuilder
15 |
16 |
17 |
18 |
19 | org.eclipse.jdt.core.javabuilder
20 |
21 |
22 |
23 |
24 | com.android.ide.eclipse.adt.ApkBuilder
25 |
26 |
27 |
28 |
29 |
30 | com.android.ide.eclipse.adt.AndroidNature
31 | org.eclipse.jdt.core.javanature
32 |
33 |
34 |
--------------------------------------------------------------------------------
/AndroidManifest.xml:
--------------------------------------------------------------------------------
1 |
2 |
6 |
7 |
10 |
11 |
16 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/src/com/example/widget/AnalogClock.java:
--------------------------------------------------------------------------------
1 | package com.example.widget;
2 |
3 | import java.util.TimeZone;
4 | import android.content.BroadcastReceiver;
5 | import android.content.Context;
6 | import android.content.Intent;
7 | import android.content.IntentFilter;
8 | import android.content.res.Resources;
9 | import android.graphics.Canvas;
10 | import android.graphics.drawable.Drawable;
11 | import android.os.Handler;
12 | import android.text.format.DateUtils;
13 | import android.text.format.Time;
14 | import android.util.AttributeSet;
15 | import android.view.View;
16 | import android.widget.RemoteViews.RemoteView;
17 | import com.example.android_clock.R;
18 |
19 | /**
20 | * 有时针、分针、秒针的显示时钟
21 | */
22 | @RemoteView
23 | public class AnalogClock extends View {
24 |
25 | private Context mContext;
26 | private Time mCalendar;
27 | private Drawable mHourHand;
28 | private Drawable mMinuteHand;
29 | private Drawable mSecondHand;
30 | /** 时钟面板 */
31 | private Drawable mDial;
32 | private int mDialWidth;
33 | private int mDialHeight;
34 | private boolean mAttached;
35 | private final Handler mHandler = new Handler();
36 | private float mMinutes;
37 | private float mHour;
38 | private float mSecond;
39 | private boolean mChanged;
40 | /** 定时刷新 时钟界面的Handler */
41 | private Handler tickHandler;
42 |
43 | public AnalogClock(Context context) {
44 | this(context, null);
45 | }
46 |
47 | public AnalogClock(Context context, AttributeSet attrs) {
48 | this(context, attrs, 0);
49 | }
50 |
51 | public AnalogClock(Context context, AttributeSet attrs, int defStyle) {
52 | super(context, attrs, defStyle);
53 | mContext = context;
54 | mCalendar = new Time();
55 | Resources resource = mContext.getResources();
56 | mDial = resource.getDrawable(R.drawable.btn_clock);
57 | mHourHand = resource.getDrawable(R.drawable.clock_hand_hour);
58 | mMinuteHand = resource.getDrawable(R.drawable.clock_hand_minute);
59 | mSecondHand = resource.getDrawable(R.drawable.clock_hand_second);
60 | mDialWidth = mDial.getIntrinsicWidth();
61 | mDialHeight = mDial.getIntrinsicHeight();
62 | prepareRefresh();
63 | }
64 |
65 | /**
66 | * 准备刷新时钟面板
67 | */
68 | public void prepareRefresh() {
69 | tickHandler = new Handler();
70 | tickHandler.post(tickRunnable);
71 | }
72 |
73 | /**
74 | * 更新时钟的线程
75 | */
76 | private Runnable tickRunnable = new Runnable() {
77 | public void run() {
78 | onTimeChanged();
79 | postInvalidate();
80 | tickHandler.postDelayed(tickRunnable, 1000); // 1s中更改1次时间
81 | }
82 | };
83 |
84 | @Override
85 | protected void onAttachedToWindow() {
86 | super.onAttachedToWindow();
87 | if (!mAttached) {
88 | mAttached = true;
89 | IntentFilter filter = new IntentFilter();
90 | filter.addAction(Intent.ACTION_TIME_TICK);
91 | filter.addAction(Intent.ACTION_TIMEZONE_CHANGED);
92 | getContext().registerReceiver(mIntentReceiver, filter, null,
93 | mHandler);
94 | }
95 | mCalendar = new Time();
96 | onTimeChanged();
97 | }
98 |
99 | @Override
100 | protected void onDetachedFromWindow() {
101 | super.onDetachedFromWindow();
102 | if (mAttached) {
103 | getContext().unregisterReceiver(mIntentReceiver);
104 | mAttached = false;
105 | }
106 | }
107 |
108 | @Override
109 | protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
110 | // 设置控件大小为表盘的大小
111 | setMeasuredDimension(mDialWidth, mDialHeight);
112 | }
113 |
114 | @Override
115 | protected void onSizeChanged(int w, int h, int oldw, int oldh) {
116 | super.onSizeChanged(w, h, oldw, oldh);
117 | mChanged = true;
118 | }
119 |
120 | @Override
121 | protected void onDraw(Canvas canvas) {
122 | super.onDraw(canvas);
123 | boolean changed = mChanged;
124 | if (changed) {
125 |
126 | mChanged = false;
127 | }
128 |
129 | int availableWidth = getRight() - getLeft();
130 | System.out.println("availableWidth----" + availableWidth); // 76
131 | int availableHeight = getBottom() - getTop();
132 | System.out.println("availableWidth----" + availableHeight); // 86
133 |
134 | int x = availableWidth / 2;
135 | int y = availableHeight / 2;
136 | System.out.println("x----" + x); // 38
137 | System.out.println("y----" + y); // 43
138 |
139 | final Drawable dial = mDial;
140 | int w = dial.getIntrinsicWidth();
141 | System.out.println("w----" + w); // 76
142 | int h = dial.getIntrinsicHeight();
143 | System.out.println("h----" + h); // 86
144 |
145 | boolean scaled = false;
146 |
147 | // 开始画面板
148 | if (availableWidth < w || availableHeight < h) {
149 |
150 | scaled = true;
151 | float scale = Math.min((float) availableWidth / (float) w,
152 | (float) availableHeight / (float) h);
153 | canvas.save();
154 | canvas.scale(scale, scale, x, y);
155 | }
156 | if (changed) {
157 |
158 | dial.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y + (h / 2));
159 | }
160 | dial.draw(canvas);
161 |
162 | // 开始画时针
163 | canvas.save();
164 | canvas.rotate(mHour / 12.0f * 360.0f, x, y);
165 | final Drawable hourHand = mHourHand;
166 | if (changed) {
167 |
168 | w = hourHand.getIntrinsicWidth();
169 | h = hourHand.getIntrinsicHeight();
170 | hourHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y
171 | + (h / 2));
172 | }
173 | hourHand.draw(canvas);
174 |
175 | // 开始画分针
176 | canvas.restore();
177 | canvas.save();
178 | canvas.rotate(mMinutes / 60.0f * 360.0f, x, y);
179 | final Drawable minuteHand = mMinuteHand;
180 | if (changed) {
181 |
182 | w = minuteHand.getIntrinsicWidth();
183 | h = minuteHand.getIntrinsicHeight();
184 | minuteHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y
185 | + (h / 2));
186 | }
187 | minuteHand.draw(canvas);
188 |
189 | // 开始画秒针
190 | canvas.restore();
191 | canvas.save();
192 | canvas.rotate(mSecond / 60.0f * 360.0f, x, y);
193 | final Drawable secondHand = mSecondHand;
194 | if (changed) {
195 |
196 | w = secondHand.getIntrinsicWidth();
197 | h = secondHand.getIntrinsicHeight();
198 | secondHand.setBounds(x - (w / 2), y - (h / 2), x + (w / 2), y
199 | + (h / 2));
200 | }
201 | secondHand.draw(canvas);
202 | canvas.restore();
203 | if (scaled) {
204 | canvas.restore();
205 | }
206 | }
207 |
208 | /**
209 | * 更新时间到当前时间
210 | */
211 | private void onTimeChanged() {
212 | mCalendar.setToNow();
213 | int hour = mCalendar.hour;
214 | int minute = mCalendar.minute;
215 | int second = mCalendar.second;
216 |
217 | mMinutes = minute + second / 60.0f;
218 | mHour = hour + mMinutes / 60.0f;
219 | mSecond = second;
220 | mChanged = true;
221 | updateContentDescription(mCalendar);
222 | }
223 |
224 | @SuppressWarnings("deprecation")
225 | private void updateContentDescription(Time time) {
226 | final int flags = DateUtils.FORMAT_SHOW_TIME | DateUtils.FORMAT_24HOUR;
227 | String contentDescription = DateUtils.formatDateTime(mContext,
228 | time.toMillis(false), flags);
229 | setContentDescription(contentDescription);
230 | }
231 |
232 | private final BroadcastReceiver mIntentReceiver = new BroadcastReceiver() {
233 | @Override
234 | public void onReceive(Context context, Intent intent) {
235 | if (intent.getAction().equals(Intent.ACTION_TIMEZONE_CHANGED)) {
236 | String tz = intent.getStringExtra("time-zone");
237 | mCalendar = new Time(TimeZone.getTimeZone(tz).getID());
238 | }
239 | onTimeChanged();
240 | invalidate(); // 使UI无效
241 | }
242 | };
243 | }
--------------------------------------------------------------------------------