????????笔者用ArkTS 写了一个简单的带笔锋的手写板应用,并且可以将手写内容保存为图片。
????????手写效果如下(在鸿蒙手机模拟器上运行,手写时反应可能会有点慢)
参考文章:
支持笔锋效果的手写签字控件_android 写字板如何兼容笔峰-CSDN博客
主要代码:
????????核心思想在于通过插值,在两点之间逐渐绘制多个椭圆,从而呈现出笔锋的效果。
??drawLine
方法是一段用于在2D渲染画布上绘制线条并赋予其笔锋效果的代码。
????????在代码中,curDis
用于计算起始点和结束点之间的欧几里德距离。steps
根据距离计算出线条上需要绘制的点的数量。deltaX
, deltaY
, deltaW
分别表示 x 坐标、y 坐标和宽度每一步的增量。
????????通过 for
循环,在两点之间进行插值,绘制多个椭圆,以模拟笔锋效果。每一步循环中,创建一个椭圆对象 (oval
),并设置其位置调用 oval
方法绘制椭圆。
????????最后,更新坐标和宽度的增量,为绘制下一个椭圆做准备。
/**
* 绘制线条方法,实现笔锋效果
* @param canvas 2D 渲染上下文对象
* @param x0 起始点 x 坐标
* @param y0 起始点 y 坐标
* @param w0 起始点宽度
* @param x1 结束点 x 坐标
* @param y1 结束点 y 坐标
* @param w1 结束点宽度
*/
private drawLine(canvas: CanvasRenderingContext2D, x0: number, y0: number, w0: number, x1: number, y1: number, w1: number): void {
// 计算两点之间的欧几里德距离
const curDis: number = Math.hypot(x0 - x1, y0 - y1);
let steps: number;
// 根据距离计算步数
steps = 1 + Math.floor(curDis / 2);
// 计算每一步的增量
let deltaX: number = (x1 - x0) / steps;
let deltaY: number = (y1 - y0) / steps;
let deltaW: number = (w1 - w0) / steps;
let x: number = x0;
let y: number = y0;
let w: number = w0;
// 根据步数循环绘制椭圆
for (let i = 0; i < steps; i++) {
// 创建椭圆对象
const oval: MyRect = new MyRect();
const top: number = y - w / 2.0;
const left: number = x - w / 4.0;
const right: number = x + w / 4.0;
const bottom: number = y + w / 2.0;
// 设置椭圆的位置
oval.set(left, top, right, bottom);
// 调用绘制椭圆的方法
this.oval(canvas, oval);
// 更新坐标和宽度增量
x += deltaX;
y += deltaY;
w += deltaW;
}
}
????????绘制椭圆的方法,在安卓中可以用canvas.drawOval()方法,在HarmonyOS中需要通过canvas.ellipse()方法来实现:
/**
* 绘制椭圆的方法
* @param canvas 渲染画布
* @param roundedCircleBox 圆角矩形的边界框
*/
private oval(canvas: CanvasRenderingContext2D, roundedCircleBox: MyRect): void {
// 开始新的路径
canvas.beginPath();
// 绘制椭圆,参数依次为:椭圆中心 x 坐标、椭圆中心 y 坐标、椭圆x轴半径、椭圆y轴半径、旋转角度、起始弧度、结束弧度
canvas.ellipse(
roundedCircleBox.left + (roundedCircleBox.right - roundedCircleBox.left) / 2,
roundedCircleBox.top + (roundedCircleBox.bottom - roundedCircleBox.top) / 2,
(roundedCircleBox.right - roundedCircleBox.left) / 2,
(roundedCircleBox.bottom - roundedCircleBox.top) / 2,
0, // 旋转角度为 0,表示不旋转
0, // 起始弧度为 0
2 * Math.PI); // 结束弧度为 2π,表示绘制整个椭圆
// 填充椭圆
canvas.fill();
// 关闭路径
canvas.closePath();
}