当前位置:   article > 正文

安卓自定义画板

安卓自定义画板

包含功能:

包含  获取当前画板的截图、设置画笔样式、获取画笔样式、设置画笔宽度、获取画笔宽度、设置画笔颜色、获取画笔颜色、加载图片、获取图片位图对象、设置图片位图对象,并在画布上绘制图片、撤销上一步操作、重做上一步撤销的操作、清空所有绘图路径,重新绘制位图

 自定义视图组件

  1. package com.zx.drawing_board;
  2. import android.content.Context;
  3. import android.graphics.Bitmap;
  4. import android.graphics.BitmapFactory;
  5. import android.graphics.Canvas;
  6. import android.graphics.Color;
  7. import android.graphics.Paint;
  8. import android.graphics.Path;
  9. import android.net.Uri;
  10. import android.os.Bundle;
  11. import android.os.Parcelable;
  12. import android.util.AttributeSet;
  13. import android.util.Log;
  14. import android.view.MotionEvent;
  15. import android.view.View;
  16. import java.io.File;
  17. import java.io.FileInputStream;
  18. import java.io.FileOutputStream;
  19. import java.io.IOException;
  20. import java.io.InputStream;
  21. import java.util.Stack;
  22. public class DrawingBoard extends View {
  23. // 上下文对象,用于获取资源和应用程序信息
  24. public Context context;
  25. // 画布对象,用于绘制图形
  26. public Canvas canvas;
  27. // 画笔对象,用于设置绘制样式和颜色
  28. public Paint paint;
  29. // 位图对象,用于在其中进行绘制操作
  30. public Bitmap bitmap;
  31. // 绘制路径对象,记录用户绘制的路径
  32. public Path path;
  33. // 图片的URI地址
  34. public Uri uri;
  35. // 图片位图对象,用于加载图片
  36. private Bitmap mImageBitmap;
  37. // 保存用户绘制路径的栈结构
  38. private Stack<Path> paths = new Stack<>();
  39. /**
  40. * 构造函数,创建一个新的FingerPainterView对象
  41. * @param context 上下文对象,用于获取资源和应用程序信息
  42. */
  43. public DrawingBoard(Context context) {
  44. super(context);
  45. // 执行初始化方法
  46. init(context);
  47. }
  48. /**
  49. * 构造函数,创建一个新的FingerPainterView对象
  50. * @param context 上下文对象,用于获取资源和应用程序信息
  51. * @param attrs 属性集合对象,用于获取视图的自定义属性
  52. */
  53. public DrawingBoard(Context context, AttributeSet attrs) {
  54. super(context, attrs);
  55. // 执行初始化方法
  56. init(context);
  57. }
  58. /**
  59. * 构造函数,创建一个新的FingerPainterView对象
  60. * @param context 上下文对象,用于获取资源和应用程序信息
  61. * @param attrs 属性集合对象,用于获取视图的自定义属性
  62. * @param defStyle 样式属性,用于设置默认样式
  63. */
  64. public DrawingBoard(Context context, AttributeSet attrs, int defStyle) {
  65. super(context, attrs, defStyle);
  66. // 执行初始化方法
  67. init(context);
  68. }
  69. /**
  70. * 获取当前画板的截图
  71. * @return 画板的截图
  72. */
  73. public Bitmap getScreenshot() {
  74. return Bitmap.createBitmap(bitmap);
  75. }
  76. /**
  77. * 初始化方法,设置默认的画笔样式和颜色
  78. * @param context 上下文对象,用于获取资源和应用程序信息
  79. */
  80. private void init(Context context) {
  81. this.context = context;
  82. // 创建路径对象和画笔对象
  83. path = new Path();
  84. paint = new Paint();
  85. // 默认的画笔样式和颜色
  86. paint.setAntiAlias(true);
  87. paint.setStyle(Paint.Style.STROKE);
  88. paint.setStrokeJoin(Paint.Join.ROUND);
  89. paint.setStrokeWidth(20);
  90. paint.setStrokeCap(Paint.Cap.ROUND);
  91. paint.setARGB(255,0,0,0);
  92. }
  93. /**
  94. * 设置画笔样式
  95. * @param brush 画笔样式
  96. */
  97. public void setBrush(Paint.Cap brush) {
  98. paint.setStrokeCap(brush);
  99. }
  100. /**
  101. * 获取画笔样式
  102. * @return 画笔样式
  103. */
  104. public Paint.Cap getBrush() {
  105. return paint.getStrokeCap();
  106. }
  107. /**
  108. * 设置画笔宽度
  109. * @param width 画笔宽度
  110. */
  111. public void setBrushWidth(int width) {
  112. paint.setStrokeWidth(width);
  113. }
  114. /**
  115. * 获取画笔宽度
  116. * @return 画笔宽度
  117. */
  118. public int getBrushWidth() {
  119. return (int) paint.getStrokeWidth();
  120. }
  121. /**
  122. * 设置画笔颜色
  123. * @param colour 画笔颜色
  124. */
  125. public void setColour(int colour) {
  126. paint.setColor(colour);
  127. }
  128. /**
  129. * 获取画笔颜色
  130. * @return 画笔颜色
  131. */
  132. public int getColour() {
  133. return paint.getColor();
  134. }
  135. /**
  136. * 加载图片
  137. * @param uri 图片的URI地址
  138. */
  139. public void load(Uri uri) {
  140. this.uri = uri;
  141. }
  142. /**
  143. * 获取图片位图对象
  144. * @return 图片位图对象
  145. */
  146. public Bitmap getmImageBitmap() {
  147. return mImageBitmap;
  148. }
  149. /**
  150. * 设置图片位图对象,并在画布上绘制图片
  151. * @param mImageBitmap 图片位图对象
  152. */
  153. public void setmImageBitmap(Bitmap mImageBitmap) {
  154. this.mImageBitmap = mImageBitmap;
  155. canvas.drawColor(Color.WHITE);
  156. canvas.drawBitmap(mImageBitmap, 0, 0, paint);
  157. }
  158. /**
  159. * 撤销上一步操作
  160. */
  161. public void undo() {
  162. if (!paths.isEmpty()) {
  163. // 移除最近的路径,并重新绘制位图
  164. paths.pop();
  165. redrawBitmap();
  166. }
  167. }
  168. /**
  169. * 重做上一步撤销的操作
  170. */
  171. public void redo() {
  172. if (!paths.isEmpty()) {
  173. // 将最近撤销的路径重新添加到绘图路径中,并重新绘制位图
  174. Path lastPath = paths.peek();
  175. paths.push(new Path(lastPath));
  176. redrawBitmap();
  177. }
  178. }
  179. /**
  180. * 清空所有绘图路径,重新绘制位图
  181. */
  182. public void clear() {
  183. paths.clear();
  184. redrawBitmap();
  185. }
  186. @Override
  187. public Parcelable onSaveInstanceState() {
  188. Bundle bundle = new Bundle();
  189. // 保存父类视图状态
  190. bundle.putParcelable("superState", super.onSaveInstanceState());
  191. try {
  192. // 将位图保存到临时缓存文件中,以克服Binder事务大小限制
  193. File f = File.createTempFile("fingerpaint", ".png", context.getCacheDir());
  194. bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(f));
  195. // 将临时文件名保存到bundle中
  196. bundle.putString("tempfile", f.getAbsolutePath());
  197. } catch(IOException e) {
  198. Log.e("FingerPainterView", e.toString());
  199. }
  200. return bundle;
  201. }
  202. @Override
  203. public void onRestoreInstanceState(Parcelable state) {
  204. if (state instanceof Bundle) {
  205. Bundle bundle = (Bundle) state;
  206. try {
  207. // 从bundle中获取缓存文件
  208. File f = new File(bundle.getString("tempfile"));
  209. Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));
  210. // 需要复制位图以创建可变版本
  211. bitmap = b.copy(b.getConfig(), true);
  212. b.recycle();
  213. f.delete();
  214. } catch(IOException e) {
  215. Log.e("FingerPainterView", e.toString());
  216. }
  217. state = bundle.getParcelable("superState");
  218. }
  219. super.onRestoreInstanceState(state);
  220. }
  221. @Override
  222. protected void onDraw(Canvas canvas) {
  223. // 画布是白色的,并在顶部绘制带有alpha通道的位图
  224. canvas.drawColor(Color.WHITE);
  225. canvas.drawBitmap(bitmap, 0, 0, paint);
  226. // 显示当前的绘图路径
  227. for (Path p : paths) {
  228. canvas.drawPath(p, paint);
  229. }
  230. canvas.drawPath(path, paint);
  231. }
  232. @Override
  233. protected void onSizeChanged(int w, int h, int oldw, int oldh) {
  234. // 在Activity创建后,当视图被膨胀时调用
  235. if(bitmap==null) {
  236. if(uri!=null) {
  237. try {
  238. // 尝试加载提供的uri,并进行缩放以适应我们的画布
  239. InputStream stream = context.getContentResolver().openInputStream(uri);
  240. Bitmap bm = BitmapFactory.decodeStream(stream);
  241. bitmap = Bitmap.createScaledBitmap(bm, Math.max(w, h), Math.max(w, h), false);
  242. stream.close();
  243. bm.recycle();
  244. } catch(IOException e) {
  245. Log.e("FingerPainterView", e.toString());
  246. }
  247. }
  248. else {
  249. // 创建一个正方形位图,以便即使在旋转到横向时也可绘制
  250. bitmap = Bitmap.createBitmap(Math.max(w,h), Math.max(w,h), Bitmap.Config.ARGB_8888);
  251. }
  252. }
  253. canvas = new Canvas(bitmap);
  254. }
  255. /**
  256. * 触摸事件处理方法,用于绘制路径
  257. */
  258. @Override
  259. public boolean onTouchEvent(MotionEvent event) {
  260. float x = event.getX();
  261. float y = event.getY();
  262. switch (event.getAction()) {
  263. case MotionEvent.ACTION_DOWN:
  264. // 按下手指时,重置路径并移动到指定位置
  265. path.reset();
  266. path.moveTo(x, y);
  267. path.lineTo(x, y);
  268. invalidate();
  269. break;
  270. case MotionEvent.ACTION_MOVE:
  271. // 手指移动时,连线到当前位置
  272. path.lineTo(x, y);
  273. invalidate();
  274. break;
  275. case MotionEvent.ACTION_UP:
  276. // 手指抬起时,将路径保存,并重置路径
  277. paths.push(new Path(path));
  278. path.reset();
  279. invalidate();
  280. break;
  281. }
  282. return true;
  283. }
  284. /**
  285. * 重新绘制位图,根据当前的绘图路径
  286. */
  287. private void redrawBitmap() {
  288. bitmap.eraseColor(Color.WHITE);
  289. for (Path p : paths) {
  290. canvas.drawPath(p, paint);
  291. }
  292. invalidate();
  293. }
  294. }

用法

  1. <?xml version="1.0" encoding="utf-8"?>
  2. <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
  3. xmlns:app="http://schemas.android.com/apk/res-auto"
  4. xmlns:tools="http://schemas.android.com/tools"
  5. android:layout_width="match_parent"
  6. android:layout_height="match_parent"
  7. tools:context=".MainActivity">
  8. <com.zx.drawing_board.DrawingBoard
  9. android:id="@+id/fp"
  10. android:layout_width="match_parent"
  11. android:layout_height="match_parent"/>
  12. </RelativeLayout>

效果

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小丑西瓜9/article/detail/92138
推荐阅读
相关标签
  

闽ICP备14008679号