自定义View签名画板并保存
来源:互联网 发布:旧电脑安装linux 编辑:程序博客网 时间:2024/06/06 20:36
项目中用到签名的功能。实现完记录一下。
效果图:
首先是签名的功能。原理很简单将我们手指一动的轨迹绘制出来就可以了。主要用到了canvas的绘制path的api。 canvas.drawPath(mPath,mPaint); 剩下的主要就是我们怎么确定path的轨迹。
path轨迹的确定可以参考文章Path之贝赛尔曲线和手势轨迹、水波纹效果
path的轨迹的确定无非就是 Path.moveTo(x,y)来指定path的起点,Path.lineTo(绘制直线),Path.quadTo(绘制二阶贝赛尔 曲线),Path.cubicTo() (绘制三阶贝赛尔)等。
使用lineTo()也能实现效果,但是它只是把我们手指绘制的点连接起来放大后会有马赛克的效果。所以用quadTo绘制曲线比较好。
public void quadTo(float x1, float y1, float x2, float y2)
参数中(x1,y1)是控制点坐标,(x2,y2)是终点坐标
整条线的起始点是通过Path.moveTo(x,y)来指定的,而如果我们连续调用quadTo(),前一个quadTo()的终点,就是下一个quadTo()函数的起点;如果初始没有调用Path.moveTo(x,y)来指定起始点,则默认以控件左上角(0,0)为起始
@Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GRAY); canvas.drawPath(mPath,mPaint); }
@Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mPath.moveTo(event.getX(),event.getY()); mPreX = event.getX(); mPreY = event.getY(); return true; case MotionEvent.ACTION_MOVE: float endX = (mPreX+event.getX())/2; float endY = (mPreY+event.getY())/2; mPath.quadTo(mPreX,mPreY,endX,endY); mPreX = event.getX(); mPreY =event.getY(); invalidate(); break; } return super.onTouchEvent(event); }
就这几行就可完成 具体详解请看Path之贝赛尔曲线和手势轨迹、水波纹效果 写的很详细,demo也是参考的此文稍微优化了下。
然后就是把我们绘制出来的签名保存到本地。
主要就是把我们的自定义view转化成一个bitmap
public Bitmap getChartBitmap() { // 创建一个bitmap 根据我们自定义view的大小 Bitmap returnedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565); // 绑定canvas Canvas canvas = new Canvas(returnedBitmap); // 获取视图的背景 Drawable bgDrawable = getBackground(); if (bgDrawable != null) // 如果有就绘制 bgDrawable.draw(canvas); else // 没有就绘制白色 canvas.drawColor(Color.WHITE); // 绘制 draw(canvas); return returnedBitmap; }
转化完成之后就是确定一个保存路径保和我们保存的格式存到本地了
public boolean saveToGallery(String fileName, String subFolderPath, String fileDescription, Bitmap.CompressFormat format, int quality) { // 控制图片质量 if (quality < 0 || quality > 100) quality = 50; long currentTime = System.currentTimeMillis(); File extBaseDir = Environment.getExternalStorageDirectory(); File file = new File(extBaseDir.getAbsolutePath() + "/DCIM/" + subFolderPath); if (!file.exists()) { if (!file.mkdirs()) { return false; } } String mimeType = ""; switch (format) { case PNG: mimeType = "image/png"; if (!fileName.endsWith(".png")) fileName += ".png"; break; case WEBP: mimeType = "image/webp"; if (!fileName.endsWith(".webp")) fileName += ".webp"; break; case JPEG: default: mimeType = "image/jpeg"; if (!(fileName.endsWith(".jpg") || fileName.endsWith(".jpeg"))) fileName += ".jpg"; break; } mFilePath = file.getAbsolutePath() + "/" + fileName; FileOutputStream out = null; try { out = new FileOutputStream(mFilePath); Bitmap b = getChartBitmap(); b.compress(format, quality, out); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); return false; } long size = new File(mFilePath).length(); ContentValues values = new ContentValues(8); // store the details values.put(MediaStore.Images.Media.TITLE, fileName); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.DATE_ADDED, currentTime); values.put(MediaStore.Images.Media.MIME_TYPE, mimeType); values.put(MediaStore.Images.Media.DESCRIPTION, fileDescription); values.put(MediaStore.Images.Media.ORIENTATION, 0); values.put(MediaStore.Images.Media.DATA, mFilePath); values.put(MediaStore.Images.Media.SIZE, size); return getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) != null; }
完整代码:
package com.chs.notificationtest;import android.content.ContentValues;import android.content.Context;import android.graphics.Bitmap;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graphics.Path;import android.graphics.drawable.Drawable;import android.os.Environment;import android.provider.MediaStore;import android.util.AttributeSet;import android.view.MotionEvent;import android.view.View;import java.io.File;import java.io.FileOutputStream;import java.io.IOException;/** * 作者:chs on 2016/9/14 16:14 * 邮箱:657083984@qq.com */public class SingerView extends View { private Paint mPaint; private Path mPath; private float mPreX,mPreY; private String mFilePath; public SingerView(Context context) { super(context); init(context); } public SingerView(Context context, AttributeSet attrs) { super(context, attrs); init(context); } public SingerView(Context context, AttributeSet attrs, int defStyleAttr) { super(context, attrs, defStyleAttr); init(context); } private void init(Context context) { mPaint = new Paint(); mPaint.setStyle(Paint.Style.STROKE); mPaint.setColor(Color.BLACK); mPaint.setStrokeWidth(2); mPaint.setAntiAlias(true); mPath = new Path(); } @Override protected void onDraw(Canvas canvas) { super.onDraw(canvas); canvas.drawColor(Color.GRAY); canvas.drawPath(mPath,mPaint); } @Override public boolean onTouchEvent(MotionEvent event) { switch (event.getAction()){ case MotionEvent.ACTION_DOWN: mPath.moveTo(event.getX(),event.getY()); mPreX = event.getX(); mPreY = event.getY(); return true; case MotionEvent.ACTION_MOVE: float endX = (mPreX+event.getX())/2; float endY = (mPreY+event.getY())/2; mPath.quadTo(mPreX,mPreY,endX,endY); mPreX = event.getX(); mPreY =event.getY(); invalidate(); break; } return super.onTouchEvent(event); } public boolean saveToGallery(String fileName, String subFolderPath, String fileDescription, Bitmap.CompressFormat format, int quality) { // 控制图片质量 if (quality < 0 || quality > 100) quality = 50; long currentTime = System.currentTimeMillis(); File extBaseDir = Environment.getExternalStorageDirectory(); File file = new File(extBaseDir.getAbsolutePath() + "/DCIM/" + subFolderPath); if (!file.exists()) { if (!file.mkdirs()) { return false; } } String mimeType = ""; switch (format) { case PNG: mimeType = "image/png"; if (!fileName.endsWith(".png")) fileName += ".png"; break; case WEBP: mimeType = "image/webp"; if (!fileName.endsWith(".webp")) fileName += ".webp"; break; case JPEG: default: mimeType = "image/jpeg"; if (!(fileName.endsWith(".jpg") || fileName.endsWith(".jpeg"))) fileName += ".jpg"; break; } mFilePath = file.getAbsolutePath() + "/" + fileName; FileOutputStream out = null; try { out = new FileOutputStream(mFilePath); Bitmap b = getChartBitmap(); b.compress(format, quality, out); out.flush(); out.close(); } catch (IOException e) { e.printStackTrace(); return false; } long size = new File(mFilePath).length(); ContentValues values = new ContentValues(8); // store the details values.put(MediaStore.Images.Media.TITLE, fileName); values.put(MediaStore.Images.Media.DISPLAY_NAME, fileName); values.put(MediaStore.Images.Media.DATE_ADDED, currentTime); values.put(MediaStore.Images.Media.MIME_TYPE, mimeType); values.put(MediaStore.Images.Media.DESCRIPTION, fileDescription); values.put(MediaStore.Images.Media.ORIENTATION, 0); values.put(MediaStore.Images.Media.DATA, mFilePath); values.put(MediaStore.Images.Media.SIZE, size); return getContext().getContentResolver().insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values) != null; } public Bitmap getChartBitmap() { // 创建一个bitmap 根据我们自定义view的大小 Bitmap returnedBitmap = Bitmap.createBitmap(getWidth(), getHeight(), Bitmap.Config.RGB_565); // 绑定canvas Canvas canvas = new Canvas(returnedBitmap); // 获取视图的背景 Drawable bgDrawable = getBackground(); if (bgDrawable != null) // 如果有就绘制 bgDrawable.draw(canvas); else // 没有就绘制白色 canvas.drawColor(Color.WHITE); // 绘制 draw(canvas); return returnedBitmap; } public String getPath(){ return mFilePath; }}
保存完我们希望能像gif图中一样显示到界面上,很简单通过路径创建个bitmap 给ImageView就可以了
Bitmap bitmap = BitmapFactory.decodeFile(mSingerView.getPath()); mImageView.setImageBitmap(bitmap);
- 自定义View签名画板并保存
- 自定义View实现画板并保存为Bitmap(用于银行卡交易签名)
- 自定义view实现涂鸦(画板)功能
- 自定义view实现涂鸦(画板)功能(二)
- android 手写签名、画板(自定义视图)的使用
- Android 自定义View-->电子签名
- android 画板(选择图片作为背景并保存)
- android 自定义view 状态保存
- android自定义view状态保存
- h5 利用canvas手写签名并保存
- ViewDragHelper自定义view保存view的位置
- Android 自定义View(手写签名)
- Android 自定义view——签名板
- android对View控件截图并保存
- 将view转化为图片并保存
- Android学习笔记-自定义view保存状态
- Android中自定义View的状态保存
- Android自定义view保存状态学习总结
- DOM三大方法的区别
- Fragment中onOptionsItemSelected方法不起作用的解决方法
- 第3周项目3-求集合并集
- ORACLE 12C新特性——CDB与PDB
- hdu3715 Go Deeper--二分 & 2-sat
- 自定义View签名画板并保存
- Android Studio 错误 com.android.dex.DexIndexOverflowException: method ID not in [0, 0xffff]: 65536
- maven的坐标,仓库介绍及配置
- RocketMq 搭建速记
- IE内核安装OCX插件
- Android.mk简单分析
- Unity3D和ios交互
- json和jsonp的区别
- 人脸识别之人脸对齐(四)--CLM算法及概率图模型改进