安卓自定义画板

包含功能:

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

 自定义视图组件

package com.zx.drawing_board;import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Path;
import android.net.Uri;
import android.os.Bundle;
import android.os.Parcelable;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.Stack;public class DrawingBoard extends View {// 上下文对象,用于获取资源和应用程序信息public Context context;// 画布对象,用于绘制图形public Canvas canvas;// 画笔对象,用于设置绘制样式和颜色public Paint paint;// 位图对象,用于在其中进行绘制操作public Bitmap bitmap;// 绘制路径对象,记录用户绘制的路径public Path path;// 图片的URI地址public Uri uri;// 图片位图对象,用于加载图片private Bitmap mImageBitmap;// 保存用户绘制路径的栈结构private Stack<Path> paths = new Stack<>();/*** 构造函数,创建一个新的FingerPainterView对象* @param context 上下文对象,用于获取资源和应用程序信息*/public DrawingBoard(Context context) {super(context);// 执行初始化方法init(context);}/*** 构造函数,创建一个新的FingerPainterView对象* @param context 上下文对象,用于获取资源和应用程序信息* @param attrs 属性集合对象,用于获取视图的自定义属性*/public DrawingBoard(Context context, AttributeSet attrs) {super(context, attrs);// 执行初始化方法init(context);}/*** 构造函数,创建一个新的FingerPainterView对象* @param context 上下文对象,用于获取资源和应用程序信息* @param attrs 属性集合对象,用于获取视图的自定义属性* @param defStyle 样式属性,用于设置默认样式*/public DrawingBoard(Context context, AttributeSet attrs, int defStyle) {super(context, attrs, defStyle);// 执行初始化方法init(context);}/*** 获取当前画板的截图* @return 画板的截图*/public Bitmap getScreenshot() {return Bitmap.createBitmap(bitmap);}/*** 初始化方法,设置默认的画笔样式和颜色* @param context 上下文对象,用于获取资源和应用程序信息*/private void init(Context context) {this.context = context;// 创建路径对象和画笔对象path = new Path();paint = new Paint();// 默认的画笔样式和颜色paint.setAntiAlias(true);paint.setStyle(Paint.Style.STROKE);paint.setStrokeJoin(Paint.Join.ROUND);paint.setStrokeWidth(20);paint.setStrokeCap(Paint.Cap.ROUND);paint.setARGB(255,0,0,0);}/*** 设置画笔样式* @param brush 画笔样式*/public void setBrush(Paint.Cap brush) {paint.setStrokeCap(brush);}/*** 获取画笔样式* @return 画笔样式*/public Paint.Cap getBrush() {return paint.getStrokeCap();}/*** 设置画笔宽度* @param width 画笔宽度*/public void setBrushWidth(int width) {paint.setStrokeWidth(width);}/*** 获取画笔宽度* @return 画笔宽度*/public int getBrushWidth() {return (int) paint.getStrokeWidth();}/*** 设置画笔颜色* @param colour 画笔颜色*/public void setColour(int colour) {paint.setColor(colour);}/*** 获取画笔颜色* @return 画笔颜色*/public int getColour() {return paint.getColor();}/*** 加载图片* @param uri 图片的URI地址*/public void load(Uri uri) {this.uri = uri;}/*** 获取图片位图对象* @return 图片位图对象*/public Bitmap getmImageBitmap() {return mImageBitmap;}/*** 设置图片位图对象,并在画布上绘制图片* @param mImageBitmap 图片位图对象*/public void setmImageBitmap(Bitmap mImageBitmap) {this.mImageBitmap = mImageBitmap;canvas.drawColor(Color.WHITE);canvas.drawBitmap(mImageBitmap, 0, 0, paint);}/*** 撤销上一步操作*/public void undo() {if (!paths.isEmpty()) {// 移除最近的路径,并重新绘制位图paths.pop();redrawBitmap();}}/*** 重做上一步撤销的操作*/public void redo() {if (!paths.isEmpty()) {// 将最近撤销的路径重新添加到绘图路径中,并重新绘制位图Path lastPath = paths.peek();paths.push(new Path(lastPath));redrawBitmap();}}/*** 清空所有绘图路径,重新绘制位图*/public void clear() {paths.clear();redrawBitmap();}@Overridepublic Parcelable onSaveInstanceState() {Bundle bundle = new Bundle();// 保存父类视图状态bundle.putParcelable("superState", super.onSaveInstanceState());try {// 将位图保存到临时缓存文件中,以克服Binder事务大小限制File f = File.createTempFile("fingerpaint", ".png", context.getCacheDir());bitmap.compress(Bitmap.CompressFormat.PNG, 100, new FileOutputStream(f));// 将临时文件名保存到bundle中bundle.putString("tempfile", f.getAbsolutePath());} catch(IOException e) {Log.e("FingerPainterView", e.toString());}return bundle;}@Overridepublic void onRestoreInstanceState(Parcelable state) {if (state instanceof Bundle) {Bundle bundle = (Bundle) state;try {// 从bundle中获取缓存文件File f = new File(bundle.getString("tempfile"));Bitmap b = BitmapFactory.decodeStream(new FileInputStream(f));// 需要复制位图以创建可变版本bitmap = b.copy(b.getConfig(), true);b.recycle();f.delete();} catch(IOException e) {Log.e("FingerPainterView", e.toString());}state = bundle.getParcelable("superState");}super.onRestoreInstanceState(state);}@Overrideprotected void onDraw(Canvas canvas) {// 画布是白色的,并在顶部绘制带有alpha通道的位图canvas.drawColor(Color.WHITE);canvas.drawBitmap(bitmap, 0, 0, paint);// 显示当前的绘图路径for (Path p : paths) {canvas.drawPath(p, paint);}canvas.drawPath(path, paint);}@Overrideprotected void onSizeChanged(int w, int h, int oldw, int oldh) {// 在Activity创建后,当视图被膨胀时调用if(bitmap==null) {if(uri!=null) {try {// 尝试加载提供的uri,并进行缩放以适应我们的画布InputStream stream = context.getContentResolver().openInputStream(uri);Bitmap bm = BitmapFactory.decodeStream(stream);bitmap  = Bitmap.createScaledBitmap(bm, Math.max(w, h), Math.max(w, h), false);stream.close();bm.recycle();} catch(IOException e) {Log.e("FingerPainterView", e.toString());}}else {// 创建一个正方形位图,以便即使在旋转到横向时也可绘制bitmap = Bitmap.createBitmap(Math.max(w,h), Math.max(w,h), Bitmap.Config.ARGB_8888);}}canvas = new Canvas(bitmap);}/*** 触摸事件处理方法,用于绘制路径*/@Overridepublic boolean onTouchEvent(MotionEvent event) {float x = event.getX();float y = event.getY();switch (event.getAction()) {case MotionEvent.ACTION_DOWN:// 按下手指时,重置路径并移动到指定位置path.reset();path.moveTo(x, y);path.lineTo(x, y);invalidate();break;case MotionEvent.ACTION_MOVE:// 手指移动时,连线到当前位置path.lineTo(x, y);invalidate();break;case MotionEvent.ACTION_UP:// 手指抬起时,将路径保存,并重置路径paths.push(new Path(path));path.reset();invalidate();break;}return true;}/*** 重新绘制位图,根据当前的绘图路径*/private void redrawBitmap() {bitmap.eraseColor(Color.WHITE);for (Path p : paths) {canvas.drawPath(p, paint);}invalidate();}
}

