Flutter三方库适配OpenHarmony【harmony_ui】输入类控件实战:文本框三态、搜索框、数字加减与图案锁
前言
harmony_ui是 Material/Cupertino 风格的 Flutter 组件库,完整实现了HarmonyOS 设计语言,覆盖官方「控件概览」6 大类 42 个控件,并额外实现了沉浸光感材质与 UI Design Kit 增强能力。本系列按官方控件类别逐类实战:第 1 篇导航类、第 2 篇展示类、第 3 篇操作类,本篇是第 4 篇:输入类。
输入类是"用户向 App 喂数据"的通道,官方共 4 个控件:文本输入(OhosTextField)、搜索框(OhosSearchBar)、数字加减(OhosCounter)、图案锁(OhosPatternLock)。控件虽少,却是"手感"最敏感的一类——label 怎么浮动、错误态怎么提示、搜索框展开什么节奏,这些细节直接决定表单好不好用。
所有示例代码都在OpenHarmony 模拟器上直接运行验证(Flutter3.47.7-ohos-1.0.1+ DevEco Studio26.0.0 Release,截图环境:API 26,1280×2832)。环境搭建、依赖引入与构建步骤见文首「环境与版本」「安装与引入 harmony_ui」以及第九节;仓库地址:AtomGit / GitHub。
环境与版本
本文的示例与截图基于以下环境组合(2026-10 实测):
| 组件 | 版本 | 说明 |
|---|---|---|
| Flutter SDK(OH 适配版) | 3.47.7-ohos-1.0.1 | oh-flutter/flutter_flutter,oh-3.47-dev分支 |
| DevEco Studio | 26.0.0 Release | 提供 hvigor / ohpm / hdc / JBR 等工具链 |
| OpenHarmony SDK / API | API 26(26.0.0) | 模拟器与 SDK 均为 API 26 |
| 运行设备 | OpenHarmony 模拟器 | API 26,1280×2832 |
环境搭建(分叉获取、DevEco Studio 与 SDK 配置、模拟器创建)请按官方指导操作:OpenHarmony-flutter 环境搭建指导。
harmony_ui是纯 Dart/Flutter 组件库,不依赖 ohos 平台通道;在官方 Flutter SDK 上也能运行(用于跨平台预览)。只有跑example/ohos工程、构建 HAP 时才需要上面的 OH 适配版 SDK。
安装与引入 harmony_ui
harmony_ui已发布到 pub.dev,当前最新版本是0.3.0。在应用工程的pubspec.yaml中声明:
dependencies:flutter:sdk:flutterharmony_ui:^0.3.0然后拉取依赖:
fvm flutter pub get如果团队需要固定到仓库的某个提交(例如使用尚未发版的修复),改用 git 依赖:
dependencies:harmony_ui:git:url:https://atomgit.com/oh-flutter/harmony_ui.gitref:v0.3.0# 固定 tag;写 main 则跟随最新提交fvm flutter pub getpub.dev 与 git 两种方式二选一,不要同时声明。CI 中建议固定 tag(如
v0.3.0)而不是main,避免构建结果随上游漂移。harmony_ui目前只依赖qr一个三方包,ohos_icons是可选配套图标包,不引入也不影响组件使用。
一、输入类总览
| 官方控件 | 实现 | 一句话说明 |
|---|---|---|
| 文本输入 | OhosTextField | 下划线风格,正常/聚焦/错误三态 |
| 搜索框 | OhosSearchBar | 胶囊搜索框,清空按钮 + 提交回调 |
| 数字加减 | OhosCounter | 步进器,min/max/step 约束 |
| 图案锁 | OhosPatternLock | 3×3 九宫格,安全输入 |
输入类整体效果(gallery「输入」分类页,模拟器实机):
输入类:OhosTextField三态(正常/聚焦/错误)、OhosSearchBar胶囊搜索框、OhosCounter数字加减、OhosPatternLock图案锁
二、文本输入 OhosTextField
OhosTextField对齐 ArkUI 的下划线输入框风格:默认无背景,底部一条细分隔线,聚焦时下划线变为品牌色——与 Material 的填充/描边风格明显不同,这是鸿蒙输入框最直观的识别点。
2.1 正常态
OhosTextField(labelText:'用户名',prefixIcon:constIcon(Icons.person_outline),onChanged:(Stringv)=>_username=v,)参数速览:
| 参数 | 说明 |
|---|---|
labelText | 浮动标签(聚焦/有值时上浮变小) |
hintText | 占位文字(无 label 时建议用 hint) |
prefixIcon | 前缀图标(账号/密码/手机号场景标配) |
obscureText | 密码遮挡 |
keyboardType | 键盘类型(数字/邮箱/电话等) |
controller | 文本控制器(取值/定位光标) |
enabled | false 整体禁用 |
errorText | 错误提示(见 2.3 节) |
2.2 聚焦态
聚焦行为由组件内部处理:label 上浮、下划线变品牌色(highlight),与官方规范一致,不需要业务代码参与:
// 多个输入框时管理焦点跳转final_focus1=FocusNode();final_focus2=FocusNode();OhosTextField(labelText:'手机号',keyboardType:TextInputType.phone,controller:_phoneCtrl,focusNode:_focus1,onSubmitted:(_)=>_focus2.requestFocus(),// 回车跳到下一项)提示:鸿蒙平台的系统键盘由 OpenHarmony 输入法提供,
keyboardType的映射由鸿蒙社区 Flutter 分叉处理(CPF-Flutter/flutter_flutter),常用类型(文本/数字/邮箱/电话)在模拟器上验证正常。
2.3 错误态
errorText非空时进入错误态:红色提示文字 + 红色下划线,就地打断输入流之外的任何提示(不要弹对话框报错):
OhosTextField(labelText:'密码',obscureText:true,errorText:_showError?'密码至少 8 位':null,// 动态切换)- 错误信息在失焦(
onEditingComplete)或提交时触发,不要在每个键入都报错; - 错误清除:输入合法后把
errorText置回null即可,组件自动回到正常态。
2.4 完整表单组合
注册表单的完整组合(label 浮动 + 图标 + 密码遮挡 + 错误校验):
classRegisterFormextendsStatefulWidget{constRegisterForm({super.key});@overrideState<RegisterForm>createState()=>_RegisterFormState();}class_RegisterFormStateextendsState<RegisterForm>{final_usernameCtrl=TextEditingController();final_passwordCtrl=TextEditingController();String?_passwordError;bool _obscure=true;void_validate(){setState((){_passwordError=_passwordCtrl.text.length>=8?null:'密码至少 8 位';});}@overrideWidgetbuild(BuildContextcontext){returnOhosList(children:[OhosTextField(controller:_usernameCtrl,labelText:'用户名',prefixIcon:constIcon(Icons.person_outline),),constSizedBox(height:20),OhosTextField(controller:_passwordCtrl,labelText:'密码',prefixIcon:constIcon(Icons.lock_outline),obscureText:_obscure,errorText:_passwordError,onEditingComplete:_validate,),constSizedBox(height:24),OhosButton(onPressed:_passwordError==null?_register:null,child:constText('注册'),),],);}}三、搜索框 OhosSearchBar
OhosSearchBar是胶囊形搜索输入框(对齐 ArkUI Search 组件),内置清空按钮(有内容时自动显示)与提交回调。
3.1 基本用法
OhosSearchBar(hintText:'搜索商品、品牌',height:40,prefixIcon:constIcon(Icons.search),onChanged:(Stringquery){// 输入过程:可做防抖联想_debounceSearch(query);},onSubmitted:(Stringquery){// 回车/键盘搜索键:执行搜索_doSearch(query);},)autofocus: true适合搜索结果页回跳后直接输入;- 高度默认 40vp(胶囊规范),
prefixIcon默认搜索图标; controller可外部接管文本(回显历史关键词等)。
3.2 防抖联想实现
onChanged每个键入都触发,联想词场景直接发请求会打爆接口。标准写法是 300ms 防抖 + 取消过期请求:
class_SearchPageStateextendsState<SearchPage>{Timer?_debounce;int _seq=0;void_debounceSearch(Stringquery){_debounce?.cancel();if(query.trim().isEmpty)return;_debounce=Timer(constDuration(milliseconds:300),()async{finalid=++_seq;finalsuggestions=awaitapi.suggest(query);if(id!=_seq)return;// 丢弃过期结果setState(()=>_suggestions=suggestions);});}@overrideWidgetbuild(BuildContextcontext){returnOhosScaffold(appBar:OhosAppBar(title:OhosSearchBar(autofocus:true,onChanged:_debounceSearch,onSubmitted:_doSearch,),),body:_suggestionsPage,);}}_seq序号丢弃过期响应,防止"先输完的请求覆盖后输完的联想";onSubmitted是"真正执行搜索"的时机,与onChanged的分工别混。
四、数字加减 OhosCounter
OhosCounter是"减号 + 数值 + 加号"步进器,购物车数量、预约份数场景:
OhosCounter(value:_quantity,min:1,max:99,step:1,onChanged:(int v)=>setState(()=>_quantity=v),)min/max越界后对应按钮自动禁用(灰化不可点),不需要业务侧判断;step支持非 1 步进(如按 2 份起售的商品);buttonSize默认 32vp,列表行内可用小尺寸。
// 购物车行:列表项 + 步进器OhosListTile(title:constText('鸿蒙机械键盘'),subtitle:constText('¥ 399'),trailing:OhosCounter(value:_cartQty,min:1,max:20,onChanged:_updateCart,),)五、图案锁 OhosPatternLock
3×3 九宫格图案锁,安全设置/应用锁场景。onCompleted在抬指时回传节点索引列表(0-8 顺序),onError校验失败时触发:
OhosPatternLock(size:280,cellSize:56,activeColor:constColor(0xFF0A59F7),// 已选路径颜色(默认品牌色)errorColor:constColor(0xFFE84026),// 错误抖动颜色onCompleted:(List<int>pattern){// pattern 如 [0, 1, 2, 4, 6, 7, 8]_verifyPattern(pattern);},onError:(){showOhosToast(context,'图案错误,请重试');},)- 路径绘制、错误抖动动画均由组件内部处理;
- 校验逻辑在
onCompleted里做(本地比对或下发服务端); - 连续失败锁定(如 5 次后禁用 30 秒)需要业务侧自己记次数——组件保持无状态。
安全提示:图案锁适合设备端轻量保护,不要用它承载高安全等级场景(支付密码请用系统能力);比对在本地完成、勿把 pattern 上传。
六、鸿蒙平台键盘与 IME 适配
输入类在鸿蒙平台上跑,键盘由 OpenHarmony 系统输入法提供,Flutter 分叉负责TextInput协议映射。几个实测结论:
- 键盘类型:
TextInputType.text / number / phone / emailAddress等常用类型在模拟器上均正确映射,数字框直接出数字键盘; - 回车键行为:
onSubmitted由键盘"搜索/完成"键触发,与 Android 一致,无需平台分支; - 键盘避让:
OhosScaffold跟随系统 resize 策略,输入框被键盘顶起时页面自动上移,长表单建议包SingleChildScrollView; - 中文输入:模拟器中文输入法(小艺输入法)组合输入正常,
onChanged在上屏时触发(与 Android 行为一致),不要在每次onChanged里做整串正则校验——拼音上屏前的中间态会误报。
// 中文输入安全校验:失焦时才校验OhosTextField(controller:_nicknameCtrl,labelText:'昵称',onEditingComplete:()=>_validateNickname(),)6.1 键盘类型速查
| 场景 | keyboardType | 鸿蒙键盘表现 |
|---|---|---|
| 普通文本/昵称 | TextInputType.text | 全键盘(中文/英文) |
| 手机号 | TextInputType.phone | 数字 + 拨号符号 |
| 纯数字(验证码/金额) | TextInputType.number | 数字键盘 |
| 邮箱 | TextInputType.emailAddress | 带 @ . 快捷键 |
| 多行备注 | TextInputType.multiline | 回车为换行、无"完成"键 |
多行输入注意:
multiline下没有"完成"键,提交动作必须放在按钮上(OhosActionBar主按钮),不要依赖onSubmitted。
七、表单校验设计
输入类的体验核心是校验时机。推荐"分层校验"策略:
| 时机 | 校验内容 | 反馈方式 |
|---|---|---|
| 键入中(onChanged) | 长度上限、格式白名单(如手机号位数) | 静默截断,不报错 |
| 失焦(onEditingComplete) | 格式正则(手机号/邮箱) | errorText就地提示 |
| 提交(按钮点击) | 全部字段 + 业务规则 | 全部errorText+ 焦点定位到第一个错误项 |
void_submit(){finalok=_validateAll();// 逐字段校验并设置 errorTextif(!ok){_firstErrorFocus.requestFocus();// 焦点跳到第一个错误输入框return;}_doSubmit();}- 提交按钮在"未通过基础校验"时直接禁用(
onPressed: null),减少无谓提交。
7.1 焦点定位实现
"跳到第一个错误项"需要给每个输入框挂FocusNode,校验失败时定位:
class_RegisterFormStateextendsState<RegisterForm>{final_phoneFocus=FocusNode();final_passwordFocus=FocusNode();final_smsFocus=FocusNode();bool_validateAll(){varok=true;if(!RegExp(r'^1\d{10}$').hasMatch(_phoneCtrl.text)){_phoneError='手机号格式不正确';ok=false;}if(_passwordCtrl.text.length<8){_passwordError='密码至少 8 位';ok=false;}setState((){});// 焦点定位到第一个错误项if(_phoneError!=null){_phoneFocus.requestFocus();}elseif(_passwordError!=null){_passwordFocus.requestFocus();}returnok;}}- 焦点跳转后键盘自动弹出,用户可以直接改错,不用重新点击输入框;
- 错误多时用
showOhosDialog汇总提示"还有 N 项未通过",比逐个滚动找错误友好。
汇总类错误提示对话框实机效果:
showOhosDialog弹出框:提交校验失败时的错误汇总提示
八、在鸿蒙模拟器上运行
输入类全部控件在 gallery 示例应用的「输入」分类页可交互运行,最短运行路径:
安装3.47.7-ohos-1.0.1的 OH 适配版 SDK。该版本在仓库里是 git tag,按 tag 浅克隆到 fvm 版本目录后在工程内切换:
gitclone--depth1--branch3.47.7-ohos-1.0.1\https://atomgit.com/oh-flutter/flutter_flutter.git\~/fvm/versions/ohos/oh-3.47.7-releasecd<harmony_ui 仓库根目录>fvm use ohos/oh-3.47.7-release fvm flutter--version# 应输出 Flutter 3.47.7-ohos-1.0.1fvm 的
fvm install <alias>/<ref>只识别分支名,3.47.7-ohos-1.0.1是 tag,不能直接 install;按上面的方式 clone 到版本目录后fvm use即可。source env.sh加载 DevEco Studio26.0.0 Release的工具链(node / ohpm / hvigor / SDK toolchains);如果命令不可用,按文首的环境搭建指导检查DEVECO_SDK_HOME、JAVA_HOME与hdc;进入
example/:fvm flutter pub get && fvm flutter create --platforms ohos .;构建并安装到模拟器:
fvm flutter build hap--debug--no-codesign hdc list targets hdcinstall-rbuild/ohos/hap/entry-default-unsigned.hap hdc shell aa start-aEntryAbility-bcom.example.ohos_ui_example在模拟器上测输入类,建议同时挂一个 Android/iOS 真机对比键盘行为差异——鸿蒙分叉的 IME 映射以模拟器为准,真机输入法(第三方)可能有边界差异。
九、常见问题 FAQ
9.1 输入类组件的高频问题
- label 不浮动?确认用的是
labelText(浮动标签)而不是hintText(占位文字,不浮动);两者可以共存(label 在上方、hint 在输入区); - 错误态不消失?
errorText是受控参数,校验通过时必须主动置回null,组件不会自动清除; - 数字键盘出现字母?检查
keyboardType: TextInputType.number是否传对;邮箱用TextInputType.emailAddress; - 搜索框清空按钮不出现?清空按钮只在有内容时显示,空内容时隐藏,这是符合规范的行为;
- 图案锁节点索引?按"Z 字形"从 0 开始:
[0,1,2 / 3,4,5 / 6,7,8],比对时注意顺序敏感。
9.2flutter pub get找不到 harmony_ui?
先确认pubspec.yaml写的是harmony_ui: ^0.3.0,或按文首 git 依赖写法固定ref: v0.3.0;两种方式不要同时声明。改完后执行fvm flutter clean && fvm flutter pub get,仍异常时删除pubspec.lock与.dart_tool/重试。
9.3 颜色、字阶与截图不一致?
通常是主题没有注入。OhosTheme要包住页面根节点(MaterialApp.home或builder),组件通过OhosTheme.of(context)读取 Token;只 import 组件库不会自动注入。输入类组件还常因显式覆盖fillColor/borderColor导致三态不生效,先回到默认主题排查。
9.4 构建时报npm not found或hvigor不存在?
说明 DevEco 工具链没有进入 PATH。执行source env.sh(按 DevEco Studio 26.0.0 Release 的默认安装路径配置),确认node、ohpm、hvigor、hdc可执行;DEVECO_SDK_HOME指向.../Contents/sdk。
9.5 模拟器安装失败,或提示签名错误?
OpenHarmony 模拟器接受未签名 debug HAP:fvm flutter build hap --debug --no-codesign后用hdc install -r build/ohos/hap/entry-default-unsigned.hap安装。真机与flutter run热重载需要调试证书签名。
9.6 官方 Flutter 上能用输入类组件吗?
可以。harmony_ui是纯 Dart/Flutter 实现,不依赖平台通道;键盘行为由官方 Flutter 或鸿蒙分叉各自处理,跨平台预览用官方 Flutter,鸿蒙验证用 3.47.7-ohos-1.0.1。
十、最佳实践
- 三态优先:任何输入框设计时先画出正常/聚焦/错误三态再写代码,
OhosTextField的三态就是按这个顺序实现的; - 错误就地化:校验错误一律
errorText就地显示,禁止用对话框/Toast 报错打断输入; - 校验分层:键入中静默、失焦提示、提交兜底,三层各司其职;
- 搜索防抖:
onChanged联想必加防抖(300ms),onSubmitted才真正请求; - 步进器约束:
OhosCounter用 min/max 交给组件禁用边界按钮,业务侧不要再包一层判断; - 图案锁无状态:锁定次数、失败计数放业务层,组件保持纯展示 + 回调。
总结
输入类 4 个控件体量不大,但"手感"权重最高:下划线聚焦变色、label 浮动、错误就地提示、搜索防抖、步进边界禁用、图案锁抖动——这些细节全部由harmony_ui的默认行为承担,业务代码只需要声明"我要什么状态",不需要手写任何动画。输入体验对了,表单页就有鸿蒙的味道。
下一篇进入选择类:勾选/单选/开关三件套、评分条、滑动条、分段按钮、三模式颜色选择器与底部选择器,把"从选项里挑一个"的所有形态讲全。
如果这篇文章对你有帮助,欢迎点赞👍、收藏⭐、关注🔔,你的支持是我持续创作的动力!
相关资源:
- harmony_ui 仓库(AtomGit):oh-flutter/harmony_ui
- harmony_ui 仓库(GitHub):shaohushuo/harmony_ui
- 鸿蒙社区 Flutter 分叉:CPF-Flutter/flutter_flutter
- 配套图标包 ohos_icons:pub.dev/packages/ohos_icons
- 官方控件概览(42 控件清单):general_overview
- 华为鸿蒙设计入门文档:design/devstart
- fvm 多版本管理:fvm.app