尧图网络科技YAOTU DIGITAL 获取报价
获取报价
首页 / 资讯中心 / 文章详情

HarmonyOS 7 自动填充框总偏一截?PageNodeInfo 的 px 坐标与 PC 页面原点

发布时间:2026/9/28 21:25:02

资讯中心
01
ARTICLE

HarmonyOS 7 自动填充框总偏一截?PageNodeInfo 的 px 坐标与 PC 页面原点

HarmonyOS 7 自动填充框总偏一截?PageNodeInfo 的 px 坐标与 PC 页面原点
HarmonyOS 7 自动填充框总偏一截PageNodeInfo 的 px 坐标与 PC 页面原点把登录表单接上自动填充请求已经发出候选框却偏离输入框同一段代码放到电脑窗口里偏移又变了。为了排查顺手把回调的ViewData整包打进日志结果账号和密码也跟着进了日志。这不是一个“再调几个margin”能稳妥解决的问题。API26开放的显式表单请求把节点位置、类型、值和焦点交给应用组织应用也必须对坐标来源和回填对象负责。下面先修正坐标再实现不会按数组位置填错字段的结果处理。新的是显式请求不是自动填充从7.0才有autoFillManager模块早已存在。本文讨论的是26.0.0新增的 requestAutoFill(context, request, callback)以及它使用的FillRequest、ViewData、PageNodeInfo等公开类型。旧的 requestAutoSave(context, callback) 与新增的带SaveRequest重载也不能混作同一个起始版本。官方资料核对日期为2026年9月27日。autoFillManager参考更新于9月23日PageNodeInfo、AutoFillRect、ViewData及请求类型参考更新于8月29日。接口使用Stage模型系统能力为 SystemCapability.Ability.AbilityRuntime.AbilityCoreAPI26支持元服务。结构关键字段不能省略的含义FillRequesttype、viewData请求哪一类填充与当前页面数据ViewDatabundleName、pageUrl、pageNodeInfos、pageRect应用、页面、节点集合及页面几何PageNodeInfoid、autoFillType、value、rect、isFocus节点身份、字段类型、当前值、位置与焦点AutoFillRectleft、top、width、height单位都是px节点位置相对页面PageNodeInfo.placeholder可选。FillRequest.triggerType也可选不清楚其含义时不要随意编一个数值。本例只传已核对的必填字段。案例一相对位置算对了为什么仍然差一倍假设同一套布局测量给出页面原点(10,20)节点原点(40,80)节点大小(120,24)单位都是vp。节点相对页面的位置是(30,60)vp。若示例换算系数是2提交的left/top应为(60,120)px大小为(240,48)px。两种常见错误会在这里叠加直接提交节点的绝对原点或者做完相减却忘了单位转换。还有一种相反错误测量API本来已经返回px又调用一次vp2px结果又放大了。为了把约束写进代码先定义测量输入。这里的originX/originY必须来自同一个坐标系、同一次布局不能一个取屏幕坐标另一个取父容器坐标。转换函数不负责猜测来源。export interface MeasuredBox { originX: number; originY: number; width: number; height: number; unit: vp | px; } export interface FillRect { left: number; top: number; width: number; height: number; } function validBox(box: MeasuredBox): boolean { return Number.isFinite(box.originX) Number.isFinite(box.originY) Number.isFinite(box.width) Number.isFinite(box.height) box.width 0 box.height 0; } export function relativeRectPx( node: MeasuredBox, page: MeasuredBox, vpToPx: (value: number) number ): FillRect { if (!validBox(node) || !validBox(page)) throw new Error(invalid geometry); if (node.unit ! page.unit) throw new Error(mixed geometry units); const convert node.unit vp ? vpToPx : (value: number): number value; const rect: FillRect { left: convert(node.originX - page.originX), top: convert(node.originY - page.originY), width: convert(node.width), height: convert(node.height) }; if (![rect.left, rect.top, rect.width, rect.height].every(Number.isFinite) || rect.width 0 || rect.height 0) throw new Error(invalid conversion); return rect; } export function pcPageRectPx(page: MeasuredBox, vpToPx: (value: number) number): FillRect { if (!validBox(page)) throw new Error(invalid page geometry); const convert page.unit vp ? vpToPx : (value: number): number value; const width convert(page.width); const height convert(page.height); if (!Number.isFinite(width) || !Number.isFinite(height) || width 0 || height 0) throw new Error(invalid page size); return { left: 0, top: 0, width, height }; }为什么没有把负的left/top一律改成0因为滚动后节点有可能部分位于页面外强行夹到0会改变实际几何。是否允许该节点参与当前请求应由表单的可见性规则决定。这个转换函数只检查数值和单位不伪装成一套完整的布局采集器。真实接入时vpToPx传入当前UIContext的vp2px转换不要写死示例里的2。窗口、字体、滚动和折叠形态发生变化后需要重新采集布局函数能把旧坐标转换成正确单位但无法把旧坐标变成当前坐标。const pageVp: MeasuredBox { originX: 10, originY: 20, width: 500, height: 400, unit: vp }; const nodeVp: MeasuredBox { originX: 40, originY: 80, width: 120, height: 24, unit: vp }; const r relativeRectPx(nodeVp, pageVp, value value * 2); if (r.left ! 60 || r.top ! 120 || r.width ! 240 || r.height ! 48) throw new Error(vp conversion failed); const pagePx: MeasuredBox { originX: 20, originY: 40, width: 1000, height: 800, unit: px }; const nodePx: MeasuredBox { originX: 80, originY: 160, width: 240, height: 48, unit: px }; const nativePx relativeRectPx(nodePx, pagePx, () { throw new Error(px must not be converted twice); }); if (nativePx.left ! 60 || nativePx.top ! 120) throw new Error(px offset failed); const pc pcPageRectPx(pagePx, value value * 2); if (pc.left ! 0 || pc.top ! 0 || pc.width ! 1000) throw new Error(PC page failed); console.log(vp, px and PC geometry cases passed);电脑上的pageRect有额外要求ViewData参考明确说明PC/2in1上的密码保险箱以弹窗形式展示为保证位置跟随输入框pageRect.left和top需要置为0。不能把窗口在屏幕上的位置直接填进这里也不能因为left/top为0就顺手把宽高改成0。注意这条规则针对ViewData.pageRect不是要求每一个节点rect都从(0,0)开始。节点仍要提供其相对页面的位置。把这两个矩形混在一起会出现所有输入框都指向页面左上角的另一个错误。本例pcPageRectPx专门表达电脑场景。其他设备的页面数据按实际窗口与官方约定提供不能把一个名叫PC的辅助函数当成所有设备的万能坐标策略。从几何进入真实requestAutoFill下面是平台适配函数。viewData必须由当前表单模型和当前布局共同组装bundleName、pageUrl不能保留官方示例占位值PageNodeInfo.id与应用控件映射要稳定。请求类型使用官方枚举而不是靠数字记忆。import { autoFillManager } from kit.AbilityKit; import { UIContext } from kit.ArkUI; import { BusinessError } from kit.BasicServicesKit; export function requestAccountFill( ui: UIContext, viewData: autoFillManager.ViewData, accept: (data: autoFillManager.ViewData) void, reportFailure: (code: number) void ): void { const request: autoFillManager.FillRequest { type: autoFillManager.AutoFillType.USER_NAME, viewData }; const callback: autoFillManager.AutoFillCallback { onSuccess: (data: autoFillManager.ViewData): void { accept(data); }, onFailure: (result: autoFillManager.FillFailureResult): void { reportFailure(result.errCode); } }; try { autoFillManager.requestAutoFill(ui, request, callback); } catch (error) { reportFailure((error as BusinessError).code); } }这不是自动触发、静默保存账号的代码。应由应用明确的填充交互调用。成功回调接收ViewData失败回调接收FillFailureResult其中错误码字段是errCode同步异常按BusinessError处理。不要把onFailure当成一个无参数回调也不要把requestAutoFill误写成返回Promise的接口。当前环境尚未具备API26 SDK和真机以上ArkTS平台适配段没有完成API26编译和设备测试。本文实际在本地执行的是几何转换及结果映射的原文测试。真实自动填充服务是否有可用数据、弹窗最终位置和不同设备行为需要在支持版本的设备上继续验证。案例二结果顺序变了账号不要填进密码框请求中用户名在数组第0项密码在第1项不意味着回调的数据永远可以按下标直接赋值。应用已经有节点id就应该建立明确的ID映射。字段顺序调整、新增输入项或者某个结果未返回都不应改变字段归属。下面只接受声明过的节点遇到未知或重复id就拒绝这一批结果。缺失字段保持原值不猜一个空字符串覆盖。这个严格策略是本例应用层选择并不是宣称平台一定会返回未知或重复节点。export interface FieldValue { id: number; value: string; } export interface AccountForm { account: string; password: string; } export function mergeAccountValues( current: AccountForm, values: FieldValue[], accountId: number, passwordId: number ): AccountForm { if (accountId passwordId) throw new Error(field IDs must differ); const seen new Setnumber(); let account current.account; let password current.password; for (const item of values) { if (seen.has(item.id)) throw new Error(duplicate field ID); seen.add(item.id); if (item.id accountId) account item.value; else if (item.id passwordId) password item.value; else throw new Error(unknown field ID); } return { account, password }; } export function fillEventSummary(values: FieldValue[]): string { return fill-result nodes values.length; }合并函数返回新对象检查全部成功后再一次性更新界面。这样最后一项发现未知ID时不会出现用户名已改、密码还没改的半更新状态。生产代码还应确认返回结果属于当前页面和当前请求如果请求期间已经切换账号或离开页面应丢弃旧结果而不是继续修改另一个表单。const original: AccountForm { account: old-account, password: old-secret }; const result mergeAccountValues(original, [{ id: 20, value: new-secret }, { id: 10, value: new-account }], 10, 20); if (result.account ! new-account || result.password ! new-secret) throw new Error(result order changed field ownership); if (original.account ! old-account) throw new Error(input mutated); const partial mergeAccountValues(original, [{ id: 10, value: updated }], 10, 20); if (partial.password ! old-secret) throw new Error(missing field overwritten); let rejected false; try { mergeAccountValues(original, [{ id: 99, value: unexpected }], 10, 20); } catch { rejected true; } if (!rejected) throw new Error(unknown ID accepted); const event fillEventSummary([{ id: 20, value: must-not-be-logged }]); if (event.includes(must-not-be-logged)) throw new Error(sensitive value leaked); console.log(reordered, partial and rejected result cases passed);测试中的值是虚构数据不是真实账号密码。事件摘要只返回节点数量既不序列化value也不记录具体账号。排查位置时可以记录经过审查的几何和设备类型排查结果时记录成功、失败码、耗时与节点数即可。不能为了方便调试把整包ViewData放入公开日志或埋点。三种修法的取舍修法表面效果后续问题给候选框偏移补一个常量当前设备看起来对齐密度、窗口位置、滚动后再次失效每个调用点自行换单位局部能修复混入px/vp或重复转换难以发现明确测量合同统一生成请求转换和请求字段可独立测试需要维护布局采集与控件ID映射我更倾向第三种但不会把它扩成一个负责所有窗口的全局单例。每个表单负责提供自己的当前数据统一工具只负责可检验的转换和映射。页面位置变化后重新采集服务结果回来后核对上下文失败时保留手动输入路径。上线前至少检查节点rect以px表示坐标来自同一原点PC pageRect.left/top为0且宽高真实节点ID不重复字段类型正确焦点信息对应当前输入项日志无value填充失败仍能手动完成表单。能把这些点逐项复现比“在我这台机器上看起来没偏”更经得起窗口变化和版本升级。官方参考autoFillManagerAPI26请求签名及回调PageNodeInfo字段、值、位置和焦点AutoFillRect页面相对距离与px单位ViewDataPC/2in1的pageRect原点要求AutoFillRequestFillRequest与失败结果
02
RELATED NEWS

相关资讯

更多网站建设与数字化升级内容

03
WHY YAOTU

想打造同款高转化官网?

懂行业、懂生意,从建站到增长一站式陪跑

◈

场景化定制

不做模板站,围绕你的业务场景量身设计,小众不撞款。

◐

营销型架构

以转化目标组织内容与路径,让官网真正带来询盘。

▲

全周期服务

设计、开发、运营、运维一体,上线只是开始。

免费获取你的建站方案

留下需求,专属顾问 24 小时内为你输出方案建议。