0916Android基础自定义View(Canvas绘图)

自定义View

自定义View的一些知识

  自定义一个类继承View,然后将这个View添加到布局文件中 ,然后在活动中对这个View进行UI操作。在onDraw方法中需要用到Canvas来画各种形状的图形。Canvas的方法中还涉及到一个API:Paint,代表了Canvas上面的画笔,因此Paint类主要用于设置绘制风格,包括画笔颜色、画笔笔触粗细、填充风格等,常用的方法例:

  • setColor(int color):设置颜色
  • setAntiAlias(boolean aa):设置是否抗锯齿(true则抗锯齿)
  • setStrokeWidth(float width):设置线宽
  • setStyle(Paint.Style style):设置风格,例setStyle(Paint.Style.STROKE)设置为无填充
  • setTextSize(float textSize):设置字体大小

另外Canvas还提供了一些方法进行坐标变换,如

  • rotate(float degrees,float px,float py):对Canvas进行旋转变换
  • scale(float sx,float sy,float px,float py): 对Canvas进行缩放变换
  • skew(float sx,float sy):对Canvas执行倾斜变换
  • translate(float dx,float dy):移动Canvas (正数:向右移动dx距离,向下移动dy距离;负数:相反)

自定义View的步骤:

  • 新建一个类继承View
  • 继承一个构造方法(根据自己的需要,此处选的是两个参数的那个构造
    器和一个参数的那个构造器)
  • 重写onMesure
  • 重写onDraw

时钟Demo

  
  其实这玩意也挺麻烦的。。。这家伙数字还没有调过来呢,要调的话太麻烦,将就用了╮(╯▽╰)╭。
实现这个钟表大体分为4步:

  1. 新建类继承View,重写俩个方法onDraw和onMeasure,继承两个构造方法
  2. 绘制钟表
  3. 使钟表动起来
  4. 将组件添加到布局中

绘制钟表
在onMeasure中设置长度宽度

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWith = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        mHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    }

在两个参数的构造器中设置画笔paint

  public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mLinePaint=new Paint();
        mLinePaint.setColor(Color.BLACK);
        mLinePaint.setStrokeWidth(5);//线宽
        mLinePaint.setAntiAlias(true);//抗锯齿

        mLineSecondPaint=new Paint();
        mLineSecondPaint.setColor(Color.BLACK);
        mLineSecondPaint.setStrokeWidth(2);//线宽
        mLineSecondPaint.setAntiAlias(true);//抗锯齿

        mCirclePaint=new Paint();
        mCirclePaint.setColor(Color.BLACK);
        mCirclePaint.setStrokeWidth(5);//线宽
        mCirclePaint.setStyle(Paint.Style.STROKE);//空心圆
        mCirclePaint.setAntiAlias(true);//抗锯齿

        mCircleText=new Paint();
        mCircleText.setTextSize(30);//字体大小
        mCircleText.setTextAlign(Paint.Align.CENTER);//对齐方式


    }

在onDraw中画出图形,需要注意的是其中整数相除的时候必须要造型成浮点型数据,不然会出错。

  @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//      onDraw是由UI主线程自动调用,只需要再此绘制即可
//        canvas.drawLine(0, 0, 222, 222, mLinePaint);
        canvas.drawCircle(mWith / 2, mHeight / 2, 200, mCirclePaint);
        canvas.drawCircle(mWith / 2, mHeight / 2, 2, mCirclePaint);
        for(int i=1;i<=12;i++) {
            canvas.save();//保存当前画布状态
            canvas.rotate(360 / 12 * i, mWith / 2, mHeight / 2);//旋转,先旋转再画(旋转角度,旋转中心点xy坐标)
            canvas.drawLine(mWith / 2, mHeight / 2 - 200, mWith / 2, mHeight / 2 - 180, mLinePaint);
            canvas.drawText("" + i, mWith / 2, mHeight / 2 - 150, mCircleText);
            canvas.restore();//恢复到原位置
        }

        mCalendar=Calendar.getInstance();
//        获得时分秒
        int minute=mCalendar.get(Calendar.MINUTE);
        int hour=mCalendar.get(Calendar.HOUR);
        int second=mCalendar.get(Calendar.SECOND);
//        画上分针
        float degree=minute/60f*360;//必须定义成浮点型数据,
        canvas.save();
        canvas.rotate(degree, mWith / 2, mHeight / 2);//将下面line旋转这些角度
        canvas.drawLine(mWith / 2, mHeight / 2 - 120, mWith / 2, mHeight / 2 +20, mLinePaint);
        canvas.restore();
//        画上时针
        float hourDegree=(hour*60+minute)/(12*60f)*360;
        canvas.save();
        canvas.rotate(hourDegree, mWith / 2, mHeight / 2);
        canvas.drawLine(mWith / 2, mHeight / 2 - 90, mWith / 2, mHeight / 2 +20, mLinePaint);
        canvas.restore();
//        画上秒针
        float secondDegree=second/60f*360;//加f的位置要注意- -
        canvas.save();
        canvas.rotate(secondDegree, mWith / 2, mHeight / 2);
        canvas.drawLine(mWith / 2, mHeight / 2 - 140, mWith / 2, mHeight / 2 + 20, mLineSecondPaint);
        canvas.restore();

    }

