没有废话,简单粗暴。
1.创建一个自定义 view
创建一个 DrawView,继承自 android.view.View 类。在这个类中,先定义所需的属性,再创建一个构造方法。
public class DrawView extends View {
private int view_width = 0;//画板宽度
private int view_height = 0;//画板高度
private float preX;//起始点的 x 坐标
private float preY;//起始点的 y 坐标
private Path path;//路径
public Paint paint = null;//画笔
Bitmap cacheBitmap = null;//定义一个内存中的图片,该图片作为缓冲区
Canvas cacheCanvas = null;//定义 cacheBitmap 上的 Canvas 对象
/*构造方法*/
public DrawView(Context context, AttributeSet set){
super(context,set);
}
/*重写 onDraw 方法*/
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
2.修改 xml 文件
修改 activity_main.xml 文件,并将自定义的 DrawView 添加到布局管理器中。
<?xml version="1.0" encoding="utf-8"?>
<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:orientation="vertical" >
<com.example.test.DrawView
android:id="@+id/drawView1"
android:layout_width="match_parent"
android:layout_height="match_parent" />
</FrameLayout>
3.DrawView 的构造方法
在 DrawView 的构造方法中,首先获取屏幕的宽度和高度,并创建一个与该 view 相同大小的缓存区,然后创建一个新的画面,并实例化一个路径,再讲内存中的位图绘制到 cacheCanvas 中,最后实例化一个画笔,并设置画笔的相关属性。
//获取屏幕宽度
view_width = context.getResources().getDisplayMetrics().widthPixels;
//获取屏幕高度
view_height = context.getResources().getDisplayMetrics().heightPixels;
cacheBitmap = Bitmap.createBitmap(view_width,view_height, Bitmap.Config.ARGB_8888);
//创建一个新的画布
cacheCanvas = new Canvas();
path = new Path();
//在 cacheCanvas 上绘制 cacheBitmap
cacheCanvas.setBitmap(cacheBitmap);
paint = new Paint(Paint.DITHER_FLAG);
//设置默认的画笔颜色
paint.setColor(Color.RED);
//设置填充方式为描边
paint.setStyle(Paint.Style.STROKE);
//设置笔刷的图形样式
paint.setStrokeJoin(Paint.Join.ROUND);
//设置画笔转弯处的连接风格
paint.setStrokeCap(Paint.Cap.ROUND);
//设置默认的画笔的宽度
paint.setStrokeWidth(1);
//使用抗锯齿功能
paint.setAntiAlias(true);
//使用抖动效果
paint.setDither(true);
4.重写 onDraw 方法
在 DrawView 的 onDraw 方法中,设置背景颜色,绘制 cacheBitmap,绘制路径以及保存当前的状态到栈中,并调用 restore()方法恢复所保存的状态。
//设置背景颜色
canvas.drawColor(0xFFFFFFFF);
//采用默认设置创建一个画笔
Paint bmpPaint = new Paint();
//绘制cacheBitmap
canvas.drawBitmap(cacheBitmap,0,0,bmpPaint);
//绘制路径
canvas.drawPath(path,paint);
//保存 canvas 状态
canvas.save(Canvas.ALL_SAVE_FLAG);
//恢复 canvas 之前的保存状态,防止保存后对 canvas 执行的操作最后续的绘制有影响
canvas.restore();
5.重写 onTouchEvent 方法
在 DrawView 类中,重写onTouchEvent() 方法,为该视图添加触摸时间监听器,在该方法中,首先获取触摸时间发生的位置,然后应用 switch 对时间的不同状态添加响应代码,最后调用invalidate()方法更新视图。
@Override
public boolean onTouchEvent(MotionEvent event) {
//获取触摸时间发生的位置
float x = event.getX();
float y = event.getY();
switch (event.getAction()){
case MotionEvent.ACTION_DOWN:
//将绘图的起始点移到(x,y)的坐标位置
path.moveTo(x,y);
preX = x;
preY = y;
break;
case MotionEvent.ACTION_MOVE:
float dx = Math.abs(x-preX);
float dy = Math.abs(y-preY);
//判断是否在允许的范围内
if (dx>=5 || dy >= 5){
path.quadTo(preX,preY,(x+preX)/2,(y+preY)/2);
preX = x;
preY = y;
}
break;
case MotionEvent.ACTION_UP:
//绘制路径
cacheCanvas.drawPath(path,paint);
path.reset();
break;
}
invalidate();
//返回 true,表示处理方法已经处理该事件
return true;
}
6.编写 clear() 方法
写一个 clear() 方法,用来实现橡皮擦功能。
public void clear() {
//设置图形重叠时的处理方式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//设置橡皮擦的宽度
paint.setStrokeWidth(50);
}
7.编写 save() 方法
写一个方法,用来保存当前的绘图。
public void save() {
try {
saveBitmap("myPicture");
}catch (IOException e){
e.printStackTrace();
}
}
private void saveBitmap(String filename) throws IOException {
//创建文件对象
File file = new File("/sdcard/pictures/"+filename+".png");
//创建一个新文件
file.createNewFile();
//创建一个文件输出流对象
FileOutputStream out = new FileOutputStream(file);
//将绘图内容压缩成 PNG 格式输出到输出流对象中
cacheBitmap.compress(Bitmap.CompressFormat.PNG,100,out);
//将缓冲区的数据全部写出到输出流中
out.flush();
//关闭文件输出流对象
out.close();
}
8.设置权限
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
9.创建 menu 资源文件
在 res 目录下,创建menu 文件夹,在 menu 文件夹下,创建 toolsmenu.xml 资源文件。
<?xml version="1.0" encoding="utf-8"?>
<menu xmlns:android="http://schemas.android.com/apk/res/android" >
<item android:title="@string/color">
<menu >
<!-- 定义一组单选菜单项 -->
<group android:checkableBehavior="single" >
<!-- 定义子菜单 -->
<item android:id="@+id/red" android:title="@string/color_red"/>
<item android:id="@+id/green" android:title="@string/color_green"/>
<item android:id="@+id/blue" android:title="@string/color_blue"/>
</group>
</menu>
</item>
<item android:title="@string/width">
<menu >
<!-- 定义子菜单 -->
<group>
<item android:id="@+id/width_1" android:title="@string/width_1"/>
<item android:id="@+id/width_2" android:title="@string/width_2"/>
<item android:id="@+id/width_3" android:title="@string/width_3"/>
</group>
</menu>
</item>
<item android:id="@+id/clear" android:title="@string/clear"/>
<item android:id="@+id/save" android:title="@string/save"/>
</menu>
10.添加选项菜单
<1>重写onCreateOptionsMenu方法
在 activity 文件中,重写onCreateOptionsMenu()方法,在该方法中,实例化一个MenuInflater对象,并解析菜单资源文件。
@Override
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater menuInflater = new MenuInflater(this);
menuInflater.inflate(R.menu.toolsmenu,menu);
return super.onCreateOptionsMenu(menu);
}
<2>重写onOptionsItemSelected方法
重写onOptionsItemSelected() 方法,分别对各个菜单项被选择时做出相应的处理。
@Override
public boolean onOptionsItemSelected(MenuItem item) {
//获取自定义视图
DrawView drawView = (DrawView)findViewById(R.id.drawView1);
//取消擦除效果
drawView.paint.setXfermode(null);
//初始化画笔的宽度
drawView.paint.setStrokeWidth(1);
switch (item.getItemId()){
//设置画笔的颜色为红色
case R.id.red:
drawView.paint.setColor(Color.RED);
item.setChecked(true);
break;
//设置画笔的颜色为绿色
case R.id.green:
drawView.paint.setColor(Color.GREEN);
item.setChecked(true);
break;
//设置画笔的颜色为蓝色
case R.id.blue:
drawView.paint.setColor(Color.BLUE);
item.setChecked(true);
break;
//设置画笔的宽度为1
case R.id.width_1:
drawView.paint.setStrokeWidth(1);
break;
//设置画笔的宽度为5
case R.id.width_2:
drawView.paint.setStrokeWidth(5);
break;
//设置画笔的宽度为10
case R.id.width_3:
drawView.paint.setStrokeWidth(10);
break;
//擦除绘画
case R.id.clear:
drawView.clear();
break;
//保存绘画
case R.id.save:
drawView.save();
break;
}
return true;
}
运行,就会得到一个简易的涂鸦板,可以改变画笔颜色,画笔宽度,擦除,保存等。
真是越来越有意思了呢!