DrawingView 的原型来自DrawingView-Android,是 android 的一个可涂鸦控件。

之所以做这个控件是因为前段时间写了一个截图应用需要用到涂鸦功能,现在把涂鸦的控件单独拿出来写一个 demo。

这个控件代码超简单的哦,还不到 300 行。

效果展示

gif 效果展示:

保存的图片:

基本功能

可以设置画笔的粗细,颜色,撤销上一笔涂鸦,提供保存图片的接口。

与DrawingView-Android相比较,这个版本的控件大小可以适应图片大小和尺寸,去除了“橡皮擦”功能,增加“撤销功能”,解决了在图像上涂鸦路径不能保存的问题。

具体实现

控件适应图片

因为这个我们需要这个控件居中显示,而且 canvas 必须和加载的图片一样大(否则可以涂鸦的范围和图片大小不一样)所以在绘制这个控件的时候要测量图片大小。

重写 onMeasure()方法

@Override

protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {

super.onMeasure(widthMeasureSpec, heightMeasureSpec);

int widthSize = MeasureSpec.getSize(widthMeasureSpec);

int heightSize = MeasureSpec.getSize(heightMeasureSpec);

if (mBitmap != null) {

// 根据加载的图片尺寸缩放控件,这里只考虑了高大于宽的情况,其他情况请读者自行完善(代码中已完善)

if (mBitmap.getHeight() > heightSize) {

widthSize = heightSize * mBitmap.getWidth() / mBitmap.getHeight();

} else {

heightSize = mBitmap.getHeight();

widthSize = mBitmap.getWidth();

}

}

Log.d(TAG, "onMeasure: heightSize: " + heightSize + " widthSize: " + widthSize);

setMeasuredDimension(widthSize, heightSize);

}

增加撤销功能

思路源于在掘金上看到的一篇文章,具体就是创建一个列表,在每次手指抬起时(MotionEvent.ACTION_UP)记录下 paint 和 path,需要“撤销”的时候先清空画布,然后重新加载图片,之后移除列表中的最后一笔,最后把列表中记录的 paint 和 path 重绘一次。

记录画笔和路径,注意如果你是直接保存 mPaint 和 mPath 的话,每次手指下落的时候都要新建这两个对象,不然会导致路径列表里所有路径都是一样的,因为他们保存的对象最终指向同样的内容。

这里我做了一点小改变。不保存 mPaint,只保存了 mPaint 的两个属性,这样就不用每次 new Paint()了。

switch (event.getAction()) {

case MotionEvent.ACTION_DOWN:

// 手指下落 新建 Path 对象

mPath = new Path();

...

break;

case MotionEvent.ACTION_MOVE:

...

mCanvas.drawPath(mPath, mPaint);

break;

case MotionEvent.ACTION_UP:

mPath.lineTo(mX, mY);

mCanvas.drawPath(mPath, mPaint);

// 保存 path 和 paint 的两个属性

savePath.add(new DrawPath(mPath, mPaint.getColor(), mPaint.getStrokeWidth()));

mPath = null;

break;

default:

break;

}

撤销方法,主要就是清空重绘。

public void undo() {

Log.d(TAG, "undo: recall last path");

if (savePath != null && savePath.size() > 0) {

// 清空画布

mCanvas.drawColor(Color.TRANSPARENT, PorterDuff.Mode.CLEAR);

loadImage(mOriginBitmap);

savePath.removeLast();

// 将路径保存列表中的路径重绘在画布上 遍历绘制

for (DrawPath dp : savePath) {

mPaint.setColor(dp.getPaintColor());// 还原画笔颜色

mPaint.setStrokeWidth(dp.getPaintWidth());// 还原画笔粗细

mCanvas.drawPath(dp.path, mPaint);

}

invalidate();

} else {

// TODO: 2017/7/12 这里留一个小 bug

// 当第一笔和最后一笔画笔的样式(颜色和宽度)不同的时候,全部撤销后,这时画笔的样式被设置成了和

// 第一笔一样,此时再绘画使用的是和第一笔一样的样式,而工具栏上我们看到的是最后一笔的样式。

// UPFATE: 2018/05/31 这里的说明不完全正确

// 我们需要的是在撤销任意步后,新的画笔颜色和宽度应和当前工具栏上的属性一致。

// 之前的说法问题在于,我们随时可以更改工具栏上画笔属性,所以新画出来的画笔属性不应和最后一笔一样,

// 而是要和工具栏上一样。(已修复)

}

}

注释里面提到了一个小 bug,现象和原因和说明了,有兴趣的读者可以自行完善一下这份代码(已解决)。

其他

DrawingView 中的 mDrawMode 用来判断当前是不是涂鸦模式。假如你的应用有其他功能模块的话,增加一个模式判断,避免涂鸦功能带来不必要的影响。

DrawingView 还提供了 getPenSize()和 getPenColor()等接口。

更多详情请参考源码。

使用方法

使用超简单

布局文件中添加控件

android:layout_width="match_parent"

android:layout_height="0dp"

android:layout_weight="1"

android:background="@color/translucent">

android:id="@+id/img_screenshot"

android:layout_width="wrap_content"

android:layout_width="wrap_content"

android:layout_gravity="center" />

PS: 因为我们在 java 代码中设置控件大小随加载的图片变化,所以这里的 layout_width 和 layout_width 属性值意义不大。

提供的接口

