没有废话,简单粗暴。
创建一个 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); } }修改 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>在 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);在 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();在 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; }写一个 clear() 方法,用来实现橡皮擦功能。
public void clear() { //设置图形重叠时的处理方式 paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR)); //设置橡皮擦的宽度 paint.setStrokeWidth(50); }写一个方法,用来保存当前的绘图。
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(); }在 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>在 activity 文件中,重写onCreateOptionsMenu()方法,在该方法中,实例化一个MenuInflater对象,并解析菜单资源文件。
@Override public boolean onCreateOptionsMenu(Menu menu) { MenuInflater menuInflater = new MenuInflater(this); menuInflater.inflate(R.menu.toolsmenu,menu); return super.onCreateOptionsMenu(menu); }重写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; }运行,就会得到一个简易的涂鸦板,可以改变画笔颜色,画笔宽度,擦除,保存等。
真是越来越有意思了呢!