Android图片涂鸦,Kotlin(1)

Android图片涂鸦,Kotlin(1)

 

import android.content.Context
import android.graphics.Canvas
import android.graphics.Color
import android.graphics.Paint
import android.graphics.Path
import android.graphics.PointF
import android.util.AttributeSet
import android.util.Log
import android.view.MotionEvent
import androidx.appcompat.widget.AppCompatImageViewclass PaintView @JvmOverloads constructor(context: Context?,attrs: AttributeSet? = null,defStyleAttr: Int = 0
) : AppCompatImageView(context!!, attrs, defStyleAttr) {class DrawPath {var id: Long = 0Lvar path: Path? = nullvar paint: Paint? = nullvar points = ArrayList<PointF>()}private var mPaint: Paint? = nullprivate var mPath: Path? = nullprivate var mDownX = 0fprivate var mDownY = 0fprivate var mTempX = 0fprivate var mTempY = 0f//默认的画笔宽度private var mPaintWidth = 10//默认画笔的颜色private var mColor = Color.REDprivate val mDrawPathList: ArrayList<DrawPath>?private val mSavePathList: ArrayList<DrawPath>?companion object {var WIDTH_INCREMENT = 15const val TAG = "PaintView"}init {mDrawPathList = ArrayList()mSavePathList = ArrayList()initPaint()}private fun initPaint() {mPaint = Paint()mPaint?.color = mColormPaint?.isAntiAlias = truemPaint?.strokeWidth = mPaintWidth.toFloat()mPaint?.style = Paint.Style.STROKE}override fun onDraw(canvas: Canvas) {super.onDraw(canvas)if (!mDrawPathList.isNullOrEmpty()) {for (drawPath in mDrawPathList) {if (drawPath.path != null) {canvas.drawPath(drawPath.path!!, drawPath.paint!!)}drawPath.points.forEach {Log.d(TAG, "onDraw ${drawPath.id} ${it.x} ${it.y}")}}}}override fun onTouchEvent(event: MotionEvent): Boolean {when (event.action) {MotionEvent.ACTION_DOWN -> {Log.d(TAG, "ACTION_DOWN ${event.x} ${event.y}")mDownX = event.xmDownY = event.y//每次手指点下去作为一条新路径。mPath = Path()mPath?.moveTo(mDownX, mDownY)val drawPath = DrawPath()drawPath.id = System.currentTimeMillis()drawPath.paint = mPaintdrawPath.path = mPathmDrawPathList?.add(drawPath)//新一轮绘制开始,保存点。drawPath.points.add(PointF(event.x, event.y))invalidate()mTempX = mDownXmTempY = mDownY}MotionEvent.ACTION_MOVE -> {//Log.d(TAG, "ACTION_MOVE ${event.x} ${event.y}")val moveX = event.xval moveY = event.ymPath?.quadTo(mTempX, mTempY, moveX, moveY)mDrawPathList?.filter {it.path == mPath}?.forEach {it.points.add(PointF(event.x, event.y))}invalidate()mTempX = moveXmTempY = moveY}//每次手指抬起重置画笔,不然画笔会保存之前设置的属性会引起bug。MotionEvent.ACTION_UP -> {Log.d(TAG, "ACTION_UP ${event.x} ${event.y}")initPaint()}}return true}/*** 撤销。*/fun undo() {if (mDrawPathList != null && mDrawPathList.size >= 1) {mSavePathList?.add(mDrawPathList[mDrawPathList.size - 1])mDrawPathList.removeAt(mDrawPathList.size - 1)invalidate()}}/*** 反撤销,重新生效。*/fun reundo() {if (!mSavePathList.isNullOrEmpty()) {mDrawPathList?.add(mSavePathList[mSavePathList.size - 1])mSavePathList.removeAt(mSavePathList.size - 1)invalidate()}}/*** 画笔颜色。** @param color*/fun setPaintColor(color: Int) {this.mColor = colormPaint?.color = this.mColor}/*** 画笔的宽度。*/fun setPaintWidth(size: Int) {mPaintWidth += sizemPaint?.strokeWidth = mPaintWidth.toFloat()}/*** 放大,改变画笔的宽度。线条变粗。*/fun enlargePaintWidth() {mPaintWidth += WIDTH_INCREMENTmPaint?.strokeWidth = mPaintWidth.toFloat()}fun getDrawPath(): ArrayList<DrawPath>? {return mDrawPathList}
}

 

 

<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.ConstraintLayout 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.pkg1115.PaintViewandroid:id="@+id/paint_view"android:layout_width="match_parent"android:layout_height="match_parent"android:scaleType="fitCenter"android:src="@mipmap/p1"app:layout_constraintBottom_toBottomOf="parent"app:layout_constraintEnd_toEndOf="parent"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent" /><RelativeLayoutandroid:id="@+id/rl_left"android:layout_width="100dp"android:layout_height="wrap_content"app:layout_constraintStart_toStartOf="parent"app:layout_constraintTop_toTopOf="parent"><Buttonandroid:id="@+id/btn_undo"android:layout_width="match_parent"android:layout_height="60dp"android:text="撤销" /><Buttonandroid:id="@+id/btn_red"android:layout_width="match_parent"android:layout_height="60dp"android:layout_below="@id/btn_undo"android:text="红色" /><Buttonandroid:id="@+id/btn_green"android:layout_width="match_parent"android:layout_height="60dp"android:layout_below="@id/btn_red"android:text="绿色" /><Buttonandroid:id="@+id/btn_enlarge"android:layout_width="match_parent"android:layout_height="60dp"android:layout_below="@id/btn_green"android:text="放大" /></RelativeLayout></androidx.constraintlayout.widget.ConstraintLayout>

 

 

 

 

 

