Android 自定义View之View的绘制

相关文章:Android自定义View之View的测量


之前讲了自定义View View的测量一部分,很好掌握吧?

但是View的测量只能控制View的大小,如果想定制外观,就要靠View的绘制。


View的绘制是要重写View  的 OnDraw方法

public class MyView extends View{

	public MyView(Context context) {
		super(context);
	}
	
	@Override
	protected void onDraw(Canvas canvas){
		
	}

}

我们再看一下View类中 onDraw的源码

/**
     * Implement this to do your drawing.
     *
     * @param canvas the canvas on which the background will be drawn
     */
    protected void onDraw(Canvas canvas) {
    }
是空的~  也就是什么也没绘制

所以我们上一篇文章测试时候的View,就是一个没有图形的View。

可能有人会说,上一篇文章,最后明明显示是一个矩形!

但是实际上,呢只是因为View的边界包裹起来本身是个矩形,这和View的绘制是两码事

绘制,就是好像,View是一张矩形的纸,我们在这个纸上画画


View的绘制,我们使用Canvas ,Paint ,Path三个类就可以基本完成各种图形了


Canvas:

我直接先把Canvas提供的绘制方法放出来,大家看一下

Canvas的绘制方法
方法签名简要说明
drawLine(float startX, float startY, float stopX, float stopY, Paint paint)绘制一条直线
drawLines(float[] pts, int offset, int count, Paint paint)绘制多条直线
drawCircle(float cx, float cy, float radius, Paint paint)绘制一个圆
drawOval(RectF oval, Paint paint)绘制一个椭圆
drawPath(Path path, Paint paint)根据路径绘制任意形状
drawPoint(float x, float y, Paint paint)绘制一个点
drawPoints(float[] pts, int offset, int count, Paint paint) 绘制多个点
drawRect(float left, float top, float right, float bottom, Paint paint)绘制矩形
drawRoundRect(RectF rect, float rx, float ry, Paint paint)绘制圆角矩形
drawText(String text, int start, int end, Paint paint)绘制字符串
drawTextOnPath(参数太多,表格放不下了,需要自己查吧...)沿着路径绘制字符串
clipRect(float left, float top, float right, float bottom)剪切一个矩形区域
clipRegion(Region region)剪切制定区域
drawArc(参数太多,表格放不下了,需要自己查吧...)绘制弧
drawBitmap(Bitmap bitmap, rect src, Rect dst, Paint paint)绘制从源位图"挖取“的一块
drawBitmap(Bitmap bitmap, float left, float top, Paint paint)绘制位图
  


















上表的各种方法具体使用不一一赘述了,大家看参数和简要说明应该就明白了,实在不懂可以搜索一下,具体用法我可能以后再开一篇总结吧~

我们上表就可以看出,Canvas就是提供给我们绘制基本图形的方法,复杂的图形也就是靠这些组合起来的~

此外,Canvas还提供了坐标变换的方法(Canvas的坐标原点在View的左上角,坐标轴方向遵循Android坐标系)


Canvas坐标变换的方法
方法签名简要说明
rotate(float degrees, float px, float py)旋转变换
scale(float sx, float sy, float px, float py)缩放变换
skew(float sx, float sy)倾斜变换
translate(float dx, float dy)移动坐标原点


我们也可以看出,Canvas的使用,离不开 Paint,下面我们看一下Pait的方法


Paint

Paint 就好像生活中的画笔一样

Paint的常用方法
setARGB(int a, int r, int g, int b)设置颜色
setAlpha(int a)设置透明度
setAntiAlias(boolean aa)设置是否抗锯齿
setColor(int color)设置颜色
setPathEffect(PathEffect effect)设置绘制路径时的路径效果
setShader(Shader shader)设置画笔的填充效果
setShadowLayer(float radius, float dx, float dy, int color)设置阴影
setStrokeWidth(float width)设置画笔的笔尖宽度
setStrokeJoin(Paint.Join join)设置画笔转弯处的连接风格
setStyle(Paint.Style style)设置Pain的填充风格
setTextAlign(Paint.Align align)设置绘制文本时的文字对齐方式
setTextSize(float textSize)设置绘制文本时的文字大小












