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

0adf872dc23651bc45622c5a69097500.png

/   今日科技快讯   /

据中国载人航天工程办公室消息,北京时间2022年6月5日10时44分,搭载神舟十四号载人飞船的长征二号F遥十四运载火箭在酒泉卫星发射中心点火发射,约577秒后,神舟十四号载人飞船与火箭成功分离,进入预定轨道,飞行乘组状态良好,发射取得圆满成功。

/   作者简介   /

本篇文章来自Zuo的投稿,文章主要分享了汉字笔顺动画实现的相关内容,相信会对大家有所帮助!同时也感谢作者贡献的精彩文章。

Zuo的博客地址:

https://juejin.cn/user/747323635537159

/   前言   /

本节来实现一个笔顺动画的效果。思路来自开源库 Hanzi Writer,这是它官网的效果:

0e8e4fcfb2cf3f2155dc7461c7bbfaf4.gif

但 Android 不能直接用,也就有了模仿下的想法。我在这个姐妹库里 hanzi-writer-data,找到了它的源数据,是一个 json。

{"strokes": [], "medians": [], "radStrokes": []}

以汉字“我”为例,是这样的,很乱是吧,幸亏我对 SVG 格式有丢丢了解:

fd9b5c7033209c23c10a9ddc52c57d3c.png

其中,SVG 格式都是固定的,每个字母( 不区分大小写) 都有它的含义:

  • M x y:表示移动画笔到(x, y) 点,准备开始绘制

  • L x y:代表 Line to, L 命令将会画一条线段到(x, y)

  • Z:Z 命令会从当前点画一条直线到路径的起点,即闭合路径

  • Q x1 y1, x y:通过一个控制点绘制二阶贝塞尔曲线

  • C x1 y1, x2 y2, x y:通过两个控制点绘制三次贝塞尔曲线到(x, y)

可以看出 strokes 就是这样一个 SVG 数据,至于 medians 和 radStrokes 我们稍后再探,先将 strokes 绘制出来看下效果。

/   正文   /

解析strokes

这步很简单,纯送分题:

  1. 将 hanzi - writer - data 源数据,保存到 assets 目录,或本地路径,都没所谓

  2. 将特定路径下汉字 json 解析出来

这里直接贴下代码吧:

e1ddcf7871696230b34b6e09add96a44.png

绘制strokes

首先就遇到问题,拿到 SVG 数据后,要怎么通过 Canvas 绘制呢?

研究后发现,系统 PathParser 为我们提供好了接口,直接就能办到这件事:

// 可以解析 SVG 数据, 生成绘制所需要的 Path 
    PathParser.createPathFromPathData(String pathData)

代码是这样的,拿到汉字笔画的 path 集合:

a11c935bfc0ea3c863455f3539d0b2a4.png

这样一来,我们就可以直接在 draw(Canvas) 接口中绘制了。

0908fa4298fe9031beac9da94c713192.png

运行,发现并没有正常显示出来。经过排查,是因为 hanzi - writer - data 提供的源数据,绘制出来是上下翻转的,而且大小默认 1024 * 1024 px,所以在绘制的时候,我们需要将 y 轴翻转并等比缩放,来看下代码吧:

8f411da4563eb4185662dfbfdabb68b9.png

再运行,看下效果:

50733ebd8230dd804ae0e752abc1ee97.png

完美。但这是静态的,怎么能像 Hanzi Writer 这样动起来呢?

探究medians

在源数据 json 内的 medians,这是干嘛的?我们将 medians 解析出来,主要代码见下,medians 是解析出来的 path 集合:

f6a0210c88ce2d06bb876e5d1e282681.png

在上文的 draw(Canvas) 方法中绘制出来。

45caaed44831e62a8812638f57995f2a.png

效果见下:

f19d85fff92764b29aa30d27f3389823.png

可以猜测每个 path array 其实就是汉字的一个笔画,为了验证是否正确,我将每个笔画 array 的第一个 point 坐标都点了出来,来看下效果,是这样的。

19f4db5ad178592726fb50f61a2c669e.png

至此,我们应该知道 medians 的含义了。

动起来

现在为止,我们已经知道了每个汉字的笔画和组成笔画的若干骨干点。想动起来,是不是只需要按默认顺序绘制笔画就行了,为了更平滑的效果,我们可以在每个骨干点间进行差值动画。

说干就干,这是属性动画差值:

64f9dbd67f41ca9d92807123efc0e837.png

创建一个 PathMeasure 集合来存储 path,目的是拿到路径长度和截取路径,具体就不在这里展开说了:

e6e9ff0fc1a9b836dd6ff2c319c26531.png

最后根据进度值,在 draw(Canvas) 方法内绘制即可,其中 temp 的作用是将截取出来的路径,保存到 temp 内。

2268d533cee2be56deed61b59917e4c3.png

来看下效果:

bc1b23a84635ad58a8012552ad78c889.gif

ok,笔画已经动起来了。但是我们想要的效果是 Hanzi Writer 那样的,这个明显不达标啊,别急,如果你对 Canvas 图层有了解,我相信,你此时应该有思路了。

笔顺动画

canvas layer 不是本节的重点,如果你还不了解,可以去补下。在这里的思路,就是创建一个图层,在图层上显示 strokes 与 medians 混合后的效果。

29247f40883de4d9632e954bbe8f64f0.png

首先根据进度,绘制进度内的所有 stroke path,生成目标图像 bitmap,这里采用 srcMode,代表只保留源图像。

5e461601ce183bf92c68b38b80dd4c48.png

设置当前画笔 mode 为 PorterDuff.Mode.SRC_IN,表示只在源图像和目标图像相交的地方绘制源图像。

2b5a8fbe7edaceaf620e6d04aa21c0f3.png

接下来,根据进度绘制进度内的所有笔画,即 median path,这里采用 srcMode,代表只保留源图像。

8b2188232abdd173abc3013598630f33.png

最后恢复画布即可:

6701c3878765b06dfdeae9085be3c737.png

来看下效果,是不是很 ok 了。

9ef2ef351f0d3563316e4af59f9a1c18.gif

其实还差点,作为强迫症实在忍受不了,起笔落笔缺失了点..

起笔落笔弧度

作为解决方案,我尝试着在每个笔画的第一个和最后一个骨干点的位置,以其为中心绘制个小圆,因为指向方向不定,圆是个很好的选择,注意要绘制在 srcCanvas。

数据位置,上面已经说了,取 medians 内的每个笔画的第一个点和最后一个点,解析方法就不说了,具体代码去看 demo 吧。

ed899626202719b2859719a3db1bfc26.png

在绘制 srcBmp 时候,将起笔和落笔弧度添加上,注意索引:

713c2946a3a98b6c051dd02ca40b9c97.png

来看下效果,完美:

43b42ed54a4ff43206ae9c48b53cbff4.gif

好了,本节就到到这里了,代码都上传到了 github,感兴趣的可以看下。项目地址如下:

https://github.com/mjzuo/BlogSample

推荐阅读:

我的新书,《第一行代码 第3版》已出版!

一个解决滑动冲突的新思路,无缝嵌套滑动

跟着例子,来整一遍AIDL吧

欢迎关注我的公众号

学习技术或投稿

ceda4323c271ee32d4b58f4da8e20e1e.png

c5534d3ff11cd1961b8b73cea58d4248.png

长按上图,识别图中二维码即可关注

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值