【Android开发】范例2-实现简易绘图板

简介:
下面这个实例通过前面学过的Paint、Canvas等2D绘画技术来实现一个简单的Android的绘图板。

具体实现代码:

创建一个名为DrawView的类,该类继承自android.view.View类。在该类中,首先定义程序中所需的属性,然后添加构造方法,并重写onDraw(Canvas canvas)方法:
DrawView.java:
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
<?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中,最后实例化一个画笔,并设置画笔的相关属性。
关键代码如下:
/*
	 * 功能:构造方法
	 * */
	public DrawView(Context context, AttributeSet attrs) {
		super(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()方法恢复所保存的状态,关键代码如下:
/*
	 * 功能:重写onDraw方法
	 * */
	@Override
	protected void onDraw(Canvas canvas) {
		super.onDraw(canvas);
		canvas.drawColor(0xFFFFFFFF);//设置背景色
		Paint bmpPaint=new Paint();//采用默认设置创建一个画笔
		canvas.drawBitmap(cacheBitmap, 0, 0,bmpPaint);//绘制cacheBitmap
		canvas.drawPath(path, paint);//绘制路径
		canvas.save(Canvas.ALL_SAVE_FLAG);//保存canvas的状态
		//恢复canvas之前保存的状态,防止保存后对canvas执行的操作对后续的绘制有影响
		canvas.restore();
	}

在Draw类中,重写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:
				//保证横竖绘制距离不能超过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()方法,用于实现橡皮擦功能,具体代码如下:
public void clear(){
		//设置图形重叠时的处理方式
		paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
		//设置笔触的宽度
		paint.setStrokeWidth(50);
	}

编写保存当前绘图的save方法,在该方法中,调用saveBitmap()方法将当前绘图保存为PNG图片。save()方法的具体代码如下:
public void save(){
		try{
			saveBitmap("myPitcture");
		}catch(IOException e){
			e.printStackTrace();
		}
		
	}

编写保存绘制好的位图的方法saveBitmap(),在该方法中,首先在SD卡上创建一个文件,然后创建一个文件输出流对象,并调用Bitmap类的compress()方法将绘图内容压缩为PNG格式输出到刚刚创建的文件输出流对象中,最后将缓冲区的数据全部写出到输出流中,并关闭文件输出流对象。saveBitmap()方法的具体代码如下:
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文件中赋予相应的权限,
具体代码入下:
<!-- 执行SD卡检查的权限 -->
<uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS"/>
<!-- SD卡写入权限 -->
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>

在res目录中,创建一个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>

其中values/strings.xml中:
<?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的菜单资源文件。具体代码如下:
/*
     * 创建选项菜单
     * */
	@Override
	public boolean onCreateOptionsMenu(Menu menu) {
		MenuInflater inflator=new MenuInflater(this);
		inflator.inflate(R.menu.toolsmenu, menu);
		return super.onCreateOptionsMenu(menu);
	}
然后,重写onOptionsItemSelected方法,分别对各个菜单项被选择时做出相应的处理,具体代码如下:
/*
	 * 当菜单项被选择时,做出相应的处理
	 * */
	@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;
	}  

运行效果如图


转载请注明出处:http://blog.csdn.net/acmman/article/details/45460663

相关文章
|
21天前
|
Java Android开发
Android 开发获取通知栏权限时会出现两个应用图标
Android 开发获取通知栏权限时会出现两个应用图标
12 0
|
12天前
|
XML 开发工具 Android开发
构建高效的安卓应用:使用Jetpack Compose优化UI开发
【4月更文挑战第7天】 随着Android开发不断进化,开发者面临着提高应用性能与简化UI构建流程的双重挑战。本文将探讨如何使用Jetpack Compose这一现代UI工具包来优化安卓应用的开发流程,并提升用户界面的流畅性与一致性。通过介绍Jetpack Compose的核心概念、与传统方法的区别以及实际集成步骤,我们旨在提供一种高效且可靠的解决方案,以帮助开发者构建响应迅速且用户体验优良的安卓应用。
|
15天前
|
监控 算法 Android开发
安卓应用开发:打造高效启动流程
【4月更文挑战第5天】 在移动应用的世界中,用户的第一印象至关重要。特别是对于安卓应用而言,启动时间是用户体验的关键指标之一。本文将深入探讨如何优化安卓应用的启动流程,从而减少启动时间,提升用户满意度。我们将从分析应用启动流程的各个阶段入手,提出一系列实用的技术策略,包括代码层面的优化、资源加载的管理以及异步初始化等,帮助开发者构建快速响应的安卓应用。
|
15天前
|
Java Android开发
Android开发之使用OpenGL实现翻书动画
本文讲述了如何使用OpenGL实现更平滑、逼真的电子书翻页动画,以解决传统贝塞尔曲线方法存在的卡顿和阴影问题。作者分享了一个改造后的外国代码示例,提供了从前往后和从后往前的翻页效果动图。文章附带了`GlTurnActivity`的Java代码片段,展示如何加载和显示书籍图片。完整工程代码可在作者的GitHub找到:https://github.com/aqi00/note/tree/master/ExmOpenGL。
19 1
Android开发之使用OpenGL实现翻书动画
|
15天前
|
Android开发 开发者
Android开发之OpenGL的画笔工具GL10
这篇文章简述了OpenGL通过GL10进行三维图形绘制,强调颜色取值范围为0.0到1.0,背景和画笔颜色设置方法;介绍了三维坐标系及与之相关的旋转、平移和缩放操作;最后探讨了坐标矩阵变换,包括设置绘图区域、调整镜头参数和改变观测方位。示例代码展示了如何使用这些方法创建简单的三维立方体。
14 1
Android开发之OpenGL的画笔工具GL10
|
21天前
|
Android开发
Android开发小技巧:怎样在 textview 前面加上一个小图标。
Android开发小技巧:怎样在 textview 前面加上一个小图标。
12 0
|
22天前
|
Android开发
Android 开发 pickerview 自定义选择器
Android 开发 pickerview 自定义选择器
12 0
|
23天前
|
缓存 Java Android开发
安卓应用开发中的内存优化策略
在移动应用开发领域,性能一直是衡量应用质量的重要指标之一。特别是对于安卓平台,由于设备的硬件配置多样化,内存管理成为开发者面临的重大挑战。本文将深入探讨针对安卓平台的内存优化技巧,包括内存泄漏的预防、合理使用数据结构和算法、以及高效的资源释放机制。通过这些方法,开发者可以显著提升应用的性能和用户体验。
|
28天前
|
Java Android开发
Android开发系列全套课程
本系列课程面向有java基础,想进入企业从事android开发的计算机专业者。学习搭配实战案例,高效掌握岗位知识。
18 1
|
29天前
|
数据可视化 测试技术 Android开发
安卓应用开发:打造高效用户界面的五大技巧
【2月更文挑战第30天】在竞争激烈的应用市场中,一个流畅且直观的用户界面(UI)对于安卓应用的成功至关重要。本文将探讨五个关键的UI设计技巧,这些技巧旨在提升用户体验并优化性能。我们将深入分析布局优化、资源管理、动画效果、响应式设计和测试流程等方面,并提供实用的代码示例和最佳实践,帮助开发者构建既美观又高效的安卓应用。