用法

<?xml version="1.0" encoding="utf-8"?>
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"xmlns:app="http://schemas.android.com/apk/res-auto"xmlns:tools="http://schemas.android.com/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><com.zx.drawing_board.DrawingBoardandroid:id="@+id/fp"android:layout_width="match_parent"android:layout_height="match_parent"/></RelativeLayout>

效果

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

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

相关文章

算法刷题day13

目录 引言一、蜗牛 引言 今天时间有点紧&#xff0c;只搞了一道题目&#xff0c;不过确实搞了三个小时&#xff0c;才搞完&#xff0c;主要是也有点晚了&#xff0c;也好累啊&#xff0c;不过也还是可以的&#xff0c;学了状态DP&#xff0c;把建图和spfa算法熟悉了一下&#…

数据结构——链表 原理及C语言代码实现(可直接运行版)

1.链表 概念&#xff1a;链表是一种物理存储结构上非连续、非顺序的存储结构&#xff0c;数据元素的逻辑顺序是通过链表中的指针链接次序实现的 2.链表的分类 实际中链表的结构非常多样&#xff0c;以下情况组合起来就有8种链表结构&#xff1a; ①单向或者双向 ②带头或者不…

C语言结构体,结构体指针,学了C语言到底有什么用?

#define _CRT_SECURE_NO_WARNINGS 1 #include<stdio.h> struct Stu { char name[20]; //结构体成员名称&#xff0c;数据类型 int age; char sex[10]; char tele[12]; }; void print(struct Stu* ps) //结构体指针 { printf("%s %d %s %s\n&…