Android图形图像处理:添加涂鸦文字_android 在图片上涂鸦-CSDN博客文章浏览阅读2k次。先看运行效果: 关键的PaintView:package com.zhangphil;import android.content.Context;import android.graphics.Canvas;import android.graphics.Color;import android.graphics.Paint;import android.graph..._android 在图片上涂鸦https://blog.csdn.net/zhangphil/article/details/87810653

 

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

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

相关文章

用GPT 搭建一个占星术、解梦、塔罗牌占卜和命理学服务

今天来尝试我们的占星术、解梦、塔罗牌占卜和命理学服务&#xff0c;揭开宇宙的奥秘并获得自我认识 聊天 GPT API 集成的 HTML5 模板。我们的目标是提供易于使用且高度可定制的 API 代码&#xff0c;使您能够训练自己的人工智能解决方案并将其添加到提示中。 我们的产品是可定…

蓝桥杯每日一题2023.11.19

题目描述 “蓝桥杯”练习系统 (lanqiao.cn) 题目分析 首先想到的方法为dfs去寻找每一个数&#xff0c;但发现会有超时 #include<bits/stdc.h> using namespace std; const int N 2e5 10; int n, cnt, a[N]; void dfs(int dep, int sum, int start) {if(dep 4){if(s…

数据结构:红黑树的插入实现(C++)

个人主页 &#xff1a; 个人主页 个人专栏 &#xff1a; 《数据结构》 《C语言》《C》《Linux》 文章目录 一、红黑树二、红黑树的插入三、代码实现总结 一、红黑树 红黑树的概念&#xff1a; 红黑树是一颗二叉搜索树&#xff0c;但在每个节点上增加一个存储位表示节点的颜色&…

redis三种集群方式

redis有三种集群方式&#xff1a;主从复制&#xff0c;哨兵模式和集群。 1.主从复制 主从复制原理&#xff1a; 从服务器连接主服务器&#xff0c;发送SYNC命令&#xff1b; 主服务器接收到SYNC命名后&#xff0c;开始执行BGSAVE命令生成RDB文件并使用缓冲区记录此后执行的所…

【Java 进阶篇】JQuery 事件绑定之事件切换:让页面动起来

欢迎来到这个充满动感的 JQuery 事件绑定之旅&#xff01;在这篇博客中&#xff0c;我们将深入研究 JQuery 中的事件切换&#xff0c;让你的页面焕发出活力和互动。无论你是前端小白还是有一定经验的开发者&#xff0c;相信这篇文章都会对你有所帮助。 走进事件切换的奇妙世界…

【NI-DAQmx入门】校准

1.设备定期校准的理由 随着时间的推移电子器件的特性会发生自然漂移&#xff0c;可能会导致测量结果的不准确性。防止出现良品和差品筛选出错的情况满足行业国际标准降低设备出现故障的风险使测量结果更具备参考性 2.查找NI设备的校准间隔。 定期校准会使DAQ设备的精度保持在…

电路的基本原理

文章目录 一、算数逻辑单元(ALU)1、功能2、组成 二、电路基本知识1、逻辑运算2、复合逻辑 三、加法器实现1、一位加法器2、串行加法器3、并行加法器 一、算数逻辑单元(ALU) 1、功能 算术运算&#xff1a;加、减、乘、除等 逻辑运算&#xff1a;与、或、非、异或等 辅助功能&am…

设计模式常见面试题

简单梳理下二十三种设计模式&#xff0c;在使用设计模式的时候&#xff0c;不仅要对其分类了然于胸&#xff0c;还要了解每个设计模式的应用场景、设计与实现&#xff0c;以及其优缺点。同时&#xff0c;还要能区分功能相近的设计模式&#xff0c;避免出现误用的情况。 什么是…

Linux 零拷贝splice函数

Linux splice 函数简介 splice 是 Linux 系统中用于在两个文件描述符之间移动数据的系统调用。它的主要作用是在两个文件描述符之间传输数据&#xff0c;而无需在用户空间进行数据拷贝。也是零拷贝操作. 函数原型 #include <fcntl.h> ssize_t splice(int fd_in, loff_…

【Go入门】 Go搭建一个Web服务器

【Go入门】 Go搭建一个Web服务器 前面小节已经介绍了Web是基于http协议的一个服务&#xff0c;Go语言里面提供了一个完善的net/http包&#xff0c;通过http包可以很方便的搭建起来一个可以运行的Web服务。同时使用这个包能很简单地对Web的路由&#xff0c;静态文件&#xff0c…

mac控制台命令小技巧

shigen日更文章的博客写手&#xff0c;擅长Java、python、vue、shell等编程语言和各种应用程序、脚本的开发。记录成长&#xff0c;分享认知&#xff0c;留住感动。 hello伙伴们&#xff0c;作为忠实的mac骨灰级别的粉丝&#xff0c;它真的给我带来了很多效率上的提升。那作为接…

python-opencv 培训课程笔记(2)

python-opencv 培训课程笔记&#xff08;2&#xff09; 1.图像格式转换 先看一下cvtColor函数的例子 #默认加载彩图 pathrD:\learn\photo\cv\cat.jpg# imread(path,way) #way0 灰度图。way1 彩图 #默认彩图 imgcv2.imread(path) img_dogcv2.imread(path_dog) #图片格式的转化…