Android Kotlin制作签名白板并保存图片
2023-02-18 16:47:30 时间
学更好的别人,
做更好的自己。
——《微卡智享》
本文长度为899字,预计阅读3分钟
前言
最近的项目中要加一个人员签名的存根,在Android实现一个手写签名的功能,然后签名完成的图像需要保存图片留底,那这篇我们就来做一个手写签名白板的Demo。
实现效果
代码实现
微卡智享
实现手写签名,需要我们自己定义一个SignatureView,继承自View,里面定义画笔和划线的路径,然后重写其onTouchEvent,根据其划线的路径进行画笔操作。
核心代码SignatureView
package dem.vaccae.signnatureview
import android.content.Context
import android.graphics.*
import android.util.AttributeSet
import android.view.MotionEvent
import android.view.View
import androidx.core.view.drawToBitmap
import java.lang.Float.max
import kotlin.math.min
class SignatureView(context: Context?, attrs: AttributeSet?) : View(context, attrs) {
//笔划宽度
private var STROKE_WIDTH = 5f
private var lastTouchX = -1f
private var lastTouchY = -1f
//定义画笔相关
private val paint = Paint()
//定义画笔路径
private val path = Path()
//绘制的矩形区域
private val drawRect = RectF()
//初始化数据
init {
//设置抗锯齿
paint.isAntiAlias = true
//设置画笔颜色
paint.color = Color.BLUE
//设置画笔类型
paint.style = Paint.Style.STROKE
//设置画笔的线冒样式
paint.strokeCap = Paint.Cap.ROUND
//设置画笔连接处样式
paint.strokeJoin = Paint.Join.ROUND
//设置画笔宽度
paint.strokeWidth = STROKE_WIDTH
}
//清除绘制
fun clear(){
path.reset()
postInvalidate()
}
//获取当前页面图片
fun getBitmapFromView():Bitmap{
return drawToBitmap()
}
//设置笔划宽度
fun setPaintStrokeWidth(width:Float){
STROKE_WIDTH = width
paint.strokeWidth = STROKE_WIDTH
}
//设置笔划宽度
fun setPaintColor(color: Int){
paint.color = color
}
//画笔手执处理
override fun onTouchEvent(event: MotionEvent?): Boolean {
event?.let {
val event_x = it.x
val event_y = it.y
when (it.action) {
MotionEvent.ACTION_DOWN -> {
//点击按下时开始记录路径
path.moveTo(event_x, event_y)
//记录最后的X和Y的坐标
lastTouchX = event_x
lastTouchY = event_y
return true
}
MotionEvent.ACTION_MOVE, MotionEvent.ACTION_UP -> {
//计算绘制区域
drawRect.left = min(lastTouchX, event_x)
drawRect.right = max(lastTouchX, event_x)
drawRect.top = min(lastTouchY, event_y)
drawRect.bottom = max(lastTouchY, event_y)
// 当硬件跟踪事件的速度快于事件的交付速度时
// 事件将包含这些跳过点的历史记录
val historySize = it.historySize
(0 until historySize).forEach { i ->
val historicalx = it.getHistoricalX(i)
val historicaly = it.getHistoricalY(i)
if (historicalx < drawRect.left) {
drawRect.left = historicalx
} else if (historicalx > drawRect.right) {
drawRect.right = historicalx
}
if (historicaly < drawRect.top) {
drawRect.top = historicaly
} else if (historicaly > drawRect.bottom) {
drawRect.bottom = historicaly
}
path.lineTo(historicalx, historicaly)
}
// 回放历史记录后,将线路连接到触点。
path.lineTo(event_x, event_y)
}
else -> {
return false
}
}
// 绘制时根据笔画宽度除2用于在中心开妈绘制
postInvalidate(
(drawRect.left - STROKE_WIDTH / 2).toInt(),
(drawRect.top - STROKE_WIDTH / 2).toInt(),
(drawRect.right + STROKE_WIDTH / 2).toInt(),
(drawRect.bottom + STROKE_WIDTH / 2).toInt()
);
lastTouchX = event_x;
lastTouchY = event_y;
}
return super.onTouchEvent(event)
}
override fun onDraw(canvas: Canvas?) {
canvas?.let {
it.drawPath(path, paint)
}
super.onDraw(canvas)
}
}
几个重点
绘制图像时使用postInvalidate,根据定义的划线区域设置
清除画板直接使用path.reset()然后postInvalidate()即可
使用darwToBitmap()可以直接将当前View转出Bitmap
MainActivity中调用
01
xml布局中直接引用SignatureView
<?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">
<dem.vaccae.signnatureview.SignatureView
android:layout_width="match_parent"
android:layout_height="400dp"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent"
android:id="@+id/signatureView" />
<ImageView
android:layout_width="200dp"
android:layout_height="150dp"
android:id="@+id/imgv"
android:layout_marginTop="20dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/signatureView" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnclear"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@id/imgv"
app:layout_constraintEnd_toStartOf="@id/btnSave"
android:text="清除" />
<Button
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:id="@+id/btnSave"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintStart_toEndOf="@id/btnclear"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintTop_toBottomOf="@id/imgv"
android:text="保存图片" />
</androidx.constraintlayout.widget.ConstraintLayout>
02
MainActivity代码
package dem.vaccae.signnatureview
import android.graphics.Color
import androidx.appcompat.app.AppCompatActivity
import android.os.Bundle
import android.widget.ImageView
import android.widget.Toast
import dem.vaccae.signnatureview.databinding.ActivityMainBinding
import kotlin.random.Random
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// setContentView(R.layout.activity_main)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
binding.signatureView.setBackgroundColor(Color.rgb(245,245,245))
binding.btnclear.setOnClickListener {
binding.signatureView.clear()
}
binding.btnSave.setOnClickListener {
val bmp = binding.signatureView.getBitmapFromView()
binding.imgv.scaleType = ImageView.ScaleType.FIT_XY
binding.imgv.setImageBitmap(bmp)
}
}
}
这样一个简单的手写签名板的小Demo就实现了。
完
相关文章
- java制作验证码(java验证码小程序)
- 解决第三方邮箱APP登陆QQ、163邮箱无法验证账户名或密码的问题(IOS、MacOS、Windows、Android)
- Mac电脑运行ios应用PlayCover
- 苹果发布 iOS 16 公开测试版,一起来看看这几项新功能
- 解决 Flutter 引起的 iOS 内存崩溃问题
- iOS 16 中的 Live Text 的更新
- iOS16 中的 3 种新字体宽度样式
- 在 iOS 16 中用 SwiftUI Charts 创建一个折线图
- 在 iOS16 中用 SwiftUI 图表定制一个线图
- Android平台GB28181设备接入端如何支持跨网段语音对讲?
- 基于flask和bootstrap-table的通用数据查询
- 爬虫方案 | 爬取大众点评网评论的几个思路(从小程序端)
- 【黄啊码】如何用小程序实现世界杯参赛队伍投票
- 《Android App开发进阶与项目实战》资源下载和内容勘误
- 微信小程序使用阿里巴巴的矢量图标iconfont
- 微信小程序 点击显示隐藏 极简Tab标签 点击添加class样式
- 微信小程序 wx:if 与 hidden区别
- 微信小程序 CSS border-radius元素 overflow:hidden失效问题 iPhone ios 苹果兼容问题
- 微信小程序 自定义 tabBar案例 官方案例迁入无效解决方法 非 tab 页显示 tabBar的问题解决 自定义tabBar与原生tabBar以及自写伪tabbar的区别
- IOS APPStore 上传更新应用版本 软件