2024.2.16每日一题

LeetCode 二叉树的锯齿层序遍历 103. 二叉树的锯齿形层序遍历 - 力扣&#xff08;LeetCode&#xff09; 题目描述 给你二叉树的根节点 root &#xff0c;返回其节点值的 锯齿形层序遍历 。&#xff08;即先从左往右&#xff0c;再从右往左进行下一层遍历&#xff0c;以此类…

【C语言】简单贪吃蛇实现保姆级教学!!!

关注小庄 顿顿解馋૮(˶ᵔ ᵕ ᵔ˶)ა 新年快乐呀小伙伴 引言&#xff1a; 小伙伴们应该都有一个做游戏的梦吧&#xff1f;今天让小庄来用C语言简单实现一下我们的童年邪典贪吃蛇&#xff0c;顺便巩固我们的C语言知识&#xff0c;请安心食用~ 文章目录 贪吃蛇效果一.游戏前工作…

[嵌入式系统-16]:RT-Thread -2- 主要功能功能组件详解与API函数说明

目录 一、RT-Thread主要功能组件 二、内核组件 2.1 概述 2.2 API 三、设备驱动 3.1 概述 3.2 API 四、通信组件 4.1 概述 4.4 API 五、网络组件 5.1 概述 5.2 API 5.3 补充&#xff1a;MQTT协议 六、文件系统 6.1 概述 6.2 API 七、GUI 组件 7.1 概述 7.2 …

165基于matlab的各类滤波器

基于matlab的各类滤波器。汉宁窗设计Ⅰ型数字高通滤波器、切比雪夫一致逼近法设计FIR数字低通滤波器、模拟Butterworth滤波器设计数字低通滤波器、频域抽样法的FIR数字带阻滤波器设计、频域抽样法的FIR数字带通滤波器设计、汉宁窗的FIR数字高通滤波器设计、双线性法设计巴特沃斯…

各版本安卓的彩蛋一览

目录 前言前彩蛋纪Android 2.3 GingerbreadAndroid 3 HoneycombAndroid 4.0 Ice Cream SandwichAndroid 4.1-4.3 JellybeanAndroid 4.4 KitKatAndroid 5 LollipopAndroid 6 MarshmallowAndroid 7 NougatAndroid 8 OreoAndroid 9 PieAndroid 10 Queen CakeAndroid 11 Red Velvet…

备战蓝桥杯---图论之最短路dijkstra算法

目录 先分个类吧&#xff1a; 1.对于有向无环图&#xff0c;我们直接拓扑排序&#xff0c;和AOE网类似&#xff0c;把取max改成min即可。 2.边权全部相等&#xff0c;直接BFS即可 3.单源点最短路 从一个点出发&#xff0c;到达其他顶点的最短路长度。 Dijkstra算法&#x…

STM32CubeMX的下载和安装固件库详细步骤

年也过了&#xff0c;节也过了&#xff0c;接下来又要进入紧张的学习中来了。过完年后发现一个问题&#xff0c;就是我之前吃的降压药不太管用&#xff0c;每天的血压只降到了91/140左右&#xff0c;没有到安全范围内&#xff0c;从初三开始换了一种降压药&#xff0c;效果出奇…

【JAVA-Day86】守护线程

守护线程 守护线程摘要引言1. 了解守护线程&#xff1a;它是什么&#xff1f;&#x1f47b;特点和用途示例代码 2. 为何我们需要守护线程&#xff1f;&#x1f47b;辅助性任务处理不阻止程序的正常运行重要的清理工作示例代码&#x1f4da; 3. 如何创建和管理守护线程&#xff…

【51单片机】利用STC-ISP软件工具【定时器计算器】配置【定时器】教程(详细图示)(AT89C52)

前言 大家好吖&#xff0c;欢迎来到 YY 滴单片机系列 &#xff0c;热烈欢迎&#xff01; 本章主要内容面向接触过单片机的老铁 主要内容含&#xff1a; 欢迎订阅 YY滴C专栏&#xff01;更多干货持续更新&#xff01;以下是传送门&#xff01; YY的《C》专栏YY的《C11》专栏YY的…