根据方法的简要说明,很清晰明了吧~

具体使用,自己试一试就更清楚啦~

下面我们直接上手做一个复合图形吧

效果图如下

就是一个常见的钟表盘(你会发现这个钟表盘的数字有点问题,接下来我们来看看实现代码就明白这个问题是怎么回事啦)

import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Paint;
import android.util.AttributeSet;
import android.view.View;

public class Clock extends View{

	public Clock(Context context, AttributeSet attrs) {
		super(context, attrs);
	}

	public Clock(Context context) {
		super(context);
	}
	
	@Override
	protected void onDraw(Canvas canvas){
		
		// 画外圆
		Paint paintCircle = new Paint();
		paintCircle.setStyle(Paint.Style.STROKE);
		//设置抗锯齿,防止缩放变换后图片出现锯齿边缘
		paintCircle.setAntiAlias(true);
		paintCircle.setStrokeWidth(5);
		//getWidth() 和 getHeight()是View自己的方法 获取View的宽和高
		//我们画一个以View中心点为圆心,半径为View宽度一半的圆
		//从这个函数参数的传递,我们也可以看出,Canvas的坐标原点在View左上角
		canvas.drawCircle(this.getWidth()/2, this.getHeight()/2, this.getWidth()/2, paintCircle);
		
		//画刻度的画笔
		Paint paintDegree = new Paint();
		paintDegree.setTextAlign(Paint.Align.CENTER);
		//从0点(12点)开始画刻度
		for(int i = 0; i < 12; i ++){
			//区分特殊点
			if(i == 0 || i == 3 || i == 6 || i == 9){
				//特殊的刻度,线更长,笔尖宽度更大
				paintDegree.setStrokeWidth(5);
				paintDegree.setTextSize(30);
				//大家自己琢磨一下这个线的起点和终点吧
				canvas.drawLine(this.getWidth()/2, 
						this.getHeight()/2 - this.getWidth()/2, 
						this.getWidth()/2, 
						this.getHeight()/2 - this.getWidth()/2 + 60, 
						paintDegree);
				
				String clockTime = null;
				//表盘上一般都把0点显示为12点
				if(i == 0)
					clockTime = String.valueOf(i + 12);
				else
					clockTime = String.valueOf(i);
				canvas.drawText(clockTime, this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2 + 90, paintDegree);
			}else{
				paintDegree.setStrokeWidth(3);
				paintDegree.setTextSize(15);
				canvas.drawLine(this.getWidth()/2, 
						this.getHeight()/2 - this.getWidth()/2, 
						this.getWidth()/2, 
						this.getHeight()/2 - this.getWidth()/2 + 30, 
						paintDegree);
				String clockTime = String.valueOf(i);
				canvas.drawText(clockTime, this.getWidth()/2, this.getHeight()/2 - this.getWidth()/2 + 60, paintDegree);
			}
			//这个地方,我们就用到了旋转坐标系的方法来达到每30度角画一个刻度
			//注意,这个是旋转坐标系!并不是旋转画布,也就是说,单独执行这个方法,你看不到任何效果的!
			canvas.rotate(30, this.getWidth()/2,this.getHeight()/2);
		}
	}
	
	//这里我们没有重写onMeasure
	protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec){
		super.onMeasure(widthMeasureSpec, heightMeasureSpec);
	}
}
代码注释的比较清楚,唯一就是旋转坐标系这个我想还是再强调一下。

因为当时自己开始以为是旋转画布,调用后,并没有变化。

而就是因为坐标系旋转了,所以我们呢个6点,就倒过来了,像9一样。


最后在xml文件中引用这个布局就可以了

<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.androidcanvas.MainActivity" >

   	<com.example.androidcanvas.Clock 
   	    android:layout_width="wrap_content"
   	    android:layout_height="wrap_content"/>

</RelativeLayout>

项目源码AndroidOnDraw




评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值