您的位置:首页 > 移动开发 > Android开发

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

2015-09-16 21:00 567 查看

自定义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步:

新建类继承View,重写俩个方法onDraw和onMeasure,继承两个构造方法

绘制钟表

使钟表动起来

将组件添加到布局中

绘制钟表

在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();

}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: