Android 繪圖白板元件,有畫筆和板擦的功能 (转)
package com.example.drawboard; import java.util.ArrayList;
import java.util.List;
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.graphics.Rect;
import android.util.AttributeSet;
import android.view.MotionEvent;
import android.view.View; public class DrawBoardView extends View { //定義防止線條有鋸齒的常數
private static final boolean GESTURE_RENDERING_ANTIALIAS = true;
private static final boolean DITHER_FLAG = true; // 底圖 bitmap
private Bitmap mBackgroundBitmap = null;
// View 的整個長寬範圍
private Rect mWholeRect; private Bitmap mBitmap = null; // 圖層繪圖
private Canvas mCanvas = null; // 圖層畫布
private Paint mDefaultPaint = new Paint(); // 空白畫筆 private boolean mCapturing = true; // 是否擷取狀態 //定義繪圖的基本參數:線的 width, color
private float mPaintWidth = 5f;
private int mPaintColor = Color.RED; private int mPenMode = 1; //1:為畫筆, 0:為板擦
private Paint mPaint; private Path mPath; private List<Path> mDrawList = new ArrayList<Path>();
private List<Paint> mPaintsList = new ArrayList<Paint>();
private List<Rect> mRectsList = new ArrayList<Rect>();
private int mTotalAction = 0; // 記錄動作的次數 private float mCurveStartX, mCurveStartY; // 按下的點
private float mX, mY; // 移動的點
private float mCurveEndX, mCurveEndY; // 放開的點 private final Rect mInvalidRect = new Rect();
private int mInvalidateExtraBorder = 10; // 建構子
public DrawBoardView(Context context) {
super(context);
init(context);
} // 建構子
public DrawBoardView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
} // 建構子
public DrawBoardView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
init(context);
} // 初始化
private void init(Context context) {
setWillNotDraw(false);
} private void setPaint(Paint thePaint) {
if (mPenMode != 0) {
thePaint.setStrokeWidth(mPaintWidth);
thePaint.setColor(mPaintColor);
thePaint.setStyle(Paint.Style.STROKE);
thePaint.setStrokeJoin(Paint.Join.ROUND);
thePaint.setStrokeCap(Paint.Cap.ROUND);
thePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
thePaint.setDither(DITHER_FLAG);
thePaint.setXfermode(null);
} else { // 橡皮檫模式,先以黑色顯示範圍
thePaint.setStrokeWidth(mPaintWidth);
thePaint.setColor(Color.BLACK);
thePaint.setAntiAlias(GESTURE_RENDERING_ANTIALIAS);
thePaint.setDither(DITHER_FLAG);
thePaint.setXfermode(null);
}
} @Override
protected void onSizeChanged(int w, int h, int oldw, int oldh) {
this.mWholeRect = new Rect(0, 0, w, h); mBitmap = null;
mCanvas = null;
mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); super.onSizeChanged(w, h, oldw, oldh);
} @Override
protected void onDraw(Canvas canvas) {
if (mBackgroundBitmap != null) mCanvas.drawBitmap(mBackgroundBitmap, null, this.mWholeRect, null); for (int i = 0; i < mTotalAction; i++) {
mCanvas.drawPath(mDrawList.get(i), mPaintsList.get(i));
} if (mPath != null && mPaint != null) mCanvas.drawPath(mPath, mPaint); canvas.drawBitmap(mBitmap, 0, 0, mDefaultPaint);
} @Override
public boolean onTouchEvent(MotionEvent event) {
switch (event.getAction()) {
case MotionEvent.ACTION_DOWN:
mCapturing = true;
mPaint = new Paint();
setPaint(mPaint); mPath = new Path(); touchDown(event);
invalidate(); return true; case MotionEvent.ACTION_MOVE:
if (mCapturing) {
Rect rect = touchMove(event);
if (rect != null) {
invalidate(rect);
}
} return true; case MotionEvent.ACTION_UP:
touchUp(event);
invalidate(); mCapturing = false; // 先清除已復原的動作
int totalAction = mDrawList.size();
while (totalAction > mTotalAction) {
totalAction -= 1;
mPaintsList.remove(totalAction);
mRectsList.remove(totalAction);
mDrawList.remove(totalAction);
} // 再加入新的動作
mTotalAction += 1; if (mPenMode == 0) {
mBitmap = null;
mCanvas = null;
mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); // 橡皮擦屬性
mPaint.setColor(Color.TRANSPARENT);
mPaint.setXfermode(new PorterDuffXfermode(PorterDuff.Mode.CLEAR));
}
mPaintsList.add(mPaint); mDrawList.add(mPath); mPaint = null;
mPath = null; return true;
} return false;
} private void touchDown(MotionEvent event) {
float x = event.getX();
float y = event.getY(); mCurveStartX = x;
mCurveStartY = y;
mX = x;
mY = y;
mCurveEndX = x;
mCurveEndY = y; mPath.moveTo(x, y); final int border = mInvalidateExtraBorder;
mInvalidRect.set((int) x - border, (int) y - border, (int) x + border, (int) y + border);
} private Rect touchMove(MotionEvent event) {
Rect areaToRefresh = null; final float x = event.getX();
final float y = event.getY(); final float previousX = mX;
final float previousY = mY; areaToRefresh = mInvalidRect; // start with the curve end
final int border = mInvalidateExtraBorder;
areaToRefresh.set((int) mCurveEndX - border, (int) mCurveEndY - border,
(int) mCurveEndX + border, (int) mCurveEndY + border); float cX = mCurveEndX = (x + previousX) / 2;
float cY = mCurveEndY = (y + previousY) / 2; mPath.quadTo(previousX, previousY, cX, cY); // union with the control point of the new curve
areaToRefresh.union((int) previousX - border, (int) previousY - border,
(int) previousX + border, (int) previousY + border); // union with the end point of the new curve
areaToRefresh.union((int) cX - border, (int) cY - border, (int) cX
+ border, (int) cY + border); mX = x;
mY = y; return areaToRefresh;
} private void touchUp(MotionEvent event) {
float x = event.getX();
float y = event.getY(); mCurveEndX = x;
mCurveEndY = y;
} /**
* 復原上一動作
* return: false 表不能再undo; true 表能繼續undo
*/
public boolean undo() {
int totalAction = mDrawList.size();
if (mTotalAction > 0) {
mTotalAction -= 1; mBitmap = null;
mCanvas = null;
mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); invalidate();
} if (totalAction == 0 || mTotalAction <= 0) {
return false;
} else {
return true;
}
} /**
* 取消復原動作
* return: false 表不能再 reUndo; true 表能繼續 reUndo
*/
public boolean reUndo() {
int totalAction = mDrawList.size();
if (mTotalAction < totalAction) {
mTotalAction += 1; mBitmap = null;
mCanvas = null;
mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); invalidate();
} if (totalAction == 0 || mTotalAction >= totalAction) {
return false;
} else {
return true;
}
} /**
* 檢查可復原動作的狀態
* return: 0 表不能再 undo,也不能再 reUndo;1 表不能再 undo,但可再 reUndo;2 表可再 undo,但不能再 reUndo;3 表可再 undo,也可再 reUndo;
*/
public int checkUndoStatus() {
int totalAction = mDrawList.size();
int result = 0; if (totalAction == 0) { //沒有任何動作資訊
result = 0;
} else if (mTotalAction <= 0) { //有動作資訊,但已「復原」至最前端
result = 1;
} else if (mTotalAction >= totalAction) { //有動作資訊,但已「取消復原」至最後端
result = 2;
} else {
result = 3;
} return result;
} /**
* 清除整個 View 的畫面
*/
public void clear() {
mBackgroundBitmap = null; mDrawList.removeAll(mDrawList);
mPaintsList.removeAll(mPaintsList);
mRectsList.removeAll(mRectsList);
mTotalAction = 0; mBitmap = null;
mCanvas = null;
mBitmap = Bitmap.createBitmap(this.mWholeRect.width(), this.mWholeRect.height(), Bitmap.Config.ARGB_8888);
mCanvas = new Canvas(mBitmap); invalidate();
} /**
* 設定整個 View 的畫面圖示
*/
public void setWholeViewBitmap(Bitmap bitmap) {
mBackgroundBitmap = bitmap;
invalidate();
} /**
* 設定為畫筆或板擦
* @param penMode: 1 為畫筆, 0 為板擦
*/
public void setPenMode(int penMode) {
if (penMode == 0) {
this.mPenMode = 0;
} else {
this.mPenMode = 1;
}
} /**
* 取得是畫筆或板擦
* @return: 1 為畫筆, 0 為板擦
*/
public int getPenMode() {
return this.mPenMode;
} /**
* 設定畫筆或板擦的寬度
* @param width
*/
public void setPaintStrokeWidth(float width) {
this.mPaintWidth = width;
} /**
* 取得畫筆或板擦的寬度
*/
public float getPaintStrokeWidth() {
return this.mPaintWidth;
} /**
* 設定畫筆的顏色
* @param width
*/
public void setPaintColor(int color) {
this.mPaintColor = color;
} /**
* 取得畫筆的顏色
*/
public int getPaintColor() {
return this.mPaintColor;
} }
Android 的繪圖白板元件(View)。 可當作一般的 View 元件使用。 setWholeViewBitmap(Bitmap bitmap):設定整個 View 的畫面圖示 setPenMode(int penMode):設定為畫筆或板擦 setPaintStrokeWidth(float width):設定畫筆或板擦的寬度 setPaintColor(int color):設定畫筆的顏色,话不多说自己看吧~可以直接复制代码就可以用。
Android 繪圖白板元件,有畫筆和板擦的功能 (转)的更多相关文章
- [R] 繪圖 Par 函数
本篇內文主引用 https://zhuanlan.zhihu.com/p/21394945 之內容再稍加整理並參照下方有用資源 [rdocumentation] https://www.rdocume ...
- Android消息推送(二)--基于MQTT协议实现的推送功能
国内的Android设备,不能稳定的使用Google GCM(Google Cloud Messageing)消息推送服务. 1. 国内的Android设备,基本上从操作系统底层开始就去掉了Googl ...
- Android特效专辑(十二)——仿支付宝咻一咻功能实现波纹扩散特效,精细小巧的View
Android特效专辑(十二)--仿支付宝咻一咻功能实现波纹扩散特效,精细小巧的View 先来看看这个效果 这是我的在Only上添加的效果,说实话,Only现在都还只是半成品,台面都上不了,怪自己技术 ...
- [Android中级]使用Commons-net-ftp来实现FTP上传、下载的功能
本文属于学习分享,如有雷同纯属巧合 利用业余时间.学习一些实用的东西,假设手又有点贱的话.最好还是自己也跟着敲起来. 在android上能够通过自带的ftp组件来完毕各种功能.这次是由于项目中看到用了 ...
- Android中脱离WebView使用WebSocket实现群聊和推送功能
WebSocket是Web2.0时代的新产物,用于弥补HTTP协议的某些不足,不过他们之间真实的关系是兄弟关系,都是对socket的进一步封装,其目前最直观的表现就是服务器推送和聊天功能.更多知识参考 ...
- Android应用如何监听自己是否被卸载及卸载反馈功能的实现
一个应用被用户卸载肯定是有理由的,而开发者却未必能得知这一重要的理由,毕竟用户很少会主动反馈建议,多半就是用得不爽就卸,如果能在被卸载后获取到用户的一些反馈,那对开发者进一步改进应用是非常有利的.目前 ...
- android EditText长按屏蔽ActionMode context菜单但保留选择工具功能
最近项目要求屏蔽EditText 长按出来的ActionMode菜单,但是要保留选择文本功能.这个屏蔽百度会出现各种方法,这里说一下我的思路: 1.屏蔽百度可知setCustomSelectionAc ...
- Android 高仿UC浏览器监控剪切板弹出悬浮窗功能
UC浏览器应该是android手机里 最流行的浏览器之一了,他们有一个功能 相信大家都体验过,就是如果你复制了什么文字,(在其他app中 复制也有这个效果!,所以能猜到肯定是监控了剪切板),就会弹出一 ...
- Android网络:开发浏览器(一)——基本的浏览网页功能开发
我们定义这个版本为1.0版本. 首先,因为要制作一个浏览器,那么就不能通过调用内置浏览器来实现网页的浏览功能,但是可以使用WebView组件来进行. 在此之前,我们可以来看看两种网页显示方式: ...
随机推荐
- 【Visual Studio】“rc.exe”已退出,代码为 5 ("rc.exe" exited with code 5.)
[解决方案]找到 rc.exe 所在目录,然后 方法1:添加该目录到 VC++ Directories --> Executable Directories中 方法2:添加到系统变量中的Path ...
- python之wxPython菜单使用详解
import wx APP_EXIT=1 #定义一个控件ID class Example(wx.Frame): def __init__(self, parent, id, title): super ...
- JMeter特殊情况二:针对某些请求数据每次请求都是变化的情况
概要:某些post请求,例如,登录的请求除了有我们再页面上需要输入的一些值(用户名.密码.是否记住密码等)之外,还有其他的参数,例如token等等,而且这些参数不固定,也就是说每一次post请求这些参 ...
- 10.1综合强化刷题 Day3 afternoon
竞赛时间:????年??月??日??:??-??:?? 题目名称 a b c 名称 a b c 输入 a.in b.in c.in 输出 a.out b.out c.out 每个测试点时限 1s 1s ...
- codevs——2853 方格游戏(棋盘DP)
时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 题目描述 Description 菜菜看到了一个游戏,叫做方格游戏~ 游戏规则是这样的: 在一个n*n的 ...
- luogu P3376 【模板】网络最大流(no)ek
题目描述 如题,给出一个网络图,以及其源点和汇点,求出其网络最大流. 输入输出格式 输入格式: 第一行包含四个正整数N.M.S.T,分别表示点的个数.有向边的个数.源点序号.汇点序号. 接下来M行每行 ...
- 2016北京集训测试赛(十)Problem A: azelso
Solution 我们把遇到一个旗子或者是遇到一个敌人称为一个事件. 这一题思路的巧妙之处在于我们要用\(f[i]\)表示从\(i\)这个事件一直走到终点这段路程中, \(i\)到\(i + 1\)这 ...
- PHP如何在页面中原样输出HTML代码
字符串与HTML之间的相互转换主要应用htmlentities()函数来完成. header("Content-Type: text/html; charset=utf-8"); ...
- git——简易指南
Git对于我来说,只知道是一个版本控制器,类似于乌龟的svn.其中也仅仅会几个常的命令,比如说“更新git pull”.“提交git push”等等,因为记得当初使用的时候,师傅告诉我,对于你不懂这个 ...
- {dede:sql}标签的用法
sql标签可以称得上是个万能标签了,查询数据库将其输出,这里介绍一些关于这个标签的用法: 1.用来输出统计内容,这个是不错的,举个例子,我们来统计下总共发了多少的文章,思路就是输出dede_addon ...