鸿蒙Next上获取输入框的内容,居然能卡我一整天
“按下按钮时获取输入框的内容”,这种HelloWorld级的需求,十年老工程师花了一天都没搞定,ArkUI这东西,真是给人用的?
前言
最近工作中需要开发一点ArkUI的代码,直接进入正题,给大家看看ArkUI实现这么简单的需求到底有多费劲。
插曲
在编写本文的过程中,意外发现我的 Pura70ProPlus 居然连不上电脑,换了三台电脑,换了N个USB口,换了N条数据线,最终发现反复连接/断开/连接/断开,网上一搜发现不止我一个这样。
此时,一位潜在的鸿蒙开发巨星陨落了
那我们用无线调试吧!
然后发现,hdc命令的help里,居然没有连接到无线调试的命令???
1 | hdc --help 2>&1 | findstr tconn |
此时,一位潜在的鸿蒙开发巨星又一次陨落了
最终在一些野生文档里终于找到了命令:hdc tconn 192.168.3.126:38633
,成功开启鸿蒙之旅。
简单绘制一下界面,舒服了。
getText
API?查无此人!
上述的绘制涉及两个组件,分别叫 TextInput
和 Button
,都是非常通俗易懂的东西。
1 | build() { |
Button
的点击事件可以轻松完成,虽然我还没有将 TextInput
对象绑定到变量上,但应该能获得到这个对象,我们翻一下 TextInput
的官方指南吧~
https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V5/arkts-common-components-text-input-V5 , emmmmm,只提供了onChange和onSubmit的回调函数。
onChange
?性能爆炸!
根据我长期的开发经验,onChange是只要有字符变化就触发一次回调,假设输入了"1234567890",会连续触发10次该函数,绝大部分情况下是不建议这么干的。
但毕竟是官方文档,万一是我想错了呢?
1 | TextInput() |
emmm,我可以将 string 写入到全局变量里、在Button按下时读取全局变量,但肯定不该是这样的,这样频繁地读写 string 造成内存拷贝,是非常粗鲁的写法。
arkui.club 这个网站似乎是arkui爱好者维护的,看起来他们也是用 onChange 来完成这件事的,太粗鲁了。
onSubmit
?官方示例误导人!
继续看官方的示例,onSubmit是输入完成时触发的,按照正常人的思路,应该是会返回一个 string 的,虽然将它存到全局变量里不是一个好习惯,但也不是不能接受,便有了以下demo。
1 | // 官方demo |
emmm,和我想象中的不一样,string呢???submit居然只返回一个“回车键的类型”,这回调有什么意义?除了按下屏幕上的“完成”按钮之外还有什么别的选择?难道是有用户接入了蓝牙键盘然后巧了个“Enter”键?
哇,这API设计得也太细了吧,用户是触摸屏幕还是蓝牙键盘都区分,属实是在边边角角做优化了。
你以为到这就放弃了?仔细看 onSubmit
的文档,发现官方的demo和官方的文档是对不上的,文档里说 onSubmit
接受两个参数 (enterKey: EnterKeyType, event: SubmitEvent) => void
,由于 typescript 特有的松弛感,导致单个参数也是能运行的。实际上 event: SubmitEvent
里面就有 text
字段,表示输入的内容,因此官方demo应当调整为:
1 | TextInput() |
如果真是这么简单,我也不会写文章来怒斥 ArkUI 了,请接着往下看,还有高手!
仔细观察数字键盘,右上角有一个“收起键盘按钮”,右下角有一个“完成按钮”,用户使用哪个结束输入完全取决于用户的习惯,onSubmit
逆天的地方在于,只有点击 “完成按钮” 的时候才会触发,点击“收起键盘按钮”时不触发。
emmm,也算合理,毕竟 onSubmit
字面意思上是用户彻底完成输入才算,写到一半收起键盘不算,勉强蒙混过关吧。
经过仔细研究,TextInput
的65个API里,主要包括这几类:设置属性(字体、颜色),回调函数(onChange、onSubmit)、TextInputOptions
(placeHolder、text、controller),我倒要看看这么简单的需求该怎么实现。
官方针对 TextInput
给了无数的示例,但偏偏没有读取文本内容的示例,也是逆天。
- 示例1(设置与获取光标位置)
- 示例2(设置下划线)
- 示例3(设置自定义键盘)
- 示例4(设置右侧清除按钮样式)
- 示例5(设置计数器)
- 示例6(电话号码格式化)
- 示例7(设置文本断行规则)
- 示例8(设置文本样式)
- 示例9(设置文字特性效果)
- 示例10(自定义键盘避让)
- 示例11(设置文本自适应)
- 示例12(设置折行规则)
- 示例13(实现了插入和删除的效果)
- 示例14(文本扩展自定义菜单)
@State
绑定属性?单向同步!
在疯狂的搜索后,发现 Text
有一些读写的Demo,例如按下按钮后刷新文本内容,可读可写。
1 | struct Index { |
将 @State message
绑定到 TextInput
上,神奇的事情就此发生。用户的键盘输入对 @State message
没有任何影响,但程序的按钮读写会对 UI 产生影响,比如这个鬼畜的 GIF。
1 | TextInput({ text: this.message }) |
大致原理就是:无论用户怎么编辑,都不影响内存中 message
的值。
napi
追一遍?底层有API,但不对外注册,你气不气!
到这个时候,我是真没办法了,我倒要看看这个输入框到底在哪里存放了数据,直接开始翻 arkui 的代码,https://gitee.com/openharmony/arkui_ace_engine 。
1 | // frameworks/bridge/declarative_frontend/engine/jsi/nativeModule/arkts_native_api_impl_bridge.cpp |
从注册的API看,确实没有提供 "getText" 系列的API。
再追一下 onChange
和 onSubmit
的实现,看看数据在哪里,最终在:
1 | // frameworks/core/components/text_field/text_field_component.cpp |
大概就是:TextEditController
里存放的,使用 GetText
可以拿到。
是不是和ArkUI的设置text、设置hint、设置选中对上了?诶,底层有 GetText
,但就是不给你用,你气不气?你气不气?你气不气?
官方APP[短信]会怎么做?居然是onChange?
到这时候,其实已经很明白了,TextInput
狗都不用,我已经无法想象各大主流APP在开发鸿蒙5.0时开发者到底有多崩溃了,由于大厂APP肯定不开源,我去研究一下“短信APP”是怎么实现文本编辑的。
不看不知道,一看吓一跳,鸿蒙的官方APP用的也是 onChange
,好家伙,我直呼好家伙。
只能说,我开发水平不足以理解这种高深的写法。
在神仙 4qwerty7
的反复尝试后,翻到了塞到某个犄角旮旯里的文档
难道,就此放弃了吗?
每当我遇到奇奇怪怪的无法解决的问题,都会向 4老师 寻求意见,一边怒斥 ArkUI 的变量绑定做得烂,一边搞了好几个小时没搞出来,本来以为 4老师 也要经历滑铁卢了,突然晚饭时候和我说有方案了。
我也不知道他是怎么找到的,$$语法:内置组件双向同步 ,反正就,用了这个语法就会自动刷新变量中的值了,甚至demo还真是 TextInput
做的。
1 | message: string = ''; |
这个 $$
是个什么东西我也不太懂,自定义的刁钻语法糖,只能说,4老师牛逼……
技术总结
如果要在UI和内存中双向同步一个数据,需要使用 $$
来修饰 State变量(不代表以后能用,懂的都懂,不能明说),demo如下:
1 |
|
吐槽总结
本文就是用于输出情绪的,从一个简单的功能来有理有据地批评 ArkUI 到底是怎样的一坨,毫不夸张地讲,两位顶尖的工程师都得花这么久的时间才能研究明白,其他菜鸟工程师解决起来只会更费劲。
更进一步,以 ArkUI 这个样子,显然是鸿蒙生态的路上一道阻碍,我也不是第一次用了,私下里用一次骂一次、用一次骂一次,本以为是我太菜了,经过这次事件我深刻认识到,ArkUI就是一坨,不接受反驳。