最近想好好看下自定義View,有趣使用,下面是在學習別人代碼的基礎上寫出來的一個View。
package com.example.xxiang1x.teststudio;
import android.annotation.TargetApi;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Build;
import android.os.Handler;
import android.os.Looper;
import android.util.AttributeSet;
import android.view.View;
import java.util.Calendar;
import java.util.GregorianCalendar;
/**
* 手表表盤
*/
public class WatchView extends View {
//create some variables
/**
* 分針畫筆
*/
private Paint minPaint;
/**
* 秒針畫筆
*/
private Paint secondPaint;
/**
* 時針畫筆
*/
private Paint hourPaint;
/**
* 表盤外輪廓畫筆
*/
private Paint circlePaint;
/**
* 表盤文字的畫筆
*/
private Paint textPaint;
/**
* 表盤內短線畫筆
*/
private Paint linePaint;
//width and height
/**
* View的寬
*/
private int mWidth;
/**
* View的高
*/
private int mHeight;
private static final double ROUND = 2d * Math.PI;
private static final double QUARTER = 1d / 4d;
private Handler mHandler = new Handler(Looper.getMainLooper());
private Calendar calendar = new GregorianCalendar();
public WatchView(Context context) {
super(context);
}
public WatchView(Context context, AttributeSet attrs) {
super(context, attrs);
initPaint();
}
/**
* 創建所有的paint
*/
private void initPaint() {
minPaint = getAvailablePaint(Color.BLUE, 0, 15, Paint.Style.FILL_AND_STROKE);
secondPaint = getAvailablePaint(Color.RED, 0, 15, Paint.Style.FILL_AND_STROKE);
hourPaint = getAvailablePaint(Color.GRAY, 0, 15, Paint.Style.FILL_AND_STROKE);
circlePaint = getAvailablePaint(Color.GRAY, 5, 10, Paint.Style.STROKE);
textPaint = getAvailablePaint(Color.GRAY, 45, 3, Paint.Style.FILL);
linePaint = getAvailablePaint(Color.GRAY, 45, 3, Paint.Style.FILL);
}
/**
* get a paint by ur request.
*
* @param color
* @param textSize
* @param strockWidth
* @param style
* @return
*/
private Paint getAvailablePaint(int color, int textSize, int strockWidth, Paint.Style style) {
Paint paint = new Paint(Paint.ANTI_ALIAS_FLAG | Paint.FAKE_BOLD_TEXT_FLAG);
paint.setAntiAlias(true);
paint.setTextSize(textSize);
paint.setAlpha(1);
paint.setColor(color);
paint.setStyle(style);
paint.setStrokeWidth(strockWidth);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setTextAlign(Paint.Align.CENTER);
paint.setStrokeCap(Paint.Cap.ROUND);
paint.setDither(true);//設置圖像抖動處理
paint.setStrokeJoin(Paint.Join.ROUND);//畫筆線等連接處的輪廓樣式
paint.setSubpixelText(true);
return paint;
}
@TargetApi(Build.VERSION_CODES.LOLLIPOP)
public WatchView(Context context, AttributeSet attrs, int defStyleAttr, int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//獲取圓心坐標
int x = mWidth / 2;
int y = mHeight / 2;
//半徑
int radius = Math.min(x, y) - 10;
// 為了讓秒針連續轉動,所以秒針的角度肯定不是從「秒」這個整數里來
// 剛好秒針走一圈是 1 分鐘,那么,就用分乘以「一圈(2π)」就是秒針要走的弧度數了
float millis = calendar.get(Calendar.MILLISECOND) / 1000f;
float second = (calendar.get(Calendar.SECOND) + millis) / 60f;
float minute = (calendar.get(Calendar.MINUTE) + second) / 60f;
float hour = (calendar.get(Calendar.HOUR) + minute) / 12f;
drawHand(canvas, hourPaint, x, y, radius * 0.5f, hour);
drawHand(canvas, minPaint, x, y, radius * 0.6f, minute);
drawHand(canvas, secondPaint, x, y, radius * 0.7f, second);
//draw the hour line .
drawHourNumbers(canvas, textPaint, mWidth, mHeight);
//draw the minutes line .
drawMinuteLine(canvas, linePaint, mWidth, mHeight);
//draw outer circle
circlePaint.setColor(Color.GRAY);
canvas.drawCircle(x, y, radius, circlePaint);
//draw center point
circlePaint.setColor(Color.YELLOW);
canvas.drawCircle(x, y, 3, circlePaint);
}
/**
* 畫小時的線
*
* @param canvas
* @param paint
* @param width
* @param height
*/
private void drawHourNumbers(Canvas canvas, Paint paint, int width, int height) {
//12個小時,12條線。
for (int i = 1; i < 13; i++) {
canvas.save(); //save current state of canvas.
canvas.rotate(360 / 12 * i, width / 2, height / 2);
//繪制表盤
canvas.drawLine(width / 2, height / 2 - (width / 2 - 20), width / 2, height / 2 - width / 2 + 40, paint);
//繪制文字
canvas.drawText("" + i, width / 2, height / 2 - width / 2 + 80, paint);
//恢復開始位置
canvas.restore();
}
}
/**
* 畫分鐘的線
*
* @param canvas
* @param paint
* @param width
* @param height
*/
private void drawMinuteLine(Canvas canvas, Paint paint, int width, int height) {
//一共分出來有60條線
for (int i = 1; i < 61; i++) {
canvas.save(); //save current state of canvas.
canvas.rotate(360 / 12 / 5 * i, width / 2, height / 2);
//繪制表盤
canvas.drawLine(width / 2, height / 2 - (width / 2 - 20), width / 2, height / 2 - width / 2 + 30, paint);
//恢復開始位置
canvas.restore();
}
}
/**
* @param canvas
* @param paint
* @param x
* @param y
* @param length
* @param round
*/
private void drawHand(Canvas canvas, Paint paint, float x, float y, float length, float round) {
// 三角函數的坐標軸是以 3 點方向為 0 的,所以記得要減去四分之一個圓周哦
double radians = (round - QUARTER) * ROUND;
canvas.drawLine(
x,
y,
x + (float) Math.cos(radians) * length,
y + (float) Math.sin(radians) * length,
paint);
}
@Override
protected void onAttachedToWindow() {
super.onAttachedToWindow();
mHandler.post(r);
}
@Override
protected void onDetachedFromWindow() {
super.onDetachedFromWindow();
mHandler.removeCallbacksAndMessages(null);//remove all of the messages.
}
//子線程+handler不斷更新View
Runnable r = new Runnable() {
@Override
public void run() {
calendar.setTimeInMillis(System.currentTimeMillis());
invalidate();
mHandler.postDelayed(this, 1000 / 60);
}
};
/**
* 獲取寬和高
*
* @param widthMeasureSpec
* @param heightMeasureSpec
*/
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
super.onMeasure(widthMeasureSpec, heightMeasureSpec);
//獲取View的寬高。
mWidth = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
mHeight = getDefaultSize(getSuggestedMinimumWidth(), heightMeasureSpec);
}
}
擦,在studio的模擬器上面好多了。在genymotion模擬器上比較模糊。
Screen Shot 2016-04-08 at 4.36.48 PM.png
Screen Shot 2016-04-08 at 3.39.40 PM.png