【Android】自定义View、画家(画布)Canvas与画笔Paint的应用——画图、涂鸦板app的实现

利用一个简单的画图app来说明安卓的图形处理类与自定义View的应用。

如下图,有一个供用户自己任意画图、涂鸦的app,


这里不做那么花俏了,仅提供黑白两色,但可以改变笔尖的粗细。

实质上这里的橡皮擦就是白色的画笔,根本不用使用到画笔的setXfermode方法,要搞一堆复杂的工程。

用户画完图之后可以保存图像。图像的文件名是当前的时间,保存的位置是sdcard的根目录。

制作过程如下:

1、先设置好字体文件res\values\strings.xml,主要是app的名称与菜单各个子项的字符。

<?xml version="1.0" encoding="utf-8"?>
<resources><string name="app_name">画图</string><string name="menu1">画笔宽度</string><string name="menu1_sub1">1</string><string name="menu1_sub2">5</string><string name="menu1_sub3">10</string><string name="menu1_sub4">50</string><string name="menu2">画笔</string><string name="menu3">橡皮擦</string><string name="menu4">保存</string><string name="menu5">退出</string><string name="menu_author">作者: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" ><itemandroid:id="@+id/menu1_sub1"android:title="@string/menu1_sub1"/><itemandroid:id="@+id/menu1_sub2"android:title="@string/menu1_sub2"/><itemandroid:id="@+id/menu1_sub3"android:title="@string/menu1_sub3"/><itemandroid:id="@+id/menu1_sub4"android:title="@string/menu1_sub4"/></group></menu></item><itemandroid:id="@+id/menu2"android:title="@string/menu2"/><itemandroid:id="@+id/menu3"android:title="@string/menu3"/><itemandroid:id="@+id/menu4"android:title="@string/menu4"/><itemandroid: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-sdkandroid:minSdkVersion="8"android:targetSdkVersion="18" /><!-- 需要在SD卡写入数据的权限 --><uses-permission android:name="android.permission.MOUNT_UNMOUNT_FILESYSTEMS" /><uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" /><applicationandroid:allowBackup="true"android:icon="@drawable/ic_launcher"android:label="@string/app_name"android:theme="@style/AppTheme" ><activityandroid: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}@Overrideprotected void onDraw(Canvas canvas) {super.onDraw(canvas);canvas.drawBitmap(cacheBitmap, 0, 0, paint);// 把cacheBitmap画到DrawView上}@Overridepublic 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这个类成员。用户每触摸一次屏幕,都会触发onTouchEvent方法,设置cacheCanvas把用户触摸时绘制的路径放到画纸cacheBitmap上,通过invalidate();方法的调用再次onDraw方法,Canvas把画纸cacheBitmap放到DrawView这个我们自定义的View上。用户每触摸一次屏幕都会执行一次这个操作。

(2)由于每次执行invalidate()方法,都会触发onDraw方法,因此初始化的工作应通通放在自定义View的构造方法中以节省内存,这个问题在《【Android】利用自定义View的重绘实现拖动移动,获取组件的尺寸》(点击打开链接)已经讲过了,这里不再赘述。构造方法,完成画家(画布)Canvas与画笔Paint,绘图路径Path的初始化。

关键是要把初始化之后的画纸cacheBitmap放到画家cacheCanvas手上,同时命令画家cacheCanvas把这张画纸cacheBitmap全部涂白,也就是说把画图的背景颜色设置为白色。否则一会儿你保存出来的图像的背景色默认是黑色的。虽然你看到的自定义View是白色的。

在画笔Paint初始化的事情,注意要把画笔设置为paint.setStyle(Paint.Style.STROKE);仅仅是画边的方法,这样才能做到涂鸦的效果,否则画笔默认是,附件画图画矩形那种拖泥带水的效果。

(3)触摸事件onTouchEvent里的作图方法这里反而没什么好说的,计算机图形学中最基本的内容。不懂就照复制就是了。

(4)最后的保存图像的方法saveBitmap()也没什么好说的。就是安卓对sdcard卡的操作,具体见《【Android】读取sdcard上的图片》(点击打开链接),与Java对文件的操作的综合,具体见《【Java】输入与输出与JDK1.5之后的新型字符串StringBuilder》(点击打开链接)。

5、通过自定义的View,能让res\layout\activity_main.xml这个MainActivity的布局xml,与MainActivity.java的代码变得简洁。res\layout\activity_main.xml将变得如下的简短,就放一个DrawView,该实现的东西都在这个自定义View中完成。

<FrameLayout xmlns:android="http://schemas.android.com/apk/res/android"android:layout_width="match_parent"android:layout_height="match_parent" ><com.painter.DrawViewandroid:id="@+id/drawView1"android:layout_width="match_parent"android:layout_height="match_parent" /></FrameLayout>
6、最后在MainActivity.java中实现指明各个菜单的实现方法就能完成整个app,OnCreate方法根本就是什么都没有,仅仅是加载布局文件。

package com.painter;import android.os.Bundle;
import android.app.Activity;
import android.graphics.Color;
import android.view.Menu;
import android.view.MenuItem;public class MainActivity extends Activity {@Overrideprotected void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(R.layout.activity_main);}@Overridepublic boolean onCreateOptionsMenu(Menu menu) {// Inflate the menu; this adds items to the action bar if it is present.getMenuInflater().inflate(R.menu.main, menu);return true;}// 处理菜单事件@Overridepublic boolean onOptionsItemSelected(MenuItem item) {DrawView drawView = (DrawView) findViewById(R.id.drawView1);switch (item.getItemId()) {// 设置id为menu_exit的菜单子项所要执行的方法。case R.id.menu1_sub1:drawView.paint.setStrokeWidth(1);break;case R.id.menu1_sub2:drawView.paint.setStrokeWidth(5);break;case R.id.menu1_sub3:drawView.paint.setStrokeWidth(10);break;case R.id.menu1_sub4:drawView.paint.setStrokeWidth(50);break;case R.id.menu2:drawView.paint.setColor(Color.BLACK);break;case R.id.menu3:drawView.paint.setColor(Color.WHITE);break;case R.id.menu4:try {drawView.saveBitmap();} catch (Exception e) {e.printStackTrace();}break;case R.id.menu5:System.exit(0);// 结束程序break;}return true;}}
最后,我上传了一份源码给大家:http://download.csdn.net/detail/yongh701/8900457

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/63291.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Python画图matplotlib库的使用scatter(),plot()方法教学实例

Python画图主要用到matplotlib这个库。scatter和 plot 函数最常用 这个函数几乎可以调节图的一切属性&#xff0c;包括但不限于&#xff1a;坐标范围&#xff0c;axes标签字号大小&#xff0c;xtick,ytick标签字号&#xff0c;图线宽&#xff0c;legend字号等。 具体参数参看官…

绘图神器draw.io(写文必备)

绘图神器draw.io&#xff08;写文必备&#xff09; 前言 大家早上好&#xff0c;我是毛小悠&#xff0c;一个前端开发工程师。 最近发现一个绘图神器&#xff0c;没错&#xff0c;就是标题中的draw.io。免费、开源&#xff0c;功能强大&#xff0c;真的非常适合程序员。 我…

基于Attention的机器翻译模型,论文笔记

论文题目&#xff1a;Neural Machine Translation by Jointly Learning to Align and Translate 论文地址&#xff1a;http://pdfs.semanticscholar.org/071b/16f25117fb6133480c6259227d54fc2a5ea0.pdf GIF来源&#xff1a;https://jalammar.github.io/visualizing-neural-m…

Transformer(四)--实现验证:transformer 机器翻译实践

转载请注明出处&#xff1a;https://blog.csdn.net/nocml/article/details/125711025 本系列传送门&#xff1a; Transformer(一)–论文翻译&#xff1a;Attention Is All You Need 中文版 Transformer(二)–论文理解&#xff1a;transformer 结构详解 Transformer(三)–论文实…

机器翻译之Facebook的CNN与Google的Attention

传统的seq2seqfacebook的cnn 结构特点 position embedding卷积的引入GLU控制信息的流动attention google的attention 结构特点 KVQ的思维架构multi-head attentionattention的多种应用 参考资料 机器翻译的常用架构是seq2seq&#xff0c;可是seq2seq中的核心模型RNN是序列模型…

探索机器翻译:从统计机器翻译到神经机器翻译

❤️觉得内容不错的话&#xff0c;欢迎点赞收藏加关注&#x1f60a;&#x1f60a;&#x1f60a;&#xff0c;后续会继续输入更多优质内容❤️ &#x1f449;有问题欢迎大家加关注私戳或者评论&#xff08;包括但不限于NLP算法相关&#xff0c;linux学习相关&#xff0c;读研读博…

[机器翻译]——pivot-based zero-shot translation based on fairseq

文章目录 前言翻译到en生成"伪"的、到英语的数据文件把每一个zs语言对翻译到en从fairseq-generate生成的文件中&#xff0c;抽取纯en文件 把en数据和所有zs语言对的tgt数据形成平行语料&#xff0c;然后做预处理形成en到tgt的平行语料预处理 在en到tgt语言的"伪…

大语言模型的多语言机器翻译能力分析

来自&#xff1a;南大NLP 进NLP群—>加入NLP交流群 01 研究动机 以ChatGPT为代表的大语言模型&#xff08;Large Language Models, LLM&#xff09;在机器翻译&#xff08;Machine Translation, MT&#xff09;任务上展现出了惊人的潜力。通过情景学习&#xff08;In-Contex…

嗖的一下第二弹,这些好看的皮肤直接一键收下~~

✨前言 &#x1f4e2;首先祝大家假期愉快&#x1f680; 这个假期&#xff0c;大家是怎么玩的呢❓ 小博主我趁着假期也摆了几天&#x1f61c; 因此有好几天没有更新文章了…… 今天偷偷的发一篇文章&#xff0c;浅浅做个样子吧&#x1f62c; 今儿写的文章是继上次写的&#xff…

为什么国内APP热衷于皮肤特效

微博跟腾讯学到了精髓&#xff0c;功能不够皮肤来凑 这不是吐槽呀&#xff0c;是有一定心理学在里面的&#xff0c;人们普遍希望跟身边的人有差异性的&#xff0c;就好像打游戏我买个皮肤在战场上可以秀一下&#xff1b;在游戏中我买个xxx刀&#xff0c;可以打出火花星星等效果…

云炬Android开发教程0 jdk下载与安装教程(小白)

第一步&#xff1a;jdk下载 &#xff08;1&#xff09;oracle官网地址下载&#xff1a;点我进官网下载 &#xff08;2&#xff09;百度云连接下载&#xff08;提供8u211版本&#xff09;&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1i74YGO8zXuGxumZYGakKKw 提取码…

墨墨背单词

墨墨背单词 推荐一款背单词软件&#xff1a;墨墨背单词&#xff08;无限单词版&#xff09; 下载链接&#xff1a;https://download.csdn.net/download/EQ_cyc/12438004

将有道云词典单词本导入到墨墨背单词

有道云词典导出.XML文件用EXCEL导入.XML文件。点击&#xff1a;数据>自其他来源>来自XML数据导入 导入后会提示以下界面&#xff0c;全部点击确定即可 导入数据后变成这样子 每一行的间距可能特别大&#xff0c;不用管直接复制第一列&#xff0c;放到一个新建的txt文件…

墨墨背单词(最新无限单词版---持续更新)

----------2020年5月27日更新---------- 废话不多说先上图 用户可以直接登录账号&#xff0c;由于现在直接注册功能系统会提示更新到最新系统导致无法注册账户&#xff0c;但是可以通过忘记密码的形式来曲线注册账户&#xff0c;方法如下 软件的下载连接为: https://down…

获取墨墨背单词里面的单词书中的单词

首先&#xff0c;其实是直接尝试抓包获取的&#xff0c;不过在抓包的信息中没发现类似的内容&#xff0c;然后就去百度了以下&#xff0c;发现还是有聪明人。 把下载的 apk 文件解压缩一下&#xff0c;把里面的 assets 文件夹里面的 maimemo.v3.db 直接拖到navicat中&#xff…

[小小项目]背单词的程序---1.0_纯C语言_单文件版本

文章目录 前言&#xff1a;可以学到什么&#xff1f;一、功能介绍以及演示二、准备工作1&#xff09;准备所需的单词的文本2&#xff09;任意的C语言开发环境 三、代码1&#xff09;读取文件&#xff0c;不存在则爆出异常2&#xff09;开辟空间来存放读取出来的内容3&#xff0…

android 补签控件,墨墨背单词怎么补签 看完你就懂了

现在手机的普及让不少用户在手机上面学习英语&#xff0c;而墨墨背单词就是一款专业的英语学习软件&#xff0c;它可以提醒用户每日记忆单词&#xff0c;还有督促你学习的签到系统&#xff0c;通过每日的签到不仅可以提高你学习英语的动力还能免费提升每日学习单词的上限量呢。…

未root的情况下获取墨墨背单词的databases文件夹

文章目录 前言解决思路第一步&#xff1a;备份下载Winhex使用abe解压备份文件结语 前言 在我的《墨墨背单词免费版本地数据找回方法》这篇博客中提到&#xff1a;“复制出“databases”文件”。但这个文件夹并不是那么容易复制出的&#xff0c;如果你的手机已经被root了&#…

C语言实现背单词软件(系统级别)

目录 一、软件需求说明书 1 引言 2 任务概述 二、可行性研究报告 1 编写目的 2 所建议的系统&#xff08;技术可行性&#xff09; 3 使用方面的可行性 4 结论 三、系统设计说明书 1.面向对象设计 1.1前提说明 1.2 系统设计 2.面向对象建模 四&#xf…

不背单词vs墨墨背单词 竞品分析

1. 分析背景 1.1 业界状况 根据易观千帆数据中心&#xff0c;2020年4月全网教育APP活跃用户共44597.16万&#xff0c;将近4.5亿&#xff0c;且仍在持续稳定增长&#xff0c;其中在线外语学习赛道坐拥6726.52万活跃用户&#xff0c;占比15%。背单词类软件作为一项外语学习人群…