让钟表动起来,通过Handler实现
在两个参数的构造器 MyView(Context context, AttributeSet attrs)中发送信息

  handler.sendEmptyMessageDelayed(CLOCKFLUSH,1000);

接收消息并处理,在handler中再发送消息形成循环

    public static final int CLOCKFLUSH=0X23;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case CLOCKFLUSH:
                    mCalendar=Calendar.getInstance();//重新获取当前时间
                    invalidate();//刷新
                    handler.sendEmptyMessageDelayed(CLOCKFLUSH,1000);
                    break;
                default:
                    break;
            }
        }
    };

布局中只添加了这个组件

    <com.example.laowang.android0916canvas_.weight.MyView
    android:layout_width="match_parent"
    android:layout_height="match_parent" />

  实现效果(请无视这个按键。。。)
  
这里写图片描述

  全部代码View类

package com.example.laowang.android0916canvas_.weight;

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.view.View;

import java.util.Calendar;

/**
 * Created by Administrator on 2015/9/16.
 */
public class MyView extends View {
    private int mWith;
    private int mHeight;
    private Paint mLinePaint;
    private Paint mLineSecondPaint;
    private Paint mCirclePaint;
    private Paint mCircleText;
    private Calendar mCalendar;
    public static final int CLOCKFLUSH=0X23;
    private Handler handler=new Handler(){
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what){
                case CLOCKFLUSH:
                    mCalendar=Calendar.getInstance();//重新获取当前时间
                    invalidate();//刷新
                    handler.sendEmptyMessageDelayed(CLOCKFLUSH,1000);
                    break;
                default:
                    break;
            }
        }
    };
    public MyView(Context context) {
        super(context);
    }

    public MyView(Context context, AttributeSet attrs) {
        super(context, attrs);
        mLinePaint=new Paint();
        mLinePaint.setColor(Color.BLACK);
        mLinePaint.setStrokeWidth(5);//线宽
        mLinePaint.setAntiAlias(true);//抗锯齿

        mLineSecondPaint=new Paint();
        mLineSecondPaint.setColor(Color.BLACK);
        mLineSecondPaint.setStrokeWidth(2);//线宽
        mLineSecondPaint.setAntiAlias(true);//抗锯齿

        mCirclePaint=new Paint();
        mCirclePaint.setColor(Color.BLACK);
        mCirclePaint.setStrokeWidth(5);//线宽
        mCirclePaint.setStyle(Paint.Style.STROKE);//空心圆
        mCirclePaint.setAntiAlias(true);//抗锯齿

        mCircleText=new Paint();
        mCircleText.setTextSize(30);//字体大小
        mCircleText.setTextAlign(Paint.Align.CENTER);//对齐方式

        handler.sendEmptyMessageDelayed(CLOCKFLUSH,1000);
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        super.onMeasure(widthMeasureSpec, heightMeasureSpec);
        mWith = getDefaultSize(getSuggestedMinimumWidth(), widthMeasureSpec);
        mHeight = getDefaultSize(getSuggestedMinimumHeight(), heightMeasureSpec);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        super.onDraw(canvas);
//      onDraw是由UI主线程自动调用,只需要再此绘制即可
//        canvas.drawLine(0, 0, 222, 222, mLinePaint);
        canvas.drawCircle(mWith / 2, mHeight / 2, 200, mCirclePaint);
        canvas.drawCircle(mWith / 2, mHeight / 2, 2, mCirclePaint);
        for(int i=1;i<=12;i++) {
            canvas.save();//保存当前画布状态
            canvas.rotate(360 / 12 * i, mWith / 2, mHeight / 2);//旋转,先旋转再画(旋转角度,旋转中心点xy左边)
            canvas.drawLine(mWith / 2, mHeight / 2 - 200, mWith / 2, mHeight / 2 - 180, mLinePaint);
            canvas.drawText("" + i, mWith / 2, mHeight / 2 - 150, mCircleText);
            canvas.restore();//恢复到原位置
        }

        mCalendar=Calendar.getInstance();
//        获得时分秒
        int minute=mCalendar.get(Calendar.MINUTE);
        int hour=mCalendar.get(Calendar.HOUR);
        int second=mCalendar.get(Calendar.SECOND);
//        画上分针
        float degree=minute/60f*360;//必须定义成浮点型数据,
        canvas.save();
        canvas.rotate(degree, mWith / 2, mHeight / 2);//将下面line旋转这些角度
        canvas.drawLine(mWith / 2, mHeight / 2 - 120, mWith / 2, mHeight / 2 +20, mLinePaint);
        canvas.restore();
//        画上时针
        float hourDegree=(hour*60+minute)/(12*60f)*360;
        canvas.save();
        canvas.rotate(hourDegree, mWith / 2, mHeight / 2);
        canvas.drawLine(mWith / 2, mHeight / 2 - 90, mWith / 2, mHeight / 2 +20, mLinePaint);
        canvas.restore();
//        画上秒针
        float secondDegree=second/60f*360;//加f的位置要注意- -
        canvas.save();
        canvas.rotate(secondDegree, mWith / 2, mHeight / 2);
        canvas.drawLine(mWith / 2, mHeight / 2 - 140, mWith / 2, mHeight / 2 + 20, mLineSecondPaint);
        canvas.restore();

    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值