
下面这个实例通过前面学过的Paint、Canvas等2D绘画技术来实现一个简单的AndroID的绘图板。
具体实现代码:
创建一个名为DrawVIEw的类,该类继承自androID.vIEw.VIEw类。在该类中,首先定义程序中所需的属性,然后添加构造方法,并重写onDraw(Canvas canvas)方法:
DrawVIEw.java:
[java] vIEw plain copy
package com.example.test;
import androID.content.Context;
import androID.graphics.Bitmap;
import androID.graphics.Canvas;
import androID.graphics.Paint;
import androID.graphics.Path;
import androID.util.AttributeSet;
import 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;//画笔
Bitmap cacheBitmap=null;//定义一个内存中的图片,该图片将作为缓冲区
Canvas cacheCanvas=null;//定义cacheBitmap上的Canvas对象
/*
* 功能:构造方法
* */
public DrawVIEw(Context context,AttributeSet attrs) {
super(context,attrs);
}
/*
* 功能:重写onDraw方法
* */
@OverrIDe
protected voID onDraw(Canvas canvas) {
super.onDraw(canvas);
}
}
创建布局文件,选择帧布局,并加入上面创建的继承了VIEw的自定义画图控件:
res/layout/main.xml
[HTML] vIEw plain copy
<?xml version="1.0" enCoding="utf-8"?>
<FrameLayout xmlns:androID="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
androID:layout_wIDth="fill_parent"
androID:layout_height="fill_parent"
androID:ID="@+ID/frameLayout1"
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中,最后实例化一个画笔,并设置画笔的相关属性。
关键代码如下:
[java] vIEw plain copy
/*
* 功能:构造方法
* */
public DrawVIEw(Context context,attrs);
vIEw_wIDth=context.getResources().getdisplayMetrics().wIDthPixels;//获取屏幕宽度
vIEw_height=context.getResources().getdisplayMetrics().heightPixels;//获取屏幕高度
//创建一个与该VIEw相同大小的缓存区
cacheBitmap=Bitmap.createBitmap(vIEw_wIDth,vIEw_height,Config.ARGB_8888);
cacheCanvas=new Canvas();//创建一个新的画布
path=new Path();
//在cacheCanvas上绘制cacheBitmap
cacheCanvas.setBitmap(cacheBitmap);
paint=new Paint(Paint.DITHER_FLAG);//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);//设置默认笔触的宽度为1像素
paint.setAntiAlias(true);//设置抗锯齿效果
paint.setDither(true);//使用抖动效果
}
在DrawVIEw类的onDraw()方法中,添加以下代码,用于设置背景颜色、绘制cacheBitmap、绘制路径以及保存当前绘图状态到栈中,并调用restore()方法恢复所保存的状态,关键代码如下:
[java] vIEw plain copy
/*
* 功能:重写onDraw方法
* */
@OverrIDe
protected voID onDraw(Canvas canvas) {
super.onDraw(canvas);
canvas.drawcolor(0xFFFFFFFF);//设置背景色
Paint bmpPaint=new Paint();//采用默认设置创建一个画笔
canvas.drawBitmap(cacheBitmap,bmpPaint);//绘制cacheBitmap
canvas.drawPath(path,paint);//绘制路径
canvas.save(Canvas.ALL_SAVE_FLAG);//保存canvas的状态
//恢复canvas之前保存的状态,防止保存后对canvas执行的 *** 作对后续的绘制有影响
canvas.restore();
}
在Draw类中,重写ontouchEvent()方法,为该视图添加触摸事件监听器,在该方法中,首先获取触摸事件发生的位置,然后用switch语句对事件的不同状态添加响应代码,最后调用invalIDate()方法更新视图。具体代码如下:
[java] vIEw plain copy
@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:
//保证横竖绘制距离不能超过625
float dx=Math.abs(x-preX);
float dy=Math.abs(y-preY);
if(dx>5||dy>5){
//.quadTo贝塞尔曲线,实现平滑曲线(对比lineto)
//x1,y1为控制点的坐标值,x2,y2为终点的坐标值
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();
return true;//返回true,表明处理方法已经处理该事件
}
编写clear()方法,用于实现橡皮擦功能,具体代码如下:
[java] vIEw plain copy
public voID clear(){
//设置图形重叠时的处理方式
paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
//设置笔触的宽度
paint.setstrokeWIDth(50);
}
编写保存当前绘图的save方法,在该方法中,调用saveBitmap()方法将当前绘图保存为PNG图片。save()方法的具体代码如下:
[java] vIEw plain copy
public voID save(){
try{
saveBitmap("myPitcture");
}catch(IOException e){
e.printstacktrace();
}
}
编写保存绘制好的位图的方法saveBitmap(),在该方法中,首先在SD卡上创建一个文件,然后创建一个文件输出流对象,并调用Bitmap类的compress()方法将绘图内容压缩为PNG格式输出到刚刚创建的文件输出流对象中,最后将缓冲区的数据全部写出到输出流中,并关闭文件输出流对象。saveBitmap()方法的具体代码如下:
[java] vIEw plain copy
private voID saveBitmap(String filename) throws IOException {
file file=new file(getSdpath()+filename+".png");
file.createNewfile();
fileOutputStream fileOS=new fileOutputStream(file);
//将绘图内容压缩为PNG格式输出到输出流对象中
cacheBitmap.compress(Bitmap.CompressFormat.PNG,100,fileOS);
fileOS.flush();//将缓冲区中的数据全部写出到输出流中
fileOS.close();//关闭文件输出流对象
}
//获得SD卡的根目录
public String getSdpath(){
file sdDir = null;
boolean sdCardExist = Environment.getExternalStorageState()
.equals(androID.os.Environment.MEDIA_MOUNTED); //判断sd卡是否存在
if (sdCardExist) //如果SD卡存在,则获取跟目录
{
sdDir = Environment.getExternalStorageDirectory();//获取跟目录
}
return sdDir.toString();
}
在程序中需要向SD卡上保存文件,那么需要在AndroIDManifest.xml文件中赋予相应的权限,
具体代码入下:
[HTML] vIEw plain copy
<!-- 执行SD卡检查的权限 -->
<uses-permission androID:name="androID.permission.MOUNT_UNMOUNT_fileSYstemS"/>
<!-- SD卡写入权限 -->
<uses-permission androID:name="androID.permission.WRITE_EXTERNAL_STORAGE"/>
在res目录中,创建一个menu目录,并在该目录中创建一个名称为toolsmenu.xml的菜单资源文件,在该文件中编写实例中所应用的功能菜单,关键代码如下:
[HTML] vIEw plain copy
<?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>
其中values/strings.xml中:
[HTML] vIEw plain copy
<?xml version="1.0" enCoding="utf-8"?>
<resources>
<string name="app_name">test</string>
<string name="hello_world">Hello World!</string>
<string name="action_settings">Settings</string>
<string name="color">画笔颜色</string>
<string name="color_red">红色</string>
<string name="color_green">绿色</string>
<string name="color_blue">蓝色</string>
<string name="wIDth">画笔宽度</string>
<string name="wIDth_1">细</string>
<string name="wIDth_2">中</string>
<string name="wIDth_3">粗</string>
<string name="clear">擦除绘画</string>
<string name="save">保存绘画</string>
</resources>
在默认创建的MainActivity中,为实例添加选项菜单。
首先,重写onCreatoptionsMenu()方法,在该方法中,实例化一个MenuInflater对象,并调用该对象的inflate方法解析toolsmenu.xml的菜单资源文件。具体代码如下:
[java] vIEw plain copy
/*
* 创建选项菜单
* */
@OverrIDe
public boolean onCreateOptionsMenu(Menu menu) {
MenuInflater inflator=new MenuInflater(this);
inflator.inflate(R.menu.toolsmenu,menu);
return super.onCreateOptionsMenu(menu);
}
然后,重写onoptionsItemSelected方法,分别对各个菜单项被选择时做出相应的处理,具体代码如下:
[java] vIEw plain copy
/*
* 当菜单项被选择时,做出相应的处理
* */
@OverrIDe
public boolean onoptionsItemSelected(MenuItem item) {
//获取自定义的绘图视图
DrawVIEw dv=(DrawVIEw)findVIEwByID(R.ID.drawVIEw1);
dv.paint.setXfermode(null);//取消擦除效果
dv.paint.setstrokeWIDth(1);//初始化画笔的宽度
switch(item.getItemID()){
case R.ID.red:
dv.paint.setcolor(color.RED);//设置笔的颜色为红色
item.setChecked(true);
break;
case R.ID.green:
dv.paint.setcolor(color.GREEN);//设置笔的颜色为绿色
item.setChecked(true);
break;
case R.ID.blue:
dv.paint.setcolor(color.BLUE);//设置笔的颜色为蓝色
item.setChecked(true);
break;
case R.ID.wIDth_1:
dv.paint.setstrokeWIDth(1);//设置笔触的宽度为1像素
break;
case R.ID.wIDth_2:
dv.paint.setstrokeWIDth(5);//设置笔触的宽度为5像素
break;
case R.ID.wIDth_3:
dv.paint.setstrokeWIDth(10);//设置笔触的宽度为10像素
break;
case R.ID.clear:
dv.clear();//擦除绘画
break;
case R.ID.save:
dv.save();//保存绘画
break;
}
return true;
}
运行效果如图
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持编程小技巧。
以上是内存溢出为你收集整理的简单实现Android绘图板全部内容,希望文章能够帮你解决简单实现Android绘图板所遇到的程序开发问题。
如果觉得内存溢出网站内容还不错,欢迎将内存溢出网站推荐给程序员好友。
欢迎分享,转载请注明来源:内存溢出
微信扫一扫
支付宝扫一扫
评论列表(0条)