mDrawingView = (DrawingView) findViewById(R.id.img_screenshot);

mDrawingView.initializePen();// 初始化画笔

mDrawingView.setPenSize(10);// 设置画笔大小

mDrawingView.setPenColor(getColor(R.color.red));// 设置画笔颜色

mDrawingView.loadImage(bitmap);// 加载图片

mDrawingView.saveImage(sdcardPath, "DrawImg", Bitmap.CompressFormat.PNG, 100);//保存图片

mDrawingView.undo();// 撤销上一步

mDrawingView.getImageBitmap();// 返回控件上的 bitmap,可用于保存文件

感谢看到这里的大家~

android绘制view的撤销,DrawingView android 上的一个涂鸦控件。可以设置画笔的粗细,颜色,撤销上一笔涂鸦,提供保存图片的接口。 @codeKK Android开源站...相关推荐

  1. android绘制view的过程

    1 android绘制view的过程简单描述  简单描述可以解释为:计算大小(measure),布局坐标计算(layout),绘制到屏幕(draw):             下面看看每一步的动作到底 ...

  2. 让一个图片填满一个控件_如何在Android中实现一个全景图控件(二)

    一.背景 在 如何在Android中实现一个全景图控件(一)中,介绍了项目的一些基本情况(有 demo 演示),如果项目对你有帮助,希望文章赏个赞,项目 star 一下. 项目地址:https://g ...

  3. Android 软键盘弹出时把布局顶上去,控件乱套解决方法

    Android 软键盘弹出时把布局顶上去,控件乱套解决方法 参考文章: (1)Android 软键盘弹出时把布局顶上去,控件乱套解决方法 (2)https://www.cnblogs.com/zhuj ...

  4. Android 动态创建控件并设置控件的大小之Android屏幕适配攻略(五)

    Android 屏幕适配攻略(五)动态创建控件并设置控件的大小 题记 -- 执剑天涯,从你的点滴积累开始,所及之处,必精益求精,即是折腾每一天. 重要消息 flutter中网络请求dio使用分析 视频 ...

  5. Android如何自定义一个心电图控件?

    摘要:在我们的日常生活中,通常需要用仪器测量心率数据,来观测身体是否在一个健康的范围之内, 下面的心率图就是用一个胎心仪测量的一个宝宝心率图. 自定义控件如下图所示: 画好这样的一个心电图视图需要自定 ...

  6. android简单的自定义涂鸦控件

    简单的自定义涂鸦控件,没有写自定义属性 java代码中找到view后直接setBitmap(Bitmap bitmap)后就可以使用了 提供清除方法clear() 保存可以参考另一篇view转bitm ...

  7. 上滑ScrollView,实现控件顶部悬浮

    上滑ScrollView,实现控件顶部悬浮 因为看到网上的比较复杂,所以自己写了这篇,希望能够足够简单. 先看效果图,是不是你需要的: 不论怎么滑动屏幕内容,当蓝色部分到达顶部时,便会一直会显示在顶部 ...

  8. 应用FileInputStream类,编写应用程序,从磁盘上读取一个Java程序,并将源程序代码显示在屏幕上

    应用FileInputStream类,编写应用程序,从磁盘上读取一个Java程序,并将源程序代码显示在屏幕上. package p1;import java.io.*; public class FI ...

  9. asp.net 上传大文件控件

    这段时间写了个asp.net 上传大文件控件.经过测试,在ie中可显示进度条.特此共享,望广大网友多提意见. 大文件上传控件(包含进度条) 使用说明如下: <summary>      上 ...

最新文章

  1. 80后天才程序员,Facebook 第一任 CTO,开挂人生到底多变态?
  2. Azure运维系列 3:善用Azure捕获功能事半功倍
  3. pb调用c语言dll,PB调用C#编写的Dll类库
  4. dll function 'xxx' not found
  5. linux crud命令,crudini命令 – 操纵ini文件
  6. VTK:灯光之LightActor
  7. Logistic regression Newton’s method
  8. buffer pool mysql_理解Mysql中的Buffer pool
  9. Hi3519av100 编译kernel
  10. Sqlmap中文手册
  11. 2020-10-18 硬件电路设计之三极管放大电路【B站】
  12. PNP和NPN三极管区别
  13. 软件工程与计算-11-人机交互设计
  14. 01 牛刀小试【PAT A1046】Shortest Distance
  15. 【原创】JS 数字转换成英文写法(包含小数)
  16. 《按自己的意愿过一生》读书笔记
  17. NFT 的潜力:扩展的艺术品鉴定证书
  18. GameofMir引擎架设传奇服务器【1:架设服务端】
  19. 漫谈Linux系统的二次定制
  20. 用 PHP 来刷leetCode 之 三数之和

热门文章

  1. 海康威视SDK控制台程序consoleDemo获取视频通道参数
  2. 数据科学家为什么还要学藏语?这不科学。首份藏文数字数据集出炉
  3. 高考读卡机是谁发明的?
  4. 使用 Vue-cli 搭建SPA项目
  5. 昆石VOS3000_2.1.6.0.0安装交流 vos5000服务
  6. 腾讯云TCA运维认证考试题库
  7. 有余记账(h5记账类项目)
  8. 微信官方你真的懂OAuth2?Spring Security OAuth2整合企业微信扫码登录
  9. [服务器]Windows server 2008 R2远程桌面授权破解方法
  10. 搭建商城的微服务架构-2