当前位置: 首页 > news >正文

在Android上实现汉字笔顺动画效果——HanZiWriter

序,万般皆是命,半点不由人。

Hanzi Writer 是 javascript 免费开源库,根据汉字书写时按照笔画顺序的特征,可以播放正确笔画顺序的描边动画和练习测试。支持简体字和繁体字。可以让全球用户能够通过手绘模仿的方式来学习和练习书写汉字。

特点
  • 丰富性: 包含9000+个常用汉字的笔画数据,覆盖广泛。
  • 准确性: 笔画轨迹详细且精准,模拟真实书写体验。
  • 开放源代码: 全面免费,可自由使用和扩展,鼓励社区参与和贡献。
  • 易用性: 提供简洁的JSON格式数据,易于集成到各类开发环境中。
  • 跨平台兼容: 数据基于SVG标准,能在多种设备和浏览器上无缝运行。
  • 体积小:Hanzi Writer 库仅仅 30 kb (压缩后仅 9kb!), 所以添加它不会使网页体积增大。
  • 用处广泛:Hanzi Writer 使用 javascript, HTML5 and SVG, 所以它几乎能嵌入到任何平台应用, iOS 应用、安卓应用、桌面端应用和网页。

在Android中使用,我使用的是加载WebView。

写一个html的引用地址,在定义几个和我们安卓交互的方法。

