首先,介绍的是Canvas的基本方法
方法签名 | 简要说明 |
---|---|
drawArc(RectF oval, float startAngle, float sweepAngle, boolean useCenter, Paint paint) | 绘制弧 |
drawBitmap(Bitmap bitmap, Rect src, Rect dst,Paint paint) | 在指定点绘制从源位图中"挖取"的一块 |
drawBitmap(Bitmap bitmap, float left, flost top, Paint paint) | 在指定点绘制位图 |
drawCircle(float cx, float cy, float radius, Paint paint) | 在指定点绘制一个圆形 |
drawLine(float startX, float startY, float stopX, float stopY, Paint paint) | 绘制一条线 |
drawLines(float[] pts, int offset, int count, Paint paint) | 绘制多条线 |
drawOval(RectF oval, Paint paint) | 绘制椭圆 |
drawPath(Path path, Paint paint) | 沿着指定Path绘制任意形状 |
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(String text, Path path, float hOffset, float vOffset, Paint paint) | 沿着路径绘制字符串 |
clipRect(float left, float top, float right, float bottom) | 剪切一个矩形区域 |
clipRegion(Region region) | 剪切指定区域 |
>rotate(float degress, 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距离(dx为负数即向左移动);向下移动dy距离(dy为负数即向上移动).
Paint代表了Canvas上的画笔,因此Paint类主要用于设置绘制风格,包括画笔颜色.画笔笔触粗细,填充风格等.
Paint提供了如下所示的方法:
方法签名 | 简要说明 |
---|---|
setARGB(int a, int r, int g, int b)/setColor(int color) | 设置颜色 |
setAlpha(int a ) | 设置透明度 |
setAntiAlias(boolean aa) | 设置是否抗锯齿 |
setColor(int color) | 设置颜色 |
setPahtEffect(PathEffect cffect) | 设置绘制路径时的路径效果 |
setShader(Shader shader) | 设置画笔的填充效果 |
setShadowLayer(float radius, float dx, float dy, int color) | 设置阴影 |
setStrokeWidth(float width) | 设置画笔的笔触宽度 |
setStrokeJoin(Paint.Join join) | 设置画笔转弯处的连接风格 |
setStyle(Paint.Style style) | 设置Paint的填充风格 |
setTextAlign(Paint.Align align) | 设置绘制文本时的文字的对齐方式 |
setTextSize(float textSize) | 设置绘制文本时的文字大小 |
下面的MyView重写了onDraw(Canvas)方法,绘制了基本的几何图形.
- package com.example.canvastest.view;
- import android.annotation.SuppressLint;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.LinearGradient;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.RectF;
- import android.graphics.Shader;
- import android.util.AttributeSet;
- import android.view.View;
- public class MyView extends View {
- public MyView(Context context, AttributeSet attrs, int defStyleAttr,
- int defStyleRes) {
- super(context, attrs, defStyleAttr, defStyleRes);
- }
- public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- }
- public MyView(Context context, AttributeSet attrs) {
- super(context, attrs);
- }
- public MyView(Context context) {
- super(context);
- }
- /**
- * 重写该方法,进行绘图
- */
- @SuppressLint("DrawAllocation")
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- // 把整张画布绘制成白色
- canvas.drawColor(Color.WHITE);
- // 创建画笔
- Paint paint = new Paint();
- // 去锯齿
- paint.setAntiAlias(true);
- // 设置画笔颜色
- paint.setColor(Color.BLUE);
- // 设置画笔样式
- paint.setStyle(Paint.Style.STROKE);
- // 设置画笔的宽度
- paint.setStrokeWidth(3);
- // 绘制圆形
- canvas.drawCircle(40, 40, 30, paint);
- // 绘制正方形
- canvas.drawRect(10, 80, 70, 140, paint);
- // 绘制矩形
- canvas.drawRect(10, 150, 70, 190, paint);
- //
- RectF rectF1 = new RectF(10, 200, 70, 230);
- // 绘制圆角矩形
- canvas.drawRoundRect(rectF1, 15, 15, paint);
- //
- RectF rectF2 = new RectF(10, 240, 70, 270);
- // 绘制椭圆
- canvas.drawOval(rectF2, paint);
- // 定义一个Path对象,封闭成一个三角形
- Path path1 = new Path();
- // 设置起点
- path1.moveTo(10, 340);
- // 线路1
- path1.lineTo(70, 340);
- // 线路2
- path1.lineTo(40, 290);
- path1.close();
- // 根据Path进行绘制,绘制三角形
- canvas.drawPath(path1, paint);
- // 定义一个Path对象,绘制一个五角形
- Path path2 = new Path();
- path2.moveTo(26, 360);
- path2.lineTo(54, 360);
- path2.lineTo(70, 392);
- path2.lineTo(40, 420);
- path2.lineTo(10, 392);
- path2.close();
- // 根据Path进行绘制,绘制三角形
- canvas.drawPath(path2, paint);
- // -------------设置填充风格后绘制---------------------------
- paint.setStyle(Paint.Style.FILL);
- paint.setColor(Color.RED);
- // 绘制圆形
- canvas.drawCircle(120, 40, 30, paint);
- // 绘制正方形
- canvas.drawRect(90, 80, 150, 140, paint);
- // 绘制矩形
- canvas.drawRect(90, 200, 150, 190, paint);
- // 绘制圆角矩形
- RectF rectF3 = new RectF(90, 200, 150, 230);
- canvas.drawRoundRect(rectF3, 15, 15, paint);
- // 绘制椭圆
- RectF rectF4 = new RectF(90, 240, 150, 270);
- canvas.drawOval(rectF4, paint);
- // 绘制三角形
- Path path3 = new Path();
- path3.moveTo(90, 340);
- path3.lineTo(150, 340);
- path3.lineTo(120, 290);
- path3.close();
- canvas.drawPath(path3, paint);
- // 绘制五角形
- Path path4 = new Path();
- path4.moveTo(106, 360);
- path4.lineTo(134, 360);
- path4.lineTo(150, 392);
- path4.lineTo(120, 420);
- path4.lineTo(90, 392);
- path4.close();
- canvas.drawPath(path4, paint);
- // -------------设置渐变器后绘制------------------
- // 为paint设置渐变器
- Shader mShader = new LinearGradient(0, 0, 40, 60, new int[] {
- Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW }, null,
- Shader.TileMode.REPEAT);
- paint.setShader(mShader);
- //设置阴影
- paint.setShadowLayer(45, 10, 10, Color.GRAY);
- // 绘制圆形
- canvas.drawCircle(200, 40, 30, paint);
- // 绘制正方形
- canvas.drawRect(170, 80, 230, 140, paint);
- // 绘制矩形
- canvas.drawRect(170, 150, 230, 190, paint);
- // 绘制圆角矩形
- RectF rectF5 = new RectF(170, 200, 230, 230);
- canvas.drawRoundRect(rectF5, 15, 15, paint);
- // 绘制椭圆
- RectF rectF6 = new RectF(170, 240, 230, 270);
- canvas.drawOval(rectF6, paint);
- // 绘制三角形
- Path path6 = new Path();
- path6.moveTo(170, 340);
- path6.lineTo(230, 340);
- path6.lineTo(200, 290);
- path6.close();
- canvas.drawPath(path6, paint);
- // 绘制五角形
- Path path5 = new Path();
- path5.moveTo(186, 360);
- path5.lineTo(214, 360);
- path5.lineTo(230, 392);
- path5.lineTo(200, 420);
- path5.lineTo(170, 392);
- path5.close();
- canvas.drawPath(path5, paint);
- //----------设置字符大小后绘制-----------------
- paint.setTextSize(24);
- paint.setShader(null);
- //绘制7个字符串
- canvas.drawText("圆形", 240, 50, paint);
- canvas.drawText("正方形", 240, 120, paint);
- canvas.drawText("矩形", 240, 175, paint);
- canvas.drawText("圆角矩形", 240, 220, paint);
- canvas.drawText("椭圆形", 240, 260, paint);
- canvas.drawText("三角形", 240, 325, paint);
- canvas.drawText("五角形", 240, 390, paint);
- }
- }
package com.example.canvastest.view;
import android.annotation.SuppressLint;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.LinearGradient;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.RectF;
import android.graphics.Shader;
import android.util.AttributeSet;
import android.view.View;
public class MyView extends View {
public MyView(Context context, AttributeSet attrs, int defStyleAttr,
int defStyleRes) {
super(context, attrs, defStyleAttr, defStyleRes);
}
public MyView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
public MyView(Context context, AttributeSet attrs) {
super(context, attrs);
}
public MyView(Context context) {
super(context);
}
/**
* 重写该方法,进行绘图
*/
@SuppressLint("DrawAllocation")
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 把整张画布绘制成白色
canvas.drawColor(Color.WHITE);
// 创建画笔
Paint paint = new Paint();
// 去锯齿
paint.setAntiAlias(true);
// 设置画笔颜色
paint.setColor(Color.BLUE);
// 设置画笔样式
paint.setStyle(Paint.Style.STROKE);
// 设置画笔的宽度
paint.setStrokeWidth(3);
// 绘制圆形
canvas.drawCircle(40, 40, 30, paint);
// 绘制正方形
canvas.drawRect(10, 80, 70, 140, paint);
// 绘制矩形
canvas.drawRect(10, 150, 70, 190, paint);
//
RectF rectF1 = new RectF(10, 200, 70, 230);
// 绘制圆角矩形
canvas.drawRoundRect(rectF1, 15, 15, paint);
//
RectF rectF2 = new RectF(10, 240, 70, 270);
// 绘制椭圆
canvas.drawOval(rectF2, paint);
// 定义一个Path对象,封闭成一个三角形
Path path1 = new Path();
// 设置起点
path1.moveTo(10, 340);
// 线路1
path1.lineTo(70, 340);
// 线路2
path1.lineTo(40, 290);
path1.close();
// 根据Path进行绘制,绘制三角形
canvas.drawPath(path1, paint);
// 定义一个Path对象,绘制一个五角形
Path path2 = new Path();
path2.moveTo(26, 360);
path2.lineTo(54, 360);
path2.lineTo(70, 392);
path2.lineTo(40, 420);
path2.lineTo(10, 392);
path2.close();
// 根据Path进行绘制,绘制三角形
canvas.drawPath(path2, paint);
// -------------设置填充风格后绘制---------------------------
paint.setStyle(Paint.Style.FILL);
paint.setColor(Color.RED);
// 绘制圆形
canvas.drawCircle(120, 40, 30, paint);
// 绘制正方形
canvas.drawRect(90, 80, 150, 140, paint);
// 绘制矩形
canvas.drawRect(90, 200, 150, 190, paint);
// 绘制圆角矩形
RectF rectF3 = new RectF(90, 200, 150, 230);
canvas.drawRoundRect(rectF3, 15, 15, paint);
// 绘制椭圆
RectF rectF4 = new RectF(90, 240, 150, 270);
canvas.drawOval(rectF4, paint);
// 绘制三角形
Path path3 = new Path();
path3.moveTo(90, 340);
path3.lineTo(150, 340);
path3.lineTo(120, 290);
path3.close();
canvas.drawPath(path3, paint);
// 绘制五角形
Path path4 = new Path();
path4.moveTo(106, 360);
path4.lineTo(134, 360);
path4.lineTo(150, 392);
path4.lineTo(120, 420);
path4.lineTo(90, 392);
path4.close();
canvas.drawPath(path4, paint);
// -------------设置渐变器后绘制------------------
// 为paint设置渐变器
Shader mShader = new LinearGradient(0, 0, 40, 60, new int[] {
Color.RED, Color.GREEN, Color.BLUE, Color.YELLOW }, null,
Shader.TileMode.REPEAT);
paint.setShader(mShader);
//设置阴影
paint.setShadowLayer(45, 10, 10, Color.GRAY);
// 绘制圆形
canvas.drawCircle(200, 40, 30, paint);
// 绘制正方形
canvas.drawRect(170, 80, 230, 140, paint);
// 绘制矩形
canvas.drawRect(170, 150, 230, 190, paint);
// 绘制圆角矩形
RectF rectF5 = new RectF(170, 200, 230, 230);
canvas.drawRoundRect(rectF5, 15, 15, paint);
// 绘制椭圆
RectF rectF6 = new RectF(170, 240, 230, 270);
canvas.drawOval(rectF6, paint);
// 绘制三角形
Path path6 = new Path();
path6.moveTo(170, 340);
path6.lineTo(230, 340);
path6.lineTo(200, 290);
path6.close();
canvas.drawPath(path6, paint);
// 绘制五角形
Path path5 = new Path();
path5.moveTo(186, 360);
path5.lineTo(214, 360);
path5.lineTo(230, 392);
path5.lineTo(200, 420);
path5.lineTo(170, 392);
path5.close();
canvas.drawPath(path5, paint);
//----------设置字符大小后绘制-----------------
paint.setTextSize(24);
paint.setShader(null);
//绘制7个字符串
canvas.drawText("圆形", 240, 50, paint);
canvas.drawText("正方形", 240, 120, paint);
canvas.drawText("矩形", 240, 175, paint);
canvas.drawText("圆角矩形", 240, 220, paint);
canvas.drawText("椭圆形", 240, 260, paint);
canvas.drawText("三角形", 240, 325, paint);
canvas.drawText("五角形", 240, 390, paint);
}
}
Path类: Android提供的Path是一个非常有用的类,它可以预先在View上将N个点连成一条"路径",然后调用Canvas的drawPath(Path path, Paint paint)即可沿着路径绘制图形.实际上Android还为路径绘制提供了PathEffect来定义绘制效果,PathEffect包含了如下子类(每个子类代表一种绘制效果):
Corner PathEffect
Discrete PathEffect
Dash PathEffect
Path Dash PathEffect
Compose PathEffect
Sum PathEffect
这些绘制效果使用语言来表述总显得有些空洞,下面通过一个程序来了解一下绘制效果.接下来的程序绘制7条路径,分别示范了不适用效果和使用上面6种效果的示意.
- package com.example.canvastest.view;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.ComposePathEffect;
- import android.graphics.CornerPathEffect;
- import android.graphics.DashPathEffect;
- import android.graphics.DiscretePathEffect;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.graphics.PathDashPathEffect;
- import android.graphics.PathEffect;
- import android.graphics.SumPathEffect;
- import android.util.AttributeSet;
- import android.view.View;
- /**
- * 使用Path绘制路径
- * @author Administrator
- *
- */
- public class MyPathView extends View {
- private float phase;
- private PathEffect[] pathEffects = new PathEffect[7];
- private int[] colors;
- private Path path;
- private Paint paint;
- public MyPathView(Context context) {
- this(context, null);
- }
- public MyPathView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyPathView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- paint = new Paint();
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(4);
- // 创建并初始化Path
- path = new Path();
- path.moveTo(0, 0);
- for (int i = 0; i < 15; i++) {
- // 生成15个点,随机生成他们的Y坐标,并将它们练成一条Path
- path.lineTo(i * 20, (float) Math.random() * 60);
- }
- // 初始化7个颜色
- colors = new int[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN,
- Color.MAGENTA, Color.RED, Color.YELLOW };
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- ///将背景填充为白色
- canvas.drawColor(Color.WHITE);
- //-------下面开始初始化7种路径效果--------
- //不使用路径效果
- pathEffects[0] = null;
- //使用CornerPathEffect路径效果//角路径效应
- pathEffects[1] = new CornerPathEffect(10);
- //使用DiscretePathEffect路径效果//离散路径效应
- pathEffects[2] = new DiscretePathEffect(3.0f, 5.0f);
- //DashPathEffect//短跑路径效应
- pathEffects[3] = new DashPathEffect(new float[]{20, 10, 5, 10}, phase);
- //PathDashPathEffect//短跑的路径路径效应
- Path p = new Path();
- p.addRect(0, 0, 8, 8, Path.Direction.CCW);
- pathEffects[4] = new PathDashPathEffect(p, 12, phase, PathDashPathEffect.Style.ROTATE);
- //ComposePathEffect//组成的路径效应
- pathEffects[5] = new ComposePathEffect(pathEffects[2], pathEffects[4]);
- //SumPathEffect//总和路径效应
- pathEffects[6] = new SumPathEffect(pathEffects[4], pathEffects[3]);
- //将画布移动到(8,8)出绘制
- canvas.translate(8, 8);
- //依次使用7种不同路径效果,7种颜色来绘制路径
- for (int i = 0; i < pathEffects.length; i++) {
- paint.setPathEffect(pathEffects[i]);
- paint.setColor(colors[i]);
- canvas.drawPath(path, paint);
- canvas.translate(0, 60);
- }
- //改变phase值,形成动画效果
- phase += 1;
- invalidate();
- }
- }
package com.example.canvastest.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.ComposePathEffect;
import android.graphics.CornerPathEffect;
import android.graphics.DashPathEffect;
import android.graphics.DiscretePathEffect;
import android.graphics.Paint;
import android.graphics.Path;
import android.graphics.PathDashPathEffect;
import android.graphics.PathEffect;
import android.graphics.SumPathEffect;
import android.util.AttributeSet;
import android.view.View;
/**
* 使用Path绘制路径
* @author Administrator
*
*/
public class MyPathView extends View {
private float phase;
private PathEffect[] pathEffects = new PathEffect[7];
private int[] colors;
private Path path;
private Paint paint;
public MyPathView(Context context) {
this(context, null);
}
public MyPathView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyPathView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paint = new Paint();
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(4);
// 创建并初始化Path
path = new Path();
path.moveTo(0, 0);
for (int i = 0; i < 15; i++) {
// 生成15个点,随机生成他们的Y坐标,并将它们练成一条Path
path.lineTo(i * 20, (float) Math.random() * 60);
}
// 初始化7个颜色
colors = new int[] { Color.BLACK, Color.BLUE, Color.CYAN, Color.GREEN,
Color.MAGENTA, Color.RED, Color.YELLOW };
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
///将背景填充为白色
canvas.drawColor(Color.WHITE);
//-------下面开始初始化7种路径效果--------
//不使用路径效果
pathEffects[0] = null;
//使用CornerPathEffect路径效果//角路径效应
pathEffects[1] = new CornerPathEffect(10);
//使用DiscretePathEffect路径效果//离散路径效应
pathEffects[2] = new DiscretePathEffect(3.0f, 5.0f);
//DashPathEffect//短跑路径效应
pathEffects[3] = new DashPathEffect(new float[]{20, 10, 5, 10}, phase);
//PathDashPathEffect//短跑的路径路径效应
Path p = new Path();
p.addRect(0, 0, 8, 8, Path.Direction.CCW);
pathEffects[4] = new PathDashPathEffect(p, 12, phase, PathDashPathEffect.Style.ROTATE);
//ComposePathEffect//组成的路径效应
pathEffects[5] = new ComposePathEffect(pathEffects[2], pathEffects[4]);
//SumPathEffect//总和路径效应
pathEffects[6] = new SumPathEffect(pathEffects[4], pathEffects[3]);
//将画布移动到(8,8)出绘制
canvas.translate(8, 8);
//依次使用7种不同路径效果,7种颜色来绘制路径
for (int i = 0; i < pathEffects.length; i++) {
paint.setPathEffect(pathEffects[i]);
paint.setColor(colors[i]);
canvas.drawPath(path, paint);
canvas.translate(0, 60);
}
//改变phase值,形成动画效果
phase += 1;
invalidate();
}
}
除此之外,Android的Canvas还提供了一个DrawTextOnPath(String text,Path path, float hOffset, float vOffset, Paint paint)方法,该方法可以沿着Path绘制文本,其中hOffset参数指定水平偏移,vOffset参数指定垂直偏移.
- package com.example.canvastest.view;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Paint.Align;
- import android.graphics.Path;
- import android.graphics.RectF;
- import android.util.AttributeSet;
- import android.view.View;
- /**
- * 使用drawTextOnPaht,沿着Path(路径)绘制文本
- *
- * @author Administrator
- */
- public class MyPathTextView extends View {
- final String DRAW_STR = "绘制文本";
- private Path[] paths = new Path[3];
- Paint paint;
- public MyPathTextView(Context context) {
- this(context, null);
- }
- public MyPathTextView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public MyPathTextView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- paths[0] = new Path();
- paths[0].moveTo(0, 0);
- for (int i = 0; i < 7; i++) {
- // 生成7个点,随机生成它们的y坐标,并将它们连成一条path
- paths[0].lineTo(1 * 30, (float) Math.random() * 30);
- }
- paths[1] = new Path();
- RectF rectf = new RectF(0, 0, 200, 120);
- paths[1].addOval(rectf, Path.Direction.CCW);
- paths[2] = new Path();
- paths[2].addArc(rectf, 60, 180);
- // 初始化画笔
- paint = new Paint();
- paint.setAntiAlias(true);
- paint.setColor(Color.CYAN);
- paint.setStrokeWidth(1);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- canvas.drawColor(Color.WHITE);
- canvas.translate(40, 40);
- // 设置从右边开始绘制(右对齐)
- paint.setTextAlign(Paint.Align.RIGHT);
- paint.setTextSize(20);
- // 绘制路径
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawPath(paths[0], paint);
- // 沿着路径绘制一段文本
- paint.setStyle(Paint.Style.FILL);
- canvas.drawTextOnPath(DRAW_STR, paths[0], -8, 20, paint);
- // 对canvas进行坐标变换:画布下移60
- canvas.translate(0, 60);
- // 绘制路径
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawPath(paths[1], paint);
- // 沿着路径绘制一段文本
- paint.setStyle(Paint.Style.FILL);
- canvas.drawTextOnPath(DRAW_STR, paths[1], -20, 20, paint);
- // 对canvas进行坐标变换:画布下移120
- canvas.translate(0, 120);
- // 绘制路径
- paint.setStyle(Paint.Style.STROKE);
- canvas.drawPath(paths[2], paint);
- // 沿着路径绘制一段文本
- paint.setStyle(Paint.Style.FILL);
- canvas.drawTextOnPath(DRAW_STR, paths[2], -10, 20, paint);
- }
- }
package com.example.canvastest.view;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Paint.Align;
import android.graphics.Path;
import android.graphics.RectF;
import android.util.AttributeSet;
import android.view.View;
/**
* 使用drawTextOnPaht,沿着Path(路径)绘制文本
*
* @author Administrator
*/
public class MyPathTextView extends View {
final String DRAW_STR = "绘制文本";
private Path[] paths = new Path[3];
Paint paint;
public MyPathTextView(Context context) {
this(context, null);
}
public MyPathTextView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public MyPathTextView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
paths[0] = new Path();
paths[0].moveTo(0, 0);
for (int i = 0; i < 7; i++) {
// 生成7个点,随机生成它们的y坐标,并将它们连成一条path
paths[0].lineTo(1 * 30, (float) Math.random() * 30);
}
paths[1] = new Path();
RectF rectf = new RectF(0, 0, 200, 120);
paths[1].addOval(rectf, Path.Direction.CCW);
paths[2] = new Path();
paths[2].addArc(rectf, 60, 180);
// 初始化画笔
paint = new Paint();
paint.setAntiAlias(true);
paint.setColor(Color.CYAN);
paint.setStrokeWidth(1);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawColor(Color.WHITE);
canvas.translate(40, 40);
// 设置从右边开始绘制(右对齐)
paint.setTextAlign(Paint.Align.RIGHT);
paint.setTextSize(20);
// 绘制路径
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(paths[0], paint);
// 沿着路径绘制一段文本
paint.setStyle(Paint.Style.FILL);
canvas.drawTextOnPath(DRAW_STR, paths[0], -8, 20, paint);
// 对canvas进行坐标变换:画布下移60
canvas.translate(0, 60);
// 绘制路径
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(paths[1], paint);
// 沿着路径绘制一段文本
paint.setStyle(Paint.Style.FILL);
canvas.drawTextOnPath(DRAW_STR, paths[1], -20, 20, paint);
// 对canvas进行坐标变换:画布下移120
canvas.translate(0, 120);
// 绘制路径
paint.setStyle(Paint.Style.STROKE);
canvas.drawPath(paths[2], paint);
// 沿着路径绘制一段文本
paint.setStyle(Paint.Style.FILL);
canvas.drawTextOnPath(DRAW_STR, paths[2], -10, 20, paint);
}
}
下面是一个使用双缓冲机制实现的画面板例子
- package com.example.canvastest.view;
- import android.content.Context;
- import android.graphics.Bitmap;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.graphics.Path;
- import android.util.AttributeSet;
- import android.view.MotionEvent;
- import android.view.View;
- public class DrawView extends View {
- float preX;
- float preY;
- private Paint paint = null;
- final int VIEW_WIDTH = 320;
- final int VIEW_HEIGHT = 480;
- // 定义一个内存中的图片,该图片将作为缓冲区
- Bitmap cacheBitmap = null;
- // 定义cachebitmap上的canvas对象
- Canvas cacheCanvas = null;
- Path path = null;
- public DrawView(Context context) {
- this(context, null);
- }
- public DrawView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- // 设置画笔的颜色
- paint = new Paint(Paint.DITHER_FLAG);
- paint.setColor(Color.RED);
- // 设置画笔的风格
- paint.setStyle(Paint.Style.STROKE);
- paint.setStrokeWidth(1);
- // 抗锯齿
- paint.setAntiAlias(true);
- paint.setDither(true);
- // 创建一个与该View相同大小的缓冲区
- cacheBitmap = Bitmap.createBitmap(VIEW_WIDTH, VIEW_HEIGHT,
- Bitmap.Config.ARGB_8888);
- // 设置cacheCanvas将会绘制到内存中的cacheBitmap上
- cacheCanvas = new Canvas();
- path = new Path();
- cacheCanvas.setBitmap(cacheBitmap);
- }
- @Override
- public boolean onTouchEvent(MotionEvent event) {
- float x = event.getX();
- float y = event.getY();
- switch (event.getAction()) {
- case MotionEvent.ACTION_DOWN:
- path.moveTo(x, y);
- preX = x;
- preY = x;
- break;
- case MotionEvent.ACTION_MOVE:
- path.quadTo(preX, preY, x, y);
- preX = x;
- preY = y;
- break;
- case MotionEvent.ACTION_UP:
- cacheCanvas.drawPath(path, paint);
- path.reset();
- break;
- }
- invalidate();
- // 返回true表明处理方法已经处理该事件
- return true;
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- Paint paint = new Paint();
- // 将该bitmap绘制到该View组件上
- canvas.drawBitmap(cacheBitmap, 0, 0, paint);
- // 沿着path绘制
- canvas.drawPath(path, paint);
- }
- }
package com.example.canvastest.view;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View;
public class DrawView extends View {
float preX;
float preY;
private Paint paint = null;
final int VIEW_WIDTH = 320;
final int VIEW_HEIGHT = 480;
// 定义一个内存中的图片,该图片将作为缓冲区
Bitmap cacheBitmap = null;
// 定义cachebitmap上的canvas对象
Canvas cacheCanvas = null;
Path path = null;
public DrawView(Context context) {
this(context, null);
}
public DrawView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public DrawView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 设置画笔的颜色
paint = new Paint(Paint.DITHER_FLAG);
paint.setColor(Color.RED);
// 设置画笔的风格
paint.setStyle(Paint.Style.STROKE);
paint.setStrokeWidth(1);
// 抗锯齿
paint.setAntiAlias(true);
paint.setDither(true);
// 创建一个与该View相同大小的缓冲区
cacheBitmap = Bitmap.createBitmap(VIEW_WIDTH, VIEW_HEIGHT,
Bitmap.Config.ARGB_8888);
// 设置cacheCanvas将会绘制到内存中的cacheBitmap上
cacheCanvas = new Canvas();
path = new Path();
cacheCanvas.setBitmap(cacheBitmap);
}
@Override
public boolean onTouchEvent(MotionEvent event) {
float x = event.getX();
float y = event.getY();
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
path.moveTo(x, y);
preX = x;
preY = x;
break;
case MotionEvent.ACTION_MOVE:
path.quadTo(preX, preY, x, y);
preX = x;
preY = y;
break;
case MotionEvent.ACTION_UP:
cacheCanvas.drawPath(path, paint);
path.reset();
break;
}
invalidate();
// 返回true表明处理方法已经处理该事件
return true;
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
Paint paint = new Paint();
// 将该bitmap绘制到该View组件上
canvas.drawBitmap(cacheBitmap, 0, 0, paint);
// 沿着path绘制
canvas.drawPath(path, paint);
}
}
一个弹球游戏例子
- package com.example.canvastest;
- import java.util.Random;
- import java.util.Timer;
- import java.util.TimerTask;
- import android.app.Activity;
- import android.content.Context;
- import android.graphics.Canvas;
- import android.graphics.Color;
- import android.graphics.Paint;
- import android.os.Bundle;
- import android.os.Handler;
- import android.util.AttributeSet;
- import android.util.DisplayMetrics;
- import android.view.Display;
- import android.view.KeyEvent;
- import android.view.View;
- import android.view.View.OnKeyListener;
- import android.view.Window;
- import android.view.WindowManager;
- public class PinBallActivity extends Activity {
- /** 桌面的宽度 */
- private int tableWidth;
- /** 桌面的高度 */
- private int tableHeight;
- /** 随机数生成器 **/
- private Random random = new Random();
- /** 球拍的垂直位置 */
- private int racketY;
- /** 球拍的水平位置 */
- private int racketX = random.nextInt(200);
- /** 球拍的宽度 */
- private final int RACKET_WIDTH = 70;
- /** 球拍的高度 */
- private final int RACKET_HEIGHT = 20;
- /** 小球的大小 */
- private int BALL_SIZE = 12;
- /** 小球的X坐标 */
- private int ballX = random.nextInt(200) + 20;
- /** 小球的Y坐标 */
- private int ballY = random.nextInt(10) + 20;
- /**返回一个-0.5~0.5的比率,用于控制小球的运行方向*/
- private double xyRate = random.nextDouble()- 0.5;
- /**小球的纵向运行速度*/
- private int ySpeed = 10;
- /**小球的横向运行速度*/
- private int xSpeed = (int) (ySpeed * xyRate * 2);
- /*** 游戏是否结束的游标 */
- private boolean isLose = false;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- // 去掉窗口标题
- requestWindowFeature(Window.FEATURE_NO_TITLE);
- // 全屏显示
- getWindow().setFlags(WindowManager.LayoutParams.MATCH_PARENT,
- WindowManager.LayoutParams.MATCH_PARENT);
- // 创建FameView组件
- final GameView gameView = new GameView(this);
- setContentView(gameView);
- // 获取窗口管理器
- WindowManager manager = getWindowManager();
- // 获取密度
- Display display = manager.getDefaultDisplay();
- DisplayMetrics displayMetrics = new DisplayMetrics();
- display.getMetrics(displayMetrics);
- // 获得屏幕的宽和高
- tableWidth = displayMetrics.widthPixels;
- tableHeight = displayMetrics.heightPixels;
- // 初始化球拍的垂直位置
- racketY = tableHeight - 80;
- final Handler handler = new Handler() {
- public void handleMessage(android.os.Message msg) {
- if (msg.what == 0x123) {
- gameView.invalidate();
- }
- };
- };
- gameView.setOnKeyListener(new OnKeyListener() {
- @Override
- public boolean onKey(View v, int keyCode, KeyEvent event) {
- // 获取由那个键触发的事件
- switch (event.getAction()) {
- // 控制挡板左移
- case KeyEvent.KEYCODE_A:
- if (racketX > 0)
- racketX -= 10;
- break;
- // 控制挡板右移
- case KeyEvent.KEYCODE_D:
- if (racketX < tableWidth - tableWidth)
- racketX += 10;
- break;
- }
- // 通知GameView重绘
- gameView.invalidate();
- return true;
- }
- });
- final Timer timer = new Timer();
- timer.schedule(new TimerTask() {
- @Override
- public void run() {
- //如果小球碰到左边边框
- if(ballX <= 0 || ballX >= tableWidth - BALL_SIZE){
- xSpeed = -xSpeed;
- }
- //如果小球高度超出了球拍的位置,且横向不在球拍的范围之内,游戏结束
- if(ballY >= racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)){
- timer.cancel();
- //设置游戏是否结束的旗标为true
- isLose = true;
- }
- //如果小球位于球拍之内,且到达球拍位置,小球反弹
- else if(ballY <= 0 || (ballY >= racketY - BALL_SIZE && ballX >racketX && ballX <= racketX + RACKET_WIDTH)){
- ySpeed = -ySpeed;
- }
- //小球的坐标增加
- ballX += xSpeed;
- ballY += ySpeed;
- //发送消息,通知系统重绘组件
- handler.sendEmptyMessage(0x123);
- }
- }, 0, 100);
- }
- class GameView extends View {
- Paint paint = new Paint();
- public GameView(Context context) {
- this(context, null);
- }
- public GameView(Context context, AttributeSet attrs) {
- this(context, attrs, 0);
- }
- public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
- super(context, attrs, defStyleAttr);
- // 接收焦点
- setFocusable(true);
- }
- @Override
- protected void onDraw(Canvas canvas) {
- super.onDraw(canvas);
- // 设置样式
- paint.setStyle(Paint.Style.FILL);
- // 抗锯齿
- paint.setAntiAlias(true);
- // 如果游戏已经结束
- if (isLose) {
- // 颜色
- paint.setColor(Color.RED);
- ;
- // 字体大小
- paint.setTextSize(40);
- canvas.drawText("游戏结束", 50, 200, paint);
- }
- // 如果游戏还没有结束
- else {
- // 设置颜色,绘制小球
- paint.setColor(Color.rgb(240, 240, 80));
- canvas.drawCircle(ballX, ballY, BALL_SIZE, paint);
- // 设置颜色,绘制球拍
- paint.setColor(Color.rgb(80, 80, 200));
- canvas.drawRect(racketX, racketY, racketX + RACKET_WIDTH,
- racketY + RACKET_HEIGHT, paint);
- }
- }
- }
- }
package com.example.canvastest;
import java.util.Random;
import java.util.Timer;
import java.util.TimerTask;
import android.app.Activity;
import android.content.Context;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Bundle;
import android.os.Handler;
import android.util.AttributeSet;
import android.util.DisplayMetrics;
import android.view.Display;
import android.view.KeyEvent;
import android.view.View;
import android.view.View.OnKeyListener;
import android.view.Window;
import android.view.WindowManager;
public class PinBallActivity extends Activity {
/** 桌面的宽度 */
private int tableWidth;
/** 桌面的高度 */
private int tableHeight;
/** 随机数生成器 **/
private Random random = new Random();
/** 球拍的垂直位置 */
private int racketY;
/** 球拍的水平位置 */
private int racketX = random.nextInt(200);
/** 球拍的宽度 */
private final int RACKET_WIDTH = 70;
/** 球拍的高度 */
private final int RACKET_HEIGHT = 20;
/** 小球的大小 */
private int BALL_SIZE = 12;
/** 小球的X坐标 */
private int ballX = random.nextInt(200) + 20;
/** 小球的Y坐标 */
private int ballY = random.nextInt(10) + 20;
/**返回一个-0.5~0.5的比率,用于控制小球的运行方向*/
private double xyRate = random.nextDouble()- 0.5;
/**小球的纵向运行速度*/
private int ySpeed = 10;
/**小球的横向运行速度*/
private int xSpeed = (int) (ySpeed * xyRate * 2);
/*** 游戏是否结束的游标 */
private boolean isLose = false;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
// 去掉窗口标题
requestWindowFeature(Window.FEATURE_NO_TITLE);
// 全屏显示
getWindow().setFlags(WindowManager.LayoutParams.MATCH_PARENT,
WindowManager.LayoutParams.MATCH_PARENT);
// 创建FameView组件
final GameView gameView = new GameView(this);
setContentView(gameView);
// 获取窗口管理器
WindowManager manager = getWindowManager();
// 获取密度
Display display = manager.getDefaultDisplay();
DisplayMetrics displayMetrics = new DisplayMetrics();
display.getMetrics(displayMetrics);
// 获得屏幕的宽和高
tableWidth = displayMetrics.widthPixels;
tableHeight = displayMetrics.heightPixels;
// 初始化球拍的垂直位置
racketY = tableHeight - 80;
final Handler handler = new Handler() {
public void handleMessage(android.os.Message msg) {
if (msg.what == 0x123) {
gameView.invalidate();
}
};
};
gameView.setOnKeyListener(new OnKeyListener() {
@Override
public boolean onKey(View v, int keyCode, KeyEvent event) {
// 获取由那个键触发的事件
switch (event.getAction()) {
// 控制挡板左移
case KeyEvent.KEYCODE_A:
if (racketX > 0)
racketX -= 10;
break;
// 控制挡板右移
case KeyEvent.KEYCODE_D:
if (racketX < tableWidth - tableWidth)
racketX += 10;
break;
}
// 通知GameView重绘
gameView.invalidate();
return true;
}
});
final Timer timer = new Timer();
timer.schedule(new TimerTask() {
@Override
public void run() {
//如果小球碰到左边边框
if(ballX <= 0 || ballX >= tableWidth - BALL_SIZE){
xSpeed = -xSpeed;
}
//如果小球高度超出了球拍的位置,且横向不在球拍的范围之内,游戏结束
if(ballY >= racketY - BALL_SIZE && (ballX < racketX || ballX > racketX + RACKET_WIDTH)){
timer.cancel();
//设置游戏是否结束的旗标为true
isLose = true;
}
//如果小球位于球拍之内,且到达球拍位置,小球反弹
else if(ballY <= 0 || (ballY >= racketY - BALL_SIZE && ballX >racketX && ballX <= racketX + RACKET_WIDTH)){
ySpeed = -ySpeed;
}
//小球的坐标增加
ballX += xSpeed;
ballY += ySpeed;
//发送消息,通知系统重绘组件
handler.sendEmptyMessage(0x123);
}
}, 0, 100);
}
class GameView extends View {
Paint paint = new Paint();
public GameView(Context context) {
this(context, null);
}
public GameView(Context context, AttributeSet attrs) {
this(context, attrs, 0);
}
public GameView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
// 接收焦点
setFocusable(true);
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
// 设置样式
paint.setStyle(Paint.Style.FILL);
// 抗锯齿
paint.setAntiAlias(true);
// 如果游戏已经结束
if (isLose) {
// 颜色
paint.setColor(Color.RED);
;
// 字体大小
paint.setTextSize(40);
canvas.drawText("游戏结束", 50, 200, paint);
}
// 如果游戏还没有结束
else {
// 设置颜色,绘制小球
paint.setColor(Color.rgb(240, 240, 80));
canvas.drawCircle(ballX, ballY, BALL_SIZE, paint);
// 设置颜色,绘制球拍
paint.setColor(Color.rgb(80, 80, 200));
canvas.drawRect(racketX, racketY, racketX + RACKET_WIDTH,
racketY + RACKET_HEIGHT, paint);
}
}
}
}