基础绘制 请阅读 http://blog.csdn.net/daweibalang717/article/details/51776446
通过上文可以学会简单的图形绘制,我们来进行一个钟表的绘制。
效果图:
布局文件:
<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout 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:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context="com.example.myapplication.MainActivity">
<ImageView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/imageView"
android:layout_centerInParent="true"
android:layout_marginTop="55dp" />
</RelativeLayout>
Java 文件:
package com.example.myapplication;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Typeface;
import android.os.AsyncTask;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.widget.ImageView;
import java.util.Calendar;
public class MainActivity extends AppCompatActivity {
private ImageView mClockImageView;
private int width = 600;
private int height = 600;
private Calendar mCanlendar;
//时分秒
private int mHours,mMinue,mSecond;
private boolean isRun;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mClockImageView = (ImageView) findViewById(R.id.imageView);
isRun = true;
MyClockTask task = new MyClockTask();
task.execute();
}
//AsyncTask 类 可参考博客:http://blog.csdn.net/Kaiwii/article/details/21541499
private class MyClockTask extends AsyncTask<Object,Bitmap,Object>{
@Override
protected Object doInBackground(Object[] objects) {
while (isRun){
//一秒钟重绘一次指针
publishProgress(getDrawClockPointer());
try {
Thread.sleep(1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return null;
}
@Override
protected void onProgressUpdate(Bitmap... values) {
super.onProgressUpdate(values);
//每次重绘的内容更新到 ImageView 上;
mClockImageView.setImageBitmap(values[0]);
}
}
//画指针
private Bitmap getDrawClockPointer(){
Bitmap bm = getDrawClockDial();
Canvas canvas = new Canvas(bm);
Paint paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.BLACK);
mCanlendar = Calendar.getInstance();
mHours = mCanlendar.get(Calendar.HOUR);
mMinue = mCanlendar.get(Calendar.MINUTE);
mSecond = mCanlendar.get(Calendar.SECOND);
canvas.save();
//画时针(参考表盘如何画数字的),一小时30度,再加上分钟的度数(60分钟,时针偏转30度),每分钟时针偏转 mMinue*(30.0f/60.0f),
float degreesH = mHours*30 + mMinue*(30.0f/60.0f);
//基于圆心旋转
canvas.rotate(degreesH,width / 2,height / 2);
//时针的风格
paint.setColor(Color.RED);
paint.setStrokeWidth(6);
//时针的长
float lengthH = (height/2)*0.4f;
//时针 : 第四个参数的解释:因为半径是 height/2 或 width/2,线是从圆心开始的,所以结束的Y坐标是:height - height/2 - length
canvas.drawLine(width / 2,height / 2,width / 2,height - height/2 - lengthH,paint);
canvas.restore();
canvas.save();
//画分针 每分钟 6度 在加上秒针的度数(60秒钟 偏转6度),那么每秒钟 分钟偏转的度数 mSecond*(6.0f/60.0f);
float degreesM = mMinue*6 + mSecond*(6.0f/60.0f);
//基于圆心旋转
canvas.rotate(degreesM,width / 2,height / 2);
//分针的风格
paint.setColor(Color.GREEN);
paint.setStrokeWidth(4);
//分针的长
float lengthM = (height/2)*0.6f;
//分针 : 第四个参数的解释:因为半径是 height/2 或 width/2,线是从圆心开始的,所以结束的Y坐标是:height - height/2 - length
canvas.drawLine(width / 2,height / 2,width / 2,height - height/2 - lengthM,paint);
canvas.restore();
canvas.save();
//画秒针 每秒 6度
float degreesS = mSecond*6;
//基于圆心旋转
canvas.rotate(degreesS,width / 2,height / 2);
//秒针的风格
paint.setColor(Color.BLUE);
paint.setStrokeWidth(2);
//秒针的长
float lengthS = (height/2)*0.8f;
//秒针 : 第四个参数的解释:因为半径是 height/2 或 width/2,线是从圆心开始的,所以结束的Y坐标是:height - height/2 - length
canvas.drawLine(width / 2,height / 2,width / 2,height - height/2 - lengthS,paint);
canvas.restore();
return bm;
}
//画表盘
private Bitmap getDrawClockDial() {
//创建Bitmap
Bitmap bm = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);
//创建画布
Canvas canvas = new Canvas(bm);
//创建画笔
Paint paint = new Paint();
//空心
paint.setStyle(Paint.Style.STROKE);
//颜色
paint.setColor(Color.BLACK);
//宽度
paint.setStrokeWidth(6);
//抗锯齿
paint.setAntiAlias(true);
//画一个圆,前两个参数是中心点,第三个是半径,第四个是画笔
//注:因为圆圈的宽度为20,所以我们在计算的时候要把宽度给算进来
canvas.drawCircle(width / 2, height / 2, (width - 6) / 2, paint);
//在圆的中间画一个点 (圆点)
paint.setStyle(Paint.Style.FILL);
canvas.drawCircle(width / 2, height / 2, 4, paint);
/**
* 方便理解:画布是个虚拟的感念,可理解为即坐标系,而我们要画的内容是画在bitmap上的。
*
* 现在要画刻度了,我们要怎么画呢,我们想象一个圈360度,总共12个小时
* 一个小时就是:360/12 = 30;
* 思路:我们先保存画布的状态 canvas.save();
* for循环中,我们把坐标系旋转30度,然后写上 1 ,
* 然后再30度,写上2 ...等旋转360度的时候写上 12
* 这时候画布正好转了一圈,但是,注意,注意:
* 我们调用了canvas.restore(); 就是把坐标系回到开始保存的状态,
* 开始的状态的意思是:(坐标系是 x 左到右横向,Y是从上到下),我们旋转了360度把数字都给写上了,
* 而且写完后 (坐标系是 x 左到右横向,Y是从上到下,因为我们旋转了360度),
* 但是我们毕竟旋转了360度。也就是说现在坐标系的状态
* 是360度,canvas.restore()就是把这状态转回0度,
* 当然了,你不调用canvas.save(); canvas.restore(); 也是可以的,毕竟是旋转了360度,我这里说这个其实
* 就是为了说明这两个方法。还有旋转的概念,旋转的其实是坐标系(之前我对这点特别迷惑,认为画的东西就在画布上)
* 参考博客:http://blog.csdn.net/dinko321/article/details/7679019
* */
//先保存现在画布的状态,打个比方说就是 现在记录现在画布的方向,那头朝上,那头朝下啊的什么的。
canvas.save();
//这个画笔用来画 3 、6、9、12 加粗
Paint textPaint = new Paint();
textPaint.setColor(Color.BLACK);
textPaint.setTextSize(25);
textPaint.setTypeface(Typeface.defaultFromStyle(Typeface.BOLD));
textPaint.setTextAlign(Paint.Align.CENTER);
for (int i = 1; i <= 12; i++) {
//旋转30度 后两个参数是基于那个点旋转,这里是圆心
canvas.rotate(30, width / 2, height / 2);
// 3 、6、9、12 加粗
if (i % 3 == 0) {
//Y 值我是估计写的 关于这个函数可以看:http://blog.csdn.net/sirnuo/article/details/21165665
canvas.drawText(String.valueOf(i), width / 2, (20 + 6) * 2, textPaint);
} else {
paint.setTextSize(20);
paint.setTextAlign(Paint.Align.CENTER);
canvas.drawText(String.valueOf(i), width / 2, (20 + 6) * 2, paint);
}
}
canvas.restore();
return bm;
}
@Override
protected void onResume() {
super.onResume();
isRun = true;
}
@Override
protected void onPause() {
super.onPause();
isRun = false;
}
@Override
protected void onDestroy() {
super.onDestroy();
}
}
本代码总结于学习视频,是用于备忘。函数参数说明都在代码注释中。