【问题】
- 通过自定义 View 来实现一个钟表;
【效果图】
【代码分析】
-
重写 onDraw
-
画外圆
/**
* 画外圆和中心实心圆
* @param canvas
*/
private void drawCircle(Canvas canvas) {
Paint paint = new Paint();
paint.setColor(mRingColor);
paint.setStyle(Paint.Style.STROKE);
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStrokeWidth(getDigit(2));
canvas.drawCircle(mWidth/2, mHeight/2, mDiameter/2, paint);
// 画中心的实心圆
paint.setStyle(Paint.Style.FILL);
paint.setColor(mCenterPointColor);
canvas.drawCircle(mWidth/2, mHeight/2, getDigit(4), paint);
}
-
画刻度
/**
* 画刻度
* @param canvas
*/
private void drawScale(Canvas canvas) {
Paint paint = new Paint();
paint.setStrokeWidth(getDigit(1));
paint.setTextSize(getDigit(10));
paint.setAntiAlias(true);
for(int i=0; i<60; i++){
if(i%5 == 0){
paint.setStrokeWidth(getDigit(2));
paint.setColor(mLongScaleColor);
paint.setTextSize(getDigit(15));
String timeText = "" + i/5;
if(i==0){
timeText = "12";
}
canvas.drawLine(mWidth/2, mHeight/2 - mDiameter/2, mWidth/2, mHeight/2 - mDiameter/2 + 40, paint);
paint.setColor(mTextColor);
canvas.drawText(timeText, mWidth/2-paint.measureText(timeText)/2, mHeight/2-mDiameter/2+80, paint);
} else {
paint.setStrokeWidth(getDigit(1));
paint.setTextSize(getDigit(15));
paint.setColor(mShortScaleColor);
canvas.drawLine(mWidth/2, mHeight/2 - mDiameter/2, mWidth/2, mHeight/2 - mDiameter/2 + 20, paint);
}
// 旋转画布,每次旋转6度
canvas.rotate(6,mWidth/2, mHeight/2);
}
}
-
画指针
/**
* 画指针:时针,分针,秒针
* @param canvas
*/
private void drawIndicator(Canvas canvas) {
// 保存图层
canvas.save();
canvas.translate(mWidth/2f, mHeight/2f);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setDither(true);
paint.setStrokeWidth(getDigit(3));
paint.setColor(mHourColor);
canvas.drawLine(0, 0, getLeftBy(H), getTopBy(H), paint);
paint.setStrokeWidth(getDigit(2));
paint.setColor(mMinuteColor);
canvas.drawLine(0, 0, getLeftBy(M), getTopBy(M), paint);
paint.setStrokeWidth(getDigit(1));
paint.setColor(mSecondColor);
canvas.drawLine(0, 0, getLeftBy(S), getTopBy(S), paint);
// 合并图层
canvas.restore();
}
private float getLeftBy(int indicator){
float r=0f;
float digit = 0;
switch(indicator){
case H:
r = mHourR;
// 根据分钟进行补充,每5分钟进一小格
digit = ((mHour%12/12f*60 + mMinute/60f*5)) % 60;
break;
case M:
r = mMinuteR;
digit = mMinute;
break;
case S:
r = mSecondR;
digit = mSecond+1;
break;
}
float left = (float) Math.sin(digit/60f * Math.PI*2) * r;
if(digit<=30){
return Math.abs(left);
} else {
return -Math.abs(left);
}
}
private float getTopBy(int indicator){
float r=0f;
float digit = 0;
switch(indicator){
case H:
r = mHourR;
// 根据分钟进行补充,每5分钟进一小格
digit = ((mHour%12/12f*60 + mMinute/60f*5)) % 60;
break;
case M:
r = mMinuteR;
digit = mMinute;
break;
case S:
r = mSecondR;
digit = mSecond+1;
break;
}
float left = (float) Math.cos(digit/60f * Math.PI*2) * r;
if(15<=digit && digit<=45){
return Math.abs(left);
} else {
return -Math.abs(left);
}
}
-
-
重写 onMesure
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
mWidth = measuredWidth(widthMeasureSpec);
mHeight = measuredHeight(heightMeasureSpec);
setMeasuredDimension(mWidth, mHeight);
// 钟表的外圆直径(除去 padding )
mDiameter = Math.min(mWidth - getPaddingLeft() - getPaddingRight(), mHeight - getPaddingTop() - getPaddingBottom());
// 时针半径外环半径的1/3
mHourR = mDiameter/2f/3;
// 分针半径为外环半径的1/2
mMinuteR = mDiameter/2f/2;
// 秒针半径为外环半径的1/1.5
mSecondR = mDiameter/2f/1.5f;
}
private int measuredWidth(int widthMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(widthMeasureSpec);
int specSize = MeasureSpec.getSize(widthMeasureSpec);
if(specMode == MeasureSpec.EXACTLY){
result = specSize;
} else {
result = 500;
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result, specSize);
}
}
return result;
}
private int measuredHeight(int heightMeasureSpec) {
int result = 0;
int specMode = MeasureSpec.getMode(heightMeasureSpec);
int specSize = MeasureSpec.getSize(heightMeasureSpec);
if(specMode == MeasureSpec.EXACTLY){
result = specSize;
} else {
result = 500;
if(specMode == MeasureSpec.AT_MOST){
result = Math.min(result, specSize);
}
}
return result;
}
-
用新线程启动钟表
/**
* 启动钟表
*/
private void startClock(){
new Thread(new Runnable() {
@Override
public void run() {
while (true) {
Calendar calendar = Calendar.getInstance();
calendar.setTime(new Date());
int hour = calendar.get(Calendar.HOUR)+1;
int minute = calendar.get(Calendar.MINUTE);
int second = calendar.get(Calendar.SECOND);
setHour(hour);
setMinute(minute);
setSecond(second);
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}).start();
}