利用一个简单的绘图app来说明安卓的图形处理类与自己定义View的应用。
例如以下图,有一个供用户自己随意绘图、涂鸦的app。
这里不做那么花俏了,仅提供黑白两色。但能够改变笔尖的粗细。
实质上这里的橡皮擦就是白色的画笔,根本不用使用到画笔的setXfermode方法,要搞一堆复杂的project。
用户画完图之后能够保存图像。图像的文件名称是当前的时间。保存的位置是sdcard的根文件夹。
制作步骤例如以下:
1、先设置好字体文件res\values\strings.xml,主要是app的名称与菜单各个子项的字符。
<?xml version="1.0" encoding="utf-8"?> <resources> <string>绘图</string> <string>画笔宽度</string> <string>1</string> <string>5</string> <string>10</string> <string>50</string> <string>画笔</string> <string>橡皮擦</string> <string>保存</string> <string>退出</string> <string>作者:yongh701</string> </resources>2、之后就是菜单文件的设置,这里不再赘述了,在《【Android】日期拾取器、时间拾取器与菜单》(点击打开链接)与《【Android】app透明与字体颜色更变、上下文菜单》(点击打开链接)两篇文章都具体搞过菜单的东西。主要是第一个菜单选项“画笔宽度”是带有子项的,因此,设置菜单的id是分别给子项设置id。而不是主项。主项无须id。 <menu xmlns:android="http://schemas.android.com/apk/res/android" > <item android:title="@string/menu1"> <menu> <group android:checkableBehavior="single" > <item android:id="@+id/menu1_sub1" android:title="@string/menu1_sub1"/> <item android:id="@+id/menu1_sub2" android:title="@string/menu1_sub2"/> <item android:id="@+id/menu1_sub3" android:title="@string/menu1_sub3"/> <item android:id="@+id/menu1_sub4" android:title="@string/menu1_sub4"/> </group> </menu> </item> <item android:id="@+id/menu2" android:title="@string/menu2"/> <item android:id="@+id/menu3" android:title="@string/menu3"/> <item android:id="@+id/menu4" android:title="@string/menu4"/> <item android:id="@+id/menu5" android:title="@string/menu5"/> <item android:title="@string/menu_author"/> </menu>3、因为一会儿还要把用户画出来的图片写入的sdcard卡,因此将在AndroidManifest.xml申请sdcard的写入的权限:
<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.painter" android:versionCode="1" android:versionName="1.0" > <uses-sdk android:minSdkVersion="8" android:targetSdkVersion="18" /> <!-- 须要在SD卡写入数据的权限 --> <uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /> <application android:allowBackup="true" android:icon="@drawable/ic_launcher" android:label="@string/app_name" android:theme="@style/AppTheme" > <activity android:name="com.painter.MainActivity" android:label="@string/app_name" > <intent-filter> <action android:name="android.intent.action.MAIN" /> <category android:name="android.intent.category.LAUNCHER" /> </intent-filter> </activity> </application> </manifest> 4、之后就像《【Android】自己定义View、画布Canvas与画笔Paint》(点击打开链接)一样,新建一个自己定义的View。这里是DrawView。这个DrawView是本app实现的核心。其构造方法,使用public DrawView(Context context, AttributeSet attrs) {super(context, attrs);} ,这个带有两个參数的构造方法,由于一会儿这个DrawView将以xml的方式直接布置在MainActivity。同一时候通过Alt+Shift+S->V选择继承protected void onDraw(Canvas canvas) {},public boolean onTouchEvent(MotionEvent event) {}这两个方法,一个是安卓图像处理技术的基本方法onDraw,一个是用户触摸这个View时发生的事件onTouchEvent方法。同一时候自己加入一个saveBitmap方法,用来实现图片的终于的保存。DrawView.java的代码例如以下:
package com.painter; import java.io.File; import java.io.FileOutputStream; import java.text.SimpleDateFormat; import java.util.Date; import java.util.Locale; import android.content.Context; import android.graphics.Bitmap; import android.graphics.Bitmap.Config; import android.graphics.Canvas; import android.graphics.Color; import android.graphics.Paint; import android.graphics.Path; import android.os.Environment; import android.util.AttributeSet; import android.view.MotionEvent; import android.view.View; import android.widget.Toast; public class DrawView extends View { private Bitmap cacheBitmap;// 画纸 private Canvas cacheCanvas;// 创建画布、画家 private Path path;// 画图的路径 public Paint paint;// 画笔 private float preX, preY;// 之前的XY的位置。用于以下的手势移动 private int view_width, view_height;// 屏幕的高度与宽度 public DrawView(Context context, AttributeSet attrs) { super(context, attrs); path = new Path(); paint = new Paint(); cacheCanvas = new Canvas(); // 获取屏幕的高度与宽度 view_width = context.getResources().getDisplayMetrics().widthPixels; view_height = context.getResources().getDisplayMetrics().heightPixels; cacheBitmap = Bitmap.createBitmap(view_width, view_height, Config.ARGB_8888);// 建立图像缓冲区用来保存图像 cacheCanvas.setBitmap(cacheBitmap); cacheCanvas.drawColor(Color.WHITE); paint.setColor(Color.BLACK);// 设置画笔的默认颜色 paint.setStyle(Paint.Style.STROKE);// 设置画笔的填充方式为无填充、不过画线 paint.setStrokeWidth(1);// 设置画笔的宽度为1 } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawBitmap(cacheBitmap, 0, 0, paint);// 把cacheBitmap画到DrawView上 } @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 = y; break; case MotionEvent.ACTION_MOVE: float dx = Math.abs(x - preX); float dy = Math.abs(y - preY); if (dx > 5 || dy > 5) {// 用户要移动超过5像素才算是画图。免得手滑、手抖现象 path.quadTo(preX, preY, (x + preX) / 2, (y + preY) / 2); preX = x; preY = y; cacheCanvas.drawPath(path, paint);// 绘制路径 } break; case MotionEvent.ACTION_UP: path.reset(); break; } invalidate(); return true; } public void saveBitmap() throws Exception { String sdpath = Environment.getExternalStorageDirectory() .getAbsolutePath();// 获取sdcard的根路径 String filename = new SimpleDateFormat("yyyyMMddhhmmss", Locale.getDefault()) .format(new Date(System.currentTimeMillis()));// 产生时间戳,称为文件名称 File file = new File(sdpath + File.separator + filename + ".png"); file.createNewFile(); FileOutputStream fileOutputStream = new FileOutputStream(file); cacheBitmap.compress(Bitmap.CompressFormat.PNG, 100, fileOutputStream);// 以100%的品质创建png // 人走带门 fileOutputStream.flush(); fileOutputStream.close(); Toast.makeText(getContext(), "图像已保存到" + sdpath + File.separator + filename + ".png", Toast.LENGTH_SHORT).show(); } }整个DrawView.java做了例如以下的事情:
(1)设置一张画纸cacheBitmap。两个画家Canvas与cacheCanvas,一支画笔paint,这里之所以要有两位画家,是由于onDraw方法独占Canvas这个类成员。