Android中使用Canvas绘制简单的图形(二) 进阶 绘制钟表

基础绘制 请阅读 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();

    }
}



本代码总结于学习视频,是用于备忘。函数参数说明都在代码注释中。



  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值