<!DOCTYPE html>
<html>
<head><meta charset="utf-8"><title>Hanzi Writer</title><script src="file:///android_asset/js/hanzi-writer3.js"></script><script src="file:///android_asset/js/polyfill.min.js"></script><style>body, html {margin: 0;padding: 0;width: 100%;height: 100%;display: flex;justify-content: center;align-items: center;background-color: rgba(0, 0, 0, 0);}#target {width: 300px;height: 300px;}</style>
</head>
<body>
<div id="target"></div>
<script>let writer;function clearCharacter() {// 如果已存在 writer 实例,则删除if (writer) {writer.cancelQuiz(); // 取消正在进行的测试(如果有)writer.setCharacter(''); // 将汉字设置为空document.getElementById('target').innerHTML = ''; // 清空目标区域writer = null; // 将 writer 实例置为 null}}function loadCharacter(character,wide,height) {clearCharacter()writer = HanziWriter.create('target', character, {width: 300,height: 300,showOutline: true,showCharacter: false,drawingColor:'#168F16',drawingWidth:30,});}function startQuiz() {if (writer) {writer.quiz({onMistake: function(strokeData) {AndroidInterface.onMistake(JSON.stringify(strokeData));},onCorrectStroke: function(strokeData) {AndroidInterface.onCorrectStroke(JSON.stringify(strokeData));},onComplete: function(summaryData) {AndroidInterface.onComplete(JSON.stringify(summaryData));}});}}function getSVG() {if (writer) {const path = writer.getPath();const svg = path.toSVG();AndroidInterface.showSVG(svg);}}function init() {loadCharacter('');}window.onload = init;// 新增函数,用于从Android接收汉字function receiveCharacterFromAndroid(character) {loadCharacter(character);}</script>
</body>
</html>

在Android中调用

        webView.setLayerType(View.LAYER_TYPE_SOFTWARE, null);webView.loadUrl( "file:///android_asset/hanziwriter1.html")webView.postDelayed({Log.i("AAAA","加载汉字----")loadCharacterFromAndroid("慕")webView.evaluateJavascript("startQuiz()", null)}, 500)

Js回调。

    private class JavaScriptInterface(private val context: Context) {@JavascriptInterfacefun onMistake(data: String) {Log.i("AAAAA","onMistake: $data")val jsonObject = JSONObject(data)val character = jsonObject.getString("character")val drawPath = jsonObject.getString("drawnPath") //使用 drawPath对比圈画区域是否重叠val jsonPath = JSONObject(drawPath)val pathString = jsonPath.getString("pathString")val strPoint = StringBuilder()jsonPath.getJSONArray("points").let {for (i in 0 until it.length()) {val jsonObject = it.getJSONObject(i)val x = jsonObject.getDouble("x")val y = jsonObject.getDouble("y")strPoint.append("$x,$y ")}}val totalMistakes = jsonObject.getInt("totalMistakes")val strokeNum = jsonObject.getInt("strokeNum") + totalMistakesval mistakesOnStroke = jsonObject.getInt("mistakesOnStroke")val strokesRemaining = jsonObject.getInt("strokesRemaining")uiThread {if (context is MainActivity) {context.takeBitmap()context.updateTextView("当前汉字:$character, 一共写了${strokeNum}笔, 错误笔顺${totalMistakes}笔, 剩余笔顺${strokesRemaining}笔")context.drawSVGImage(pathString, strPoint.toString())}}}@JavascriptInterfacefun onCorrectStroke(data: String) {Log.i("AAAAA","-onCorrectStroke: $data")val jsonObject = JSONObject(data)val character = jsonObject.getString("character")val drawPath = jsonObject.getString("drawnPath")//使用 drawnPath对比圈画区域是否重叠val jsonPath = JSONObject(drawPath)val pathString = jsonPath.getString("pathString")val strPoint = StringBuilder()jsonPath.getJSONArray("points").let {for (i in 0 until it.length()) {val jsonObject = it.getJSONObject(i)val x = jsonObject.getDouble("x")val y = jsonObject.getDouble("y")strPoint.append("$x,$y,")}}val totalMistakes = jsonObject.getInt("totalMistakes")val strokeNum = jsonObject.getInt("strokeNum") + totalMistakesval mistakesOnStroke = jsonObject.getInt("mistakesOnStroke")val strokesRemaining = jsonObject.getInt("strokesRemaining")uiThread {if (context is MainActivity) {context.takeBitmap()context.updateTextView("当前汉字:$character, 一共写了${strokeNum}笔, 错误笔顺${totalMistakes}笔, 剩余笔顺${strokesRemaining}笔")context.drawSVGImage(pathString, strPoint.toString())}}}@JavascriptInterfacefun onComplete(data: String) {Log.i("AAAAA","onComplete: $data")val jsonObject = JSONObject(data)val character = jsonObject.getString("character")if (context is MainActivity) {context.updateTextView("当前汉字:$character, 笔顺完成")}}}

HanziWriter官方API

1.创建新HanziWriter实例需要传入目标 div(ID 或 DOM 引用)、要呈现的字符以及配置选项。下面是一个简单的示例。在 Javascript 中:

     function loadCharacter(character) {clearCharacter()writer = HanziWriter.create('target', character, {width: 300,height: 300,showOutline: true,showCharacter: false,drawingColor:'#168F80',drawingWidth:30,});writer.quiz({onMistake: function(strokeData) {AndroidInterface.onMistake(JSON.stringify(strokeData));},onCorrectStroke: function(strokeData) {AndroidInterface.onCorrectStroke(JSON.stringify(strokeData));},onComplete: function(summaryData) {AndroidInterface.onComplete(JSON.stringify(summaryData));}});}

可以看到一下结果

2.创建 HanziWriter 实例后,您可以通过调用 animateCharacter()方法为其设置动画。

 function animateCharacter() {if (writer) {writer.animateCharacter({AndroidInterface.start());});}}

3.除了动画和测验的核心功能外,还有其他几种方法可用于控制角色的渲染。

writer.setCharacter(newCharacter) 加载新角色并重新渲染。
writer.showCharacter() 如果角色当前处于隐藏状态,则显示该角色
writer.hideCharacter() 如果当前显示该角色,则隐藏该角色
writer.showOutline() 如果字符轮廓当前处于隐藏状态,则显示该轮廓
writer.hideOutline() 如果当前显示字符轮廓,则隐藏它
writer.updateColor(colorName, newValue) 更改任意颜色选项的值。例如:writer.updateColor('strokeColor', '#AA12CD')
writer.cancelQuiz() 立即取消当前正在进行的测验

4.options包含其他配置选项的对象。可用的完整选项包括:

showOutline:布尔值,默认为 true。控制在第一次渲染时是否显示或隐藏轮廓。
showCharacter:布尔值,默认为 true。控制在第一次渲染时是否显示或隐藏字符。
width:数字。画布的宽度(以 px 为单位)。
height:数字。画布的高度(以 px 为单位)。
padding:数字,默认值为 20。字符和画布边缘之间的填充(单位为 px)。
strokeAnimationSpeed:数字,默认为 1。绘制每个笔触的速度必须大于 0。增加此数字可加快绘制笔触的速度,减少此数字可减慢绘制笔触的速度。
strokeHighlightSpeed:数字,默认为 2。在测验中给出提示时突出显示每个笔画的速度必须大于 0。增加此数字可加快突出显示速度,减少此数字可减慢突出显示速度。
strokeFadeDuration:数字,默认为 400。调用和隐藏笔画之间的转换时间(以毫秒为单位writer.show())writer.hide()
delayBetweenStrokes:数字,默认为 1000。动画时每次描边之间的时间(以毫秒为单位)。
delayBetweenLoops:数字,默认为 2000。循环动画时,每个动画循环之间的时间(以毫秒为单位)。
strokeColor:十六进制字符串,默认为“#555”。绘制每条笔画的颜色。
radicalColor:十六进制字符串,默认为 null。如果存在部首数据,则在笔画中绘制部首的颜色。如果未设置,部首将以与其他笔画相同的颜色绘制。
highlightColor:十六进制字符串,默认为“#AAF”。测验中用于突出显示的颜色。
outlineColor:十六进制字符串,默认为“#DDD”。字符轮廓的颜色。
drawingColor:十六进制字符串,默认为 '#333'。用户在测验期间绘制的线条的颜色。
drawingWidth:数字,默认4。用户在答题时绘制的线条宽度,单位为px。
showHintAfterMisses:整数,默认为 3。在向用户提供笔画高亮提示之前未完成的次数。设置为 false 以禁用。创建测验时也可以设置此项。
markStrokeCorrectAfterMisses:整数,默认禁用。强制将笔画标记为正确之前的未命中次数。这也可以在创建测验时设置。
quizStartStrokeNum:整数,默认为 0。可将此设置为从第一个笔划以外的笔划开始测验。也可在创建测验时设置。
acceptBackwardsStrokes:布尔值,默认 false。允许在测验期间向后绘制笔画。这也可以在创建测验时设置。
highlightOnComplete:布尔值,默认为 true。控制测验在用户完成绘制整个角色时是否短暂突出显示该角色。这也可以在创建测验时设置。
highlightCompleteColor:十六进制字符串,默认为 null。在测验中突出显示完成的字符时使用的颜色。如果未设置,highlightColor则将改为使用。仅当 时才highlightOnComplete相关true。
charDataLoader:函数。自定义函数用于加载字符数据。有关用法的更多信息,请参阅“加载字符数据”部分。
onLoadCharDataSuccess:函数。角色数据加载成功时的回调。此函数使用已加载的数据进行调用。这可用于实现加载微调器。
onLoadCharDataError:函数。字符数据加载失败时的回调。无论失败原因是什么,都会从charDataLoader传递此函数。
renderer:字符串,默认为“svg”。将其设置为“canvas”以使用 2d 画布而不是 SVG 进行渲染。在某些设备上可能会有更好的性能。

附上我的githubdemo地址。

PS:HanziWriter地址

github地址

 

相关文章:

在Android上实现汉字笔顺动画效果——HanZiWriter

序&#xff0c;万般皆是命&#xff0c;半点不由人。 Hanzi Writer 是 javascript 免费开源库&#xff0c;根据汉字书写时按照笔画顺序的特征&#xff0c;可以播放正确笔画顺序的描边动画和练习测试。支持简体字和繁体字。可以让全球用户能够通过手绘模仿的方式来学习和练习书写…...

黑马头条vue2.0项目实战(一)——项目初始化

1. 图标素材&#xff08;iconfont简介&#xff09; 制作字体图标的工具有很多&#xff0c;推荐使用&#xff1a;iconfont-阿里巴巴矢量图标库。 注册账户 创建项目 可以根据项目自定义 class 前缀 上传图标到项目 生成链接&#xff0c;复制 css 代码&#xff0c;在项目中使用…...

Unity Shader动画:用代码绘制动态视觉效果

在Unity中&#xff0c;Shader是运行在GPU上的小程序&#xff0c;用于控制顶点和像素的渲染过程。通过编写自定义Shader&#xff0c;开发者可以创造出各种令人惊叹的动画效果&#xff0c;从简单的颜色变化到复杂的流体模拟。本文将探讨如何使用Unity Shader来实现动画效果。 Sh…...

智税集成2.0生成凭证

:::info &#x1f4a1; 整体业务流程 从A9服务器中取数&#xff0c;生成列表数据&#xff0c;写入到对方oracle数据库中。 ::: 项目关键点 1.连接数据库 左连接连接本地SQLserver数据库、右连接要链接A9开票服务器的数据库然后设想用SQLserver 自带的外部连接来连接oracle数据…...

B4005 [GESP202406 四级] 黑白方块 【暴力枚举】【前缀和】

#include<bits/stdc.h> using namespace std; int n,m,ans,tmp; char mp[20][20]; int cheak(int a,int b,int c,int d){//a<c b<dint cnt0;//枚举矩阵中的每个点 for(int ia;i<c;i)for(int jb;j<d;j)if(mp[i][j]1) cnt;//统计黑格的个数 return 2*cnt(c-a1…...

深度学习趋同性的量化探索:以多模态学习与联合嵌入为例

深度学习趋同性的量化探索&#xff1a;以多模态学习与联合嵌入为例 参考文献 据说是2024年最好的人工智能论文&#xff0c;是否有划时代的意义&#xff1f; [2405.07987] The Platonic Representation Hypothesis (arxiv.org) ​arxiv.org/abs/2405.07987 趋同性的量化表达 …...

决策树与随机森林:比较与应用场景分析

决策树与随机森林&#xff1a;比较与应用场景分析 引言 决策树和随机森林是机器学习中广泛使用的两种算法&#xff0c;因其简单性和强大的功能而被广泛采用。决策树是一种树形结构的决策模型&#xff0c;易于理解和解释。随机森林则是通过集成多棵决策树来提高预测性能的模型…...

C#用Aspose.Cells导出Excel,.NET导出Excel

ASP.NET MVC 控制器里面Action处理&#xff0c;下载文件&#xff0c;输出文件流 public async Task<ActionResult> ExportNewsAuthorFee(string deptId, DateTime? startDate, DateTime? endDate){if (startDate null){startDate DateTime.Parse(DateTime.Now.Year …...

天猫番茄品类TOP1,复购率超40%,「一颗大」如何策划极致产品力?

桔子要买什么品牌&#xff1f;桃子买什么品牌&#xff1f;土豆买什么品牌&#xff1f;过去人们购买农产品几乎没有品牌意识。但近年来可能某些人买猕猴桃时会考虑佳沛&#xff0c;这是一个在全球达到30%猕猴桃市场的新西兰品牌。与此类似&#xff0c;一个国产品牌「一颗大™」正…...

Docker搭建私有仓库harbor(docker 镜像仓库搭建)

Harbor介绍 Docker容器应用的开发和运行离不开可靠的镜像管理&#xff0c;虽然Docker官方也提供了公共的镜像仓库&#xff0c;但是从安全和效率等方面考虑&#xff0c;部署我们私有环境内的Registry也是非常必要的。Harbor是由VMware公司开源的企业级的Docker Registry管理项目…...

面试题:MySQL 索引

1. 谈一下你对于MySQL索引的理解?(为什么MySQL要选择B+树来存储索引) MySQL的索引选择B+树作为数据结构来进行存储,使用B+树的本质原因在于可以减少IO次数,提高查询的效率,简单来说就是可以保证在树的高度不变的情况下存储更多的数据: IO效率的提高:在MySQL数据库中,…...

云计算day13

一、Git 概述 Git 是一种分布式版本控制系统&#xff0c;用于跟踪和管理代码的变更。它是由 Linus Torvalds 创建的&#xff0c;最初被设计用于 Linux 内核的开发。Git 允许开发 人员跟踪和管理代码的版本&#xff0c;并且可以在不同的开发人员之间进行协作。 Github 用的就…...

2024年孝感中级职称报名开始了吗?

2024年孝感中级职称申报终于开始了&#xff0c;之前参加过水测的小伙伴们&#xff0c;开始准备评审了 2024年孝感本批次申报时间&#xff1a;中级、初级职称网上申报时间:2024年8月1日至8月31日。 注意&#xff1a;个人通过“湖北省职称评审管理信息系统”申报&#xff0c;须先…...

RAG技术之Router

Router有什么用&#xff1f; 在RAG应用中&#xff0c;Router可以帮助我们基于用户的查询意图来决定使用何种数据类型或数据源&#xff0c;比如是否需要进行语义检索、是否需要进行text2sql查询&#xff0c;是否需要用function call来进行API调用。 Router也可以根据用户的查询…...

linux系统通过修改sudo文件使普通用户拥有类似root用户权限

说明&#xff1a;普通用户要想拥有root权限&#xff0c;如果不在sudo文件里配置就算把该用户加到wheel组&#xff08;root用户所在的组&#xff09;也不行。 要想通过在命令前加上sudo使得该用户以root权限执行命令&#xff0c;需要修改/etc/sudoers文件。 &#xff08;如果通…...

基于PyCharm在Windows系统上远程连接Linux服务器中Docker容器进行Python项目开发与部署

文章目录 摘要项目结构项目开发项目上线参考文章 摘要 本文介绍了如何在Windows 10系统上使用PyCharm专业版2024.1&#xff0c;通过Docker容器在阿里云CentOS 7.9服务器上进行Python项目的开发和生产部署。文章详细阐述了项目结构的搭建、PyCharm的使用技巧、以及如何将开发项…...

TypeScript学习篇-类型介绍使用、ts相关面试题

文章目录 基础知识基础类型: number, string, boolean, object, array, undefined, void(代表该函数没有返回值)enum(枚举): 定义一个可枚举的对象typeinterface联合类型: |交叉类型: &any 类型null 和 undefinednullundefined never类型 面试题及实战1. 你觉得使用ts的好处…...

超详细!Jmeter性能测试

前言 性能测试是一个全栈工程师/架构师必会的技能之一&#xff0c;只有学会性能测试&#xff0c;才能根据得到的测试报告进行分析&#xff0c;找到系统性能的瓶颈所在&#xff0c;而这也是优化架构设计中重要的依据。 测试流程&#xff1a; 需求分析→环境搭建→测试计划→脚…...

C语言经典习题24

文件操作习题 一 编程删除从C盘home文件夹下data.txt文本文件中所读取字符串中指定的字符&#xff0c;该指定字符由键盘输入&#xff0c;并将修改后的字符串以追加方式写入到文本文件C:\home\data.txt中。 #include<stdio.h> main() { char s[100],ch; int i;…...

SQL labs-SQL注入(三,sqlmap使用)

本文仅作为学习参考使用&#xff0c;本文作者对任何使用本文进行渗透攻击破坏不负任何责任。 引言&#xff1a; 盲注简述&#xff1a;是在没有回显得情况下采用的注入方式&#xff0c;分为布尔盲注和时间盲注。 布尔盲注&#xff1a;布尔仅有两种形式&#xff0c;ture&#…...

Java如何权衡是使用无序的数组还是有序的数组

在 Java 中,选择有序数组还是无序数组取决于具体场景的性能需求与操作特点。以下是关键权衡因素及决策指南: ⚖️ 核心权衡维度 维度有序数组无序数组查询性能二分查找 O(log n) ✅线性扫描 O(n) ❌插入/删除需移位维护顺序 O(n) ❌直接操作尾部 O(1) ✅内存开销与无序数组相…...

【论文笔记】若干矿井粉尘检测算法概述

总的来说&#xff0c;传统机器学习、传统机器学习与深度学习的结合、LSTM等算法所需要的数据集来源于矿井传感器测量的粉尘浓度&#xff0c;通过建立回归模型来预测未来矿井的粉尘浓度。传统机器学习算法性能易受数据中极端值的影响。YOLO等计算机视觉算法所需要的数据集来源于…...

Android15默认授权浮窗权限

我们经常有那种需求&#xff0c;客户需要定制的apk集成在ROM中&#xff0c;并且默认授予其【显示在其他应用的上层】权限&#xff0c;也就是我们常说的浮窗权限&#xff0c;那么我们就可以通过以下方法在wms、ams等系统服务的systemReady()方法中调用即可实现预置应用默认授权浮…...

Map相关知识

数据结构 二叉树 二叉树&#xff0c;顾名思义&#xff0c;每个节点最多有两个“叉”&#xff0c;也就是两个子节点&#xff0c;分别是左子 节点和右子节点。不过&#xff0c;二叉树并不要求每个节点都有两个子节点&#xff0c;有的节点只 有左子节点&#xff0c;有的节点只有…...

Maven 概述、安装、配置、仓库、私服详解

目录 1、Maven 概述 1.1 Maven 的定义 1.2 Maven 解决的问题 1.3 Maven 的核心特性与优势 2、Maven 安装 2.1 下载 Maven 2.2 安装配置 Maven 2.3 测试安装 2.4 修改 Maven 本地仓库的默认路径 3、Maven 配置 3.1 配置本地仓库 3.2 配置 JDK 3.3 IDEA 配置本地 Ma…...

Java线上CPU飙高问题排查全指南

一、引言 在Java应用的线上运行环境中&#xff0c;CPU飙高是一个常见且棘手的性能问题。当系统出现CPU飙高时&#xff0c;通常会导致应用响应缓慢&#xff0c;甚至服务不可用&#xff0c;严重影响用户体验和业务运行。因此&#xff0c;掌握一套科学有效的CPU飙高问题排查方法&…...

七、数据库的完整性

七、数据库的完整性 主要内容 7.1 数据库的完整性概述 7.2 实体完整性 7.3 参照完整性 7.4 用户定义的完整性 7.5 触发器 7.6 SQL Server中数据库完整性的实现 7.7 小结 7.1 数据库的完整性概述 数据库完整性的含义 正确性 指数据的合法性 有效性 指数据是否属于所定…...

Linux nano命令的基本使用

参考资料 GNU nanoを使いこなすnano基础 目录 一. 简介二. 文件打开2.1 普通方式打开文件2.2 只读方式打开文件 三. 文件查看3.1 打开文件时&#xff0c;显示行号3.2 翻页查看 四. 文件编辑4.1 Ctrl K 复制 和 Ctrl U 粘贴4.2 Alt/Esc U 撤回 五. 文件保存与退出5.1 Ctrl …...

基于Java+VUE+MariaDB实现(Web)仿小米商城

仿小米商城 环境安装 nodejs maven JDK11 运行 mvn clean install -DskipTestscd adminmvn spring-boot:runcd ../webmvn spring-boot:runcd ../xiaomi-store-admin-vuenpm installnpm run servecd ../xiaomi-store-vuenpm installnpm run serve 注意&#xff1a;运行前…...

解析“道作为序位生成器”的核心原理

解析“道作为序位生成器”的核心原理 以下完整展开道函数的零点调控机制&#xff0c;重点解析"道作为序位生成器"的核心原理与实现框架&#xff1a; 一、道函数的零点调控机制 1. 道作为序位生成器 道在认知坐标系$(x_{\text{物}}, y_{\text{意}}, z_{\text{文}}…...