Android View与SurfaceView的手绘板制作
最近学习了如何使用View与SurfaceView制作简单的手绘板,在此做个小结。
自定义VIew实现手绘板:
首先是使用View来实现手绘板:
package com.app.superxlcr.mydrawboard.myView;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.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.view.MotionEvent;
import android.view.View;/*** Created by Superxlcr* On 2016/3/18* 普通画板View*/
public class NormalDrawBoardView extends View {// 点击的坐标private float lastX = 0, lastY = 0;private Path path;private Paint paint;// 使用内存中的图片作为缓冲区private Bitmap cacheBitmap;// 缓冲区上的Canvas对象private Canvas cacheCanvas;public NormalDrawBoardView(Context context, int width, int height) {super(context);// 创建确定大小的bitmapcacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);// 初始化缓存画布,把bitmap内容画到缓存画布上cacheCanvas = new Canvas();cacheCanvas.setBitmap(cacheBitmap);path = new Path();// 初始化画笔// 防抖动paint = new Paint(Paint.DITHER_FLAG);paint.setColor(Color.BLACK);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(1);// 反锯齿paint.setAntiAlias(true);paint.setDither(true);}/*** 设置画笔的颜色* @param color,颜色的字符串*/public void setPaintColor(String color) {switch (color) {case "red" :paint.setColor(Color.RED);break;case "green" :paint.setColor(Color.GREEN);break;case "blue" :paint.setColor(Color.BLUE);break;case "yellow" :paint.setColor(Color.YELLOW);break;default:paint.setColor(Color.BLACK);break;}}/*** 设置画笔粗细* @param width*/public void setPaintWidth(int width) {paint.setStrokeWidth(width);}public void clearCanvas() {// 清除path轨迹path.reset();path.moveTo(lastX, lastY);// 清除cacheCanvas图像Paint paint = new Paint();paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));cacheCanvas.drawPaint(paint);invalidate();
// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));}@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX(), y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: // 记录点击坐标,把当前点定义为线段的前一个点lastX = x;lastY = y;path.moveTo(x, y);break;case MotionEvent.ACTION_MOVE: // 绘制线段path.quadTo(lastX, lastY, x, y);lastX = x;lastY = y;break;case MotionEvent.ACTION_UP: // 把线段绘制到画布上cacheCanvas.drawPath(path, paint);path.reset();break;}invalidate();return true;}@Overrideprotected void onDraw(Canvas canvas) {Paint bmpPaint = new Paint();// 绘制之前画的轨迹canvas.drawBitmap(cacheBitmap, 0, 0, bmpPaint);// 绘制正在画的轨迹canvas.drawPath(path, paint);}
}
在上面的代码中我们首先初始化了以下变量:
- path:用于记录用户手指滑动的路径类
- paint:画笔类
- cacheBitmap:用于存储用户画的手绘的图片缓存
- cacheCanvas:用于描绘用户画的手绘的画布缓存
- lastX,lastY:记录上一个点击的点的坐标
- Motion.Action.DOWN:代表手指按下的事件,此时我们记录下手指点击坐标,并把path的起点设置为该坐标
- Motion.Action.MOVE:代表手指拖动事件,此时我们根据获取的坐标与前一个点的坐标画出一条线段,并更新记录的坐标
- Motion.Action.UP:代表手指抬起事件,此时我们把path记录的路径绘制到缓存中,并重置path
SurfaceView实现手绘板:
package com.app.superxlcr.mydrawboard.myView;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.PorterDuff;
import android.graphics.PorterDuffXfermode;
import android.util.Log;
import android.view.MotionEvent;
import android.view.SurfaceHolder;
import android.view.SurfaceView;import java.util.concurrent.TimeUnit;/*** Created by Superxlcr* On 2016/3/19*/
public class SurfaceViewDrawBoardView extends SurfaceViewimplements SurfaceHolder.Callback {private final String TAG = "SurfaceViewDrawBoard";// 绘制背景的线程private MyThread myThread;// 缓存用的bitmap和canvasprivate Bitmap cacheBitmap;private Canvas cacheCanvas;// 画笔和路径private Paint paint;private Path path;// 上一个点的坐标private float lastX, lastY;public SurfaceViewDrawBoardView(Context context, int width, int height) {super(context);// 设置bitmap和canvascacheBitmap = Bitmap.createBitmap(width, height, Bitmap.Config.ARGB_8888);cacheCanvas = new Canvas();cacheCanvas.setBitmap(cacheBitmap);// 设置画笔paint = new Paint(Paint.DITHER_FLAG);paint.setStyle(Paint.Style.STROKE);paint.setStrokeWidth(1);paint.setColor(Color.BLACK);paint.setAntiAlias(true);paint.setDither(true);// 初始化路径path = new Path();// 设置SurfaceHolder的回调函数getHolder().addCallback(this);// 初始化绘画线程myThread = new MyThread(getHolder());Log.v(TAG, Thread.currentThread().getName());}/*** 设置画笔的颜色** @param color,颜色的字符串*/public void setPaintColor(String color) {switch (color) {case "red":paint.setColor(Color.RED);break;case "green":paint.setColor(Color.GREEN);break;case "blue":paint.setColor(Color.BLUE);break;case "yellow":paint.setColor(Color.YELLOW);break;default:paint.setColor(Color.BLACK);break;}}/*** 设置画笔粗细** @param width*/public void setPaintWidth(int width) {paint.setStrokeWidth(width);}public void clearCanvas() {// 清除path轨迹path.reset();path.moveTo(lastX, lastY);// 清除cacheCanvas图像Paint paint = new Paint();paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));cacheCanvas.drawPaint(paint);// paint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.SRC));}@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX(), y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN: // 记录点击坐标,把当前点定义为线段的前一个点lastX = x;lastY = y;path.moveTo(x, y);break;case MotionEvent.ACTION_MOVE: // 绘制线段path.quadTo(lastX, lastY, x, y);lastX = x;lastY = y;break;case MotionEvent.ACTION_UP: // 把线段绘制到画布上cacheCanvas.drawPath(path, paint);path.reset();break;}return true;}@Overridepublic void surfaceCreated(final SurfaceHolder holder) {Log.v(TAG, "surfaceCreated");myThread.isRun = true;myThread.start();}@Overridepublic void surfaceChanged(SurfaceHolder holder, int format, int width,int height) {Log.v(TAG, "surfaceChanged");}@Overridepublic void surfaceDestroyed(SurfaceHolder holder) {Log.v(TAG, "surfaceDestoryed");myThread.isRun = false;}class MyThread extends Thread {private SurfaceHolder holder;public boolean isRun = false;private int red = 0, green = 0, blue = 0;private int colorValue = 0;private float hsbValue[];MyThread(SurfaceHolder holder) {this.holder = holder;hsbValue = new float[]{0, 1, 1};}@Overridepublic void run() {while (isRun) {Log.v(TAG, Thread.currentThread().getName());Canvas canvas = holder.lockCanvas();// 背景色渐变hsbValue[0] = hsbValue[0] + 1 <= 360 ? hsbValue[0] + 1 : 0;if (canvas != null) {// 绘制背景色canvas.drawColor(Color.HSVToColor(hsbValue));Paint bmpPaint = new Paint();// 绘制之前画的轨迹canvas.drawBitmap(cacheBitmap, 0, 0, bmpPaint);// 绘制正在画的轨迹canvas.drawPath(path, paint);holder.unlockCanvasAndPost(canvas);}try {// 休眠20msTimeUnit.MILLISECONDS.sleep(20);} catch (Exception e) {e.printStackTrace();}}}}
}
surfaceView允许我们在新开的线程中更新UI界面,我们首先实现了SurfaceHolder.Callback接口,该接口有以下几个重要方法:
- surfaceCreated:在Surface创建的时候调用,我们在该方法中开启了绘制UI的子线程
- surfaceChanged:在Surface大小发生改变时调用
- surfaceDestroyed:在Surface销毁时调用,我们在该方法中停止了绘制UI的子线程
- View适合实现被动更新画面的。比如棋类,这种用view就好了。因为画面的更新是依赖于 onTouch 来更新,可以直接使用 invalidate。 因为这种情况下,这一次Touch和下一次的Touch需要的时间比较长些,不会产生影响。
- 而主动更新的画面应该使用SurfaceView。比如背景在一直变色。这就需要一个单独的thread不停的重绘背景的状态,避免阻塞main UI thread。所以显然view不合适,需要surfaceView来控制。
Android View与SurfaceView的手绘板制作相关推荐
- 手绘板的制作——画布缩放(4)
前言 在这一篇中,我们讲解下画布的缩放,也就是做一个根据手势缩放进行画布缩放的功能. 我们先来梳理下逻辑: 监听手势,当为一根手指的时候,就延续之前的操作,执行手绘操作,当操作为两根手指的时候,则执行 ...
- 手绘板的制作——画布保存(6)
「手绘板的制作--手绘(1)」 「手绘板的制作--重置与橡皮擦(2)」 「手绘板的制作--命令模式与撤销.重制(3)」 「手绘板的制作--画布缩放(4)」 「手绘板的制作--画布移动(5)」 前言 经 ...
- 安卓开发-手绘板自定义绘画的保存,清空与恢复
写这篇文章是因为代码中刚实现过这些功能,害怕自己之后会忘记,所以把整个方法写出来,方便自己日后复习用. 还是老样子,先上图: 1.首页 2.点击手绘板图片后跳出的窗口 3.用手指进行绘制 4.点击保存 ...
- java画图颜色_手绘板,多种颜色选择。我抄的《疯狂java讲义》的,包我乱导的,但代码能用。...
[java]代码库import javax.swing.*; import java.awt.image.*; import java.awt.datatransfer.*; import javax ...
- 什么是数位板? 数位板,又名绘图板、绘画板、手绘板等等,是计算机输入设备的一种,通常是由一块板子和一支压感笔组成,它和手写板等作为非常规的输入产品相类似,都针对一定的使用群体。 与手写板所不同的是
什么是数位板? 数位板,又名绘图板.绘画板.手绘板等等,是计算机输入设备的一种,通常是由一块板子和一支压感笔组成,它和手写板等作为非常规的输入产品相类似,都针对一定的使用群体. 与手写板所不同的是,数 ...
- 解决win10下Photoshop2018CC手绘板画画变上下
有次用手绘板画画的时候, 手绘板的画笔变成上下了, 不能正常画画. 笔飘来飘去. 后来知道是因为win10系统更新导致, 那么把最近的更新卸载掉就可以了. 在系统设置里找到"更新和安全&qu ...
- Photoshop---Wacom手绘板绘画画变成了拖动,根本不能画画
前述 以下步骤都是基于windows10上的结果,而且的确是解决了我的问题,windows7没有试过,估计差不多,分享出来希望能帮到众位仙家. 背景&问题 近段时间photoshop手绘的时候 ...
- wacom怎么调压感_怎样在ps里用手绘板画出有压感的效果
展开全部 一 数位板没有32313133353236313431303231363533e4b893e5b19e31333433616331压感的解决设置方法. 我们在使用数位板绘画的过程中经常会遇 ...
- Win10手绘板无压感故障解决方法
Win10手绘板无压感故障解决方法 参考文章: (1)Win10手绘板无压感故障解决方法 (2)https://www.cnblogs.com/huangzhewei/p/11053214.html ...
最新文章
- InfoQ趋势报告:架构和设计领域技术演变详解
- MPTCP 源码分析(五) 接收端窗口值
- 【ActiveMQ】消息生产者自动注入报错:Could not autowire. No beans of 'JmsMessagingTemplate' type found...
- 如果记录没有跟得上创造和学习
- Spring框架版本命名规则
- MATLAB 牛顿迭代算法
- 第十一届蓝桥杯校园赛---原题+解析+答案
- 爬取外网数据(twitter、facebook)-易数云可视化爬虫软件
- 3dmax渲染卡顿崩溃怎么办?(一)
- 智慧城市顶层设计与不确定性
- 放大电路中反馈及类型的判断
- skype 无法连接
- webpack4.0关闭开发环境的代码压缩UglifyJsPlugin
- 我的CSDN之旅:2020年终总结
- 曹操梦中杀人应该是可信的
- 宝塔面板隐藏网站服务器真实IP
- 微信小程序(数据可视化、Canvas、绘制线段、图形、太极图、文本、图像、渐变、变形)
- 【Redis】基础篇
- 算法训练Day49 | Leetcode121. 买卖股票的最佳时机(只能买卖一次);LeetCode122. 买卖股票的最佳时机II(可以买卖多次)
- 苹果CEO史蒂夫·乔布斯在斯坦福演讲(一)