管理中心
我的
推荐
最热
最新
其他
已解决
未解决
作为一名正在开展 HarmonyOS 应用适配与开发的开发者,我认为鸿蒙生态在技术架构、自主创新和生态建设方面具有重要价值,但当前开发者服务体系仍存在较为明显的流程繁琐、权限开放不足、商业化接入门槛偏高等问题,亟须优化。一、全面取消非必要的纸质合同签署及邮寄流程目前,接入数字商品及联运服务仍需联系商务人员、填写资料、打印纸质合同、盖章、邮寄,等待华为签字盖章后再寄回开发者。在2026年数字经济和电子签约技术已经高度成熟的背景下,这种依赖人工沟通和纸质文件往返邮寄的签约方式,明显不符合现代互联网应用开发的效率要求。建议全面推行在线电子合同、企业实名认证、电子签章与自动化审核,实现协议在线阅读、在线签署、在线归档。对于标准化商业服务,应尽可能采用开发者平台在线确认协议的方式完成开通,无须经过线下商务流程。二、建立标准化开放能力组合,减少重复申请与人工审核当前,部分系统能力、服务接口及商业化功能需要开发者逐项申请、提交说明并等待审核,不仅增加开发成本,也导致项目开发进度难以预测。建议按照应用场景提供标准化开放能力组合,例如基础应用能力、用户账号能力、支付与订阅能力、消息通知能力、AI应用能力等。对于低风险、标准化、已有明确技术规范的接口,应在开发者完成实名认证后默认开放,允许直接调用,并通过配额、权限范围、安全审计及风险控制管理使用行为。只有涉及高度敏感数据、特殊硬件权限或高风险业务的能力,才应设置额外审批程序。三、进一步优化应用商业化接入流程支付、数字商品、订阅及相关商业服务是应用开发者实现持续经营的重要基础设施,不应成为复杂的商务合作项目。建议建立统一的商业化服务控制台,实现沙盒开通、生产环境申请、商品管理、交易查询、退款管理、结算、对账和税务资料管理的一站式操作。对于符合资质的普通应用开发者,应尽可能实现标准化、自动化接入,而不是要求逐一联系商务人员。四、提升平台审核透明度和开发者服务效率建议明确公开各项权限申请、应用审核、商业服务开通的材料要求、审核标准、预计处理周期及常见驳回原因。开发者应能够实时查看申请进度、补充资料和处理结果。对于超出标准处理周期的申请,应提供明确的反馈及升级处理渠道,避免开发者陷入反复咨询、长期等待且无法确定结果的状态。同时,建议建立统一的开发者工单系统,避免不同服务分属不同团队、不同邮箱及不同处理流程,造成沟通成本过高。五、加强文档、SDK及跨平台开发体验建议进一步提升开发文档的完整性、及时性与一致性,提供可以直接运行的示例工程、清晰的错误码解释、版本兼容说明和迁移指南。对于已经在iOS、Android等平台运营的应用,应提供更成熟的跨平台迁移工具、能力差异说明与适配支持,降低应用进入鸿蒙生态的实际成本。六、建立以开发者效率为核心的生态评价机制建议华为不仅关注开发者数量、应用上架数量和生态规模,也将以下指标作为开发者生态建设的重要评价依据:从注册到首次成功调用开放接口所需的时间。从申请商业化能力到正式接入生产环境所需的时间。应用审核及权限审批的平均周期。开发者需要人工沟通、线下提交或重复认证的流程数量。开发者问题的首次解决率与工单处理效率。最后,我认为鸿蒙生态真正的竞争力,不应仅体现在操作系统技术本身,更应体现在开发者能否以更低成本、更高效率完成产品开发、上线和商业化经营。在2026年的全球移动应用市场中,开发者已经习惯了在线签约、自助配置、即时开通、自动化审核和标准化API服务。纸质合同往返邮寄、简单能力反复申请、依赖人工商务沟通的流程,应当逐步退出标准化互联网开发服务体系。建议华为坚持“默认开放、风险分级、在线办理、自动审核、统一管理”的原则,减少不必要的行政化流程,将更多决定权交还开发者。开发者需要的是高效、透明、稳定、可预期的技术平台,而不是在开发产品之外承担大量重复的流程性工作。希望华为能够持续优化相关机制,让更多独立开发者和中小技术企业有意愿、有能力、也有商业动力长期投入鸿蒙生态建设。

评论0

浏览 2

发布于18分钟前
刷视频评论叠加,切换深色模式和白天模式的时候评论会高曝看不清,莫名其妙会吞评论,前一秒还能看,点一下就全消失了!

评论0

浏览 3

发布于22分钟前
如果使用 js+arkts 开发  js文件在rawfile 中是否在hap被解压后 会明文显示?Rawfile中的文件是需要自己加密是嘛?

评论3

浏览 6

发布于43分钟前
Mate 80 Pro Max机型(设备型号代码:SGT-AL10),请问什么时候可以申请加入本轮招募白名单及开放呢?

评论321

浏览 15.3k

发布于2026-06-21 10:44

评论2

浏览 19

发布于1小时前
大佬们好,我是在鸿蒙上学习C语言的初学者。我在鸿蒙终端上使用了system("clear")的Linux清屏指令,可是出现了问题(如图中所示),鸿蒙的底层不是Linux吗为什么用不了,以及请问我可以如何解决这个问题呢?感谢解答!

评论5

浏览 33

发布于2小时前
找了半天的设置,还是没找到,以前4.2里面的触屏提示音。现在只有键盘的输入声音。麻烦大家帮忙解答一下,感谢,感谢。

评论1

浏览 26

发布于3小时前
Nova12、13、14Mate60、70这个月有希望吗 都好久了 不会等到10月吧

评论114

浏览 5.3k

发布于2026-08-12 23:09
更新为鸿蒙7.0后,微信收不到消息了,微信电话都没有收到,我看后台电池显示0到20点之间是前台时长2h后台0.5h。按网上教程,进入手机"设置" > "应用和元服务"(或"应用和服务中心")> 找到"微信" 后面找不到电池选项

评论6

浏览 35

发布于4小时前
自定义滤镜和颜色拾取插件直接调图形NDK,多窗口缩放时不同线程改屏幕尺寸、滤镜对象和渲染节点,会出现空指针、整数溢出和weak_ptr重复lock竞态,怎样在接口入口做长度类型边界、用原子或互斥保护共享计数,并在异步对象释放前确认Surface已不可见?

评论2

浏览 46

发布于4小时前
相机服务的预览流如何直接输出到 XComponent 的 Surface,当相机配置变更时如何避免预览画面撕裂或丢帧?

评论4

浏览 42

发布于4小时前
菜并快乐着
|
技术支持
【解决方案】相机预览流通过 XComponent(SURFACE 类型)实现零拷贝直出,核心是将 PreviewOutput 与 XComponent 的 surfaceId 绑定。预览画面撕裂/丢帧的根因是分辨率宽高比与 Surface 宽高比不一致,以及配置变更时 Surface 生命周期处理不当。通过保持宽高比一致、正确管理 Surface 生命周期、使用 setXComponentSurfaceRect 解耦区域,可彻底避免撕裂和丢帧。【实施步骤】步骤1:在 ArkTS 侧创建 XComponent 组件,类型设为 SURFACE("surface"),通过 XComponentController 获取 surfaceId步骤2:等待 XComponent onLoad 回调触发后,确认 surfaceId 有效,再创建 PreviewOutput:cameraManager.createPreviewOutput(profile, surfaceId)步骤3:从 getSupportedOutputCapability 获取设备支持的 previewProfiles,选取与目标宽高比最接近的 Profile(系统基本支持 16:9、4:3、1:1 三种比例)步骤4:将 PreviewOutput 添加到相机会话:session.addOutput(previewOutput),然后调用 session.start() 启动预览步骤5:当配置变更(折叠屏切换、摄像头切换、分辨率变更)时,按"先 stop 再重建"流程处理:session.stop() → session.removeOutput(previewOutput) → 等待新 Surface 就绪 → createPreviewOutput(newProfile, newSurfaceId) → session.addOutput(newPreviewOutput) → session.start()步骤6:若页面布局限制无法调整 XComponent 宽高,使用 setXComponentSurfaceRect() 将 Surface 区域与 XComponent 区域解耦,使 Surface 宽高比与分辨率宽高比保持一致步骤7:处理帧数据时使用 rowStride(image.Component.rowStride)而非分辨率宽度,避免花屏【代码示例】// XComponent 声明 XComponent({   id: 'xcomponentId',   type: 'surface',   controller: this.xComponentController })   .onLoad(() => {     // Surface 创建完成,获取 surfaceId     let surfaceId = this.xComponentController.getXComponentSurfaceId()     // 此时才能创建 PreviewOutput 并启动预览     this.startPreview(surfaceId)   }) // 创建预览输出流 let previewOutput = cameraManager.createPreviewOutput(profile, surfaceId) session.addOutput(previewOutput) session.start() // 配置变更时重建预览流 async rebuildPreview(newProfile, newSurfaceId) {   session.stop()   session.removeOutput(previewOutput)   // 等待新 Surface 就绪   let newPreviewOutput = cameraManager.createPreviewOutput(newProfile, newSurfaceId)   session.addOutput(newPreviewOutput)   session.start() } // Surface 区域解耦(布局受限时) xComponentController.setXComponentSurfaceRect({   surfaceWidth: calculatedWidth,   surfaceHeight: calculatedHeight,   offsetX: 0,   offsetY: 0 })【参考文档】- 相机预览花屏解决方案:https://device.harmonyos.com/cn/docs/apiref/harmonyos-guides/camera-preview-glitch-solution【注意事项】- 必须在 XComponent onLoad 回调后获取 surfaceId,在此之前 surfaceId 无效- 不要用 XComponent 组件宽高去筛选完全相同的分辨率,只需保持宽高比一致即可- 配置变更时不要保留旧 surfaceId 直接复用,必须销毁重建- 预览流与录像输出流的分辨率宽高比必须保持一致【备选方案】方案A:使用 setXComponentSurfaceRect 使 Surface 区域超出 XComponent 区域——超出部分被裁剪,画面无变形但可能不完整。适用于全屏预览场景。方案B:使用 setXComponentSurfaceRect 使 Surface 区域包含在 XComponent 区域内——未覆盖部分以黑色填充,画面完整无变形。适用于需要完整画面的场景。
点赞
回复于4小时前
创建的vpn不定时断开,软件后台没有结束。下面是日志,可以看到莫名的ondestory回调Dream VPN diagnostics v1 Exported: 2026-10-20T10:09:20.282Z Times are UTC. UI and VPN logs are separate; compare timestamps. === ui === 2026-10-19T02:14:41.597Z [EntryAbility] onCreate 2026-10-19T02:14:41.642Z [EntryAbility] onForeground 2026-10-19T02:15:19.883Z [SingBoxPage] diagnostic export requested 2026-10-19T02:17:06.435Z [EntryAbility] onBackground 2026-10-19T02:17:20.884Z [EntryAbility] onCreate 2026-10-19T02:17:20.943Z [EntryAbility] onForeground 2026-10-19T02:18:36.158Z [EntryAbility] onBackground 2026-10-19T02:23:33.945Z [EntryAbility] onForeground 2026-10-19T02:24:35.541Z [VpnController] connect requested 2026-10-19T02:24:35.541Z [VpnController] phase=starting, cleanup=true 2026-10-19T02:24:35.593Z [VpnBackgroundTask] data transfer continuous task started 2026-10-19T02:24:35.996Z [VpnController] phase=connected, cleanup=true 2026-10-19T02:26:34.054Z [EntryAbility] onBackground 2026-10-19T02:27:52.606Z [EntryAbility] onForeground 2026-10-19T02:27:58.324Z [EntryAbility] onCreate 2026-10-19T02:27:58.390Z [EntryAbility] onForeground 2026-10-19T02:29:19.853Z [EntryAbility] onCreate 2026-10-19T02:29:19.920Z [EntryAbility] onForeground 2026-10-19T02:31:22.463Z [EntryAbility] onCreate 2026-10-19T02:31:22.532Z [EntryAbility] onForeground 2026-10-19T02:32:43.914Z [EntryAbility] onCreate 2026-10-19T02:32:43.963Z [EntryAbility] onForeground 2026-10-19T02:33:21.929Z [EntryAbility] onBackground 2026-10-19T03:39:31.666Z [EntryAbility] onCreate 2026-10-19T03:39:31.736Z [EntryAbility] onForeground 2026-10-19T03:40:39.080Z [EntryAbility] onBackground 2026-10-19T03:40:50.878Z [EntryAbility] onForeground 2026-10-19T03:41:24.935Z [EntryAbility] onBackground 2026-10-19T05:32:08.738Z [EntryAbility] onCreate 2026-10-19T05:32:08.812Z [EntryAbility] onForeground 2026-10-19T05:32:09.158Z [EntryAbility] onBackground 2026-10-19T05:33:06.208Z [EntryAbility] onForeground 2026-10-19T05:33:10.059Z [VpnController] connect requested 2026-10-19T05:33:10.059Z [VpnController] phase=starting, cleanup=true 2026-10-19T05:33:10.099Z [VpnBackgroundTask] data transfer continuous task started 2026-10-19T05:33:11.133Z [VpnController] phase=connected, cleanup=true 2026-10-19T05:33:11.465Z [EntryAbility] onBackground 2026-10-19T05:44:15.842Z [VpnBackgroundTask] continuous task cancelled, reason=2 2026-10-19T05:44:15.861Z [VpnController] singbox_health_background_lost 2026-10-19T05:44:15.868Z [VpnController] phase=failed, cleanup=true 2026-10-19T05:44:17.577Z [VpnController] singbox_health_background_lost 2026-10-19T21:58:49.732Z [EntryAbility] onCreate 2026-10-19T21:58:49.787Z [EntryAbility] onForeground 2026-10-19T21:58:54.962Z [VpnController] connect requested 2026-10-19T21:58:54.963Z [VpnController] phase=starting, cleanup=true 2026-10-19T21:58:55.000Z [VpnBackgroundTask] data transfer continuous task started 2026-10-19T21:58:55.554Z [VpnController] phase=connected, cleanup=true 2026-10-19T21:58:56.141Z [EntryAbility] onBackground 2026-10-19T22:00:00.780Z [EntryAbility] onDestroy 2026-10-19T23:23:41.403Z [EntryAbility] onCreate 2026-10-19T23:23:41.473Z [EntryAbility] onForeground 2026-10-19T23:23:42.995Z [EntryAbility] onBackground 2026-10-20T00:19:55.184Z [EntryAbility] onCreate 2026-10-20T00:19:55.260Z [EntryAbility] onForeground 2026-10-20T00:20:08.088Z [EntryAbility] onBackground 2026-10-20T00:29:17.578Z [EntryAbility] onForeground 2026-10-20T00:29:22.195Z [VpnController] connect requested 2026-10-20T00:29:22.195Z [VpnController] phase=starting, cleanup=true 2026-10-20T00:29:22.220Z [VpnBackgroundTask] data transfer continuous task started 2026-10-20T00:29:22.601Z [VpnController] phase=connected, cleanup=true 2026-10-20T00:29:23.508Z [EntryAbility] onBackground 2026-10-20T00:29:44.453Z [VpnController] system VPN network lost; checking session 2026-10-20T00:29:45.958Z [VpnController] singbox_health_unresponsive 2026-10-20T00:29:45.963Z [VpnController] phase=failed, cleanup=true 2026-10-20T00:29:48.022Z [VpnController] singbox_health_unresponsive 2026-10-20T00:30:08.123Z [EntryAbility] onForeground 2026-10-20T00:30:09.571Z [SingBoxPage] diagnostic export requested 2026-10-20T00:30:09.624Z [VpnController] singbox_health_unresponsive 2026-10-20T00:30:14.132Z [VpnController] disconnect requested 2026-10-20T00:30:14.164Z [VpnController] phase=stopped, cleanup=false 2026-10-20T00:30:14.182Z [VpnBackgroundTask] data transfer continuous task stopped 2026-10-20T00:30:19.226Z [SingBoxPage] diagnostic export requested 2026-10-20T00:30:22.643Z [EntryAbility] onBackground 2026-10-20T02:27:15.190Z [EntryAbility] onCreate 2026-10-20T02:27:15.251Z [EntryAbility] onForeground 2026-10-20T02:27:43.062Z [EntryAbility] onBackground 2026-10-20T02:28:04.516Z [EntryAbility] onForeground 2026-10-20T02:28:37.231Z [VpnController] connect requested 2026-10-20T02:28:37.232Z [VpnController] phase=starting, cleanup=true 2026-10-20T02:28:37.593Z [VpnController] phase=connected, cleanup=true 2026-10-20T02:28:58.744Z [EntryAbility] onBackground 2026-10-20T05:37:19.325Z [EntryAbility] onCreate 2026-10-20T05:37:19.385Z [EntryAbility] onForeground 2026-10-20T05:37:24.889Z [VpnController] connect requested 2026-10-20T05:37:24.889Z [VpnController] phase=starting, cleanup=true 2026-10-20T05:37:25.439Z [VpnController] phase=connected, cleanup=true 2026-10-20T05:37:25.534Z [EntryAbility] onBackground 2026-10-20T06:31:56.022Z [EntryAbility] onCreate 2026-10-20T06:31:56.080Z [EntryAbility] onForeground 2026-10-20T06:32:01.630Z [VpnController] connect requested 2026-10-20T06:32:01.630Z [VpnController] phase=starting, cleanup=true 2026-10-20T06:32:01.961Z [VpnController] phase=connected, cleanup=true 2026-10-20T06:32:02.254Z [EntryAbility] onBackground 2026-10-20T08:38:09.153Z [EntryAbility] onForeground 2026-10-20T08:38:09.160Z [VpnController] system VPN network lost; checking session 2026-10-20T08:38:10.605Z [VpnController] singbox_health_unresponsive 2026-10-20T08:38:10.607Z [VpnController] phase=failed, cleanup=true 2026-10-20T08:38:13.281Z [VpnController] disconnect requested 2026-10-20T08:38:13.316Z [VpnController] phase=stopped, cleanup=false 2026-10-20T08:38:13.335Z [VpnNotification.clearConnected] code=1600007 2026-10-20T08:47:36.763Z [EntryAbility] onBackground 2026-10-20T10:09:13.098Z [EntryAbility] onForeground 2026-10-20T10:09:17.570Z [SingBoxPage] diagnostic export requested === vpn === 2026-10-19T02:24:35.782Z [SingBoxVpnAbility] onCreate 2026-10-19T02:24:35.904Z [SingBoxVpnAbility] TUN created, fd=33 2026-10-19T02:24:35.904Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-19T02:24:35.992Z [SingBoxVpnAbility] sing-box runtime started 2026-10-19T05:33:10.285Z [SingBoxVpnAbility] onCreate 2026-10-19T05:33:10.386Z [SingBoxVpnAbility] TUN created, fd=33 2026-10-19T05:33:10.386Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-19T05:33:11.130Z [SingBoxVpnAbility] sing-box runtime started 2026-10-19T21:58:55.366Z [SingBoxVpnAbility] onCreate 2026-10-19T21:58:55.460Z [SingBoxVpnAbility] TUN created, fd=32 2026-10-19T21:58:55.461Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-19T21:58:55.550Z [SingBoxVpnAbility] sing-box runtime started 2026-10-20T00:29:22.405Z [SingBoxVpnAbility] onCreate 2026-10-20T00:29:22.481Z [SingBoxVpnAbility] TUN created, fd=31 2026-10-20T00:29:22.484Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-20T00:29:22.598Z [SingBoxVpnAbility] sing-box runtime started 2026-10-20T02:28:37.411Z [SingBoxVpnAbility] onCreate 2026-10-20T02:28:37.472Z [SingBoxVpnAbility] TUN created, fd=31 2026-10-20T02:28:37.472Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-20T02:28:37.589Z [SingBoxVpnAbility] sing-box runtime started 2026-10-20T02:28:37.639Z [VpnNotification] connection status notification published 2026-10-20T03:12:10.022Z [SingBoxVpnAbility] onDestroy 2026-10-20T05:37:25.052Z [SingBoxVpnAbility] onCreate 2026-10-20T05:37:25.128Z [SingBoxVpnAbility] TUN created, fd=32 2026-10-20T05:37:25.128Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-20T05:37:25.436Z [SingBoxVpnAbility] sing-box runtime started 2026-10-20T05:37:25.479Z [VpnNotification] connection status notification published 2026-10-20T06:07:15.293Z [SingBoxVpnAbility] onDestroy 2026-10-20T06:32:01.779Z [SingBoxVpnAbility] onCreate 2026-10-20T06:32:01.836Z [SingBoxVpnAbility] TUN created, fd=32 2026-10-20T06:32:01.837Z [SingBoxVpnAbility] outbound socket protector registered 2026-10-20T06:32:01.955Z [SingBoxVpnAbility] sing-box runtime started 2026-10-20T06:32:01.990Z [VpnNotification] connection status notification published

评论5

浏览 57

发布于5小时前
现在开启混淆就像是开盲盒,开完了之后网络请求数据都回不来数据了。好麻烦啊。

评论4

浏览 27

发布于6小时前
上架一个运动记时小工具,预审2天正常吗?上传时显示预审大约3~4小时。如果预审超过2天,是不是一定是出了问题?

评论10

浏览 57

发布于7小时前
如何实现组件边缘的折射效果 背景纯透明 仅边缘折射效果 并且可以根据背景的变化实时进行预览的效果 这种相果 也就是苹果的液态玻璃效果 如何在鸿蒙当中使用arkui去实现液态玻璃的效果 能否完全复刻苹果的液态玻璃效果

评论51

浏览 834

发布于2026-09-05 02:57
云云
|
采纳答复
点赞5
回复于2026-09-10 06:57
显示已回合什么意思 还可以用嘛

评论7

浏览 67

发布于9小时前
仙银
|
采纳答复
fluwx 最新版 6.0.6 要求 Flutter >= 3.38.0(changelog 6.0.0-preview.1 原文:"Flutter 版本要求升级到3.38.0或更高"),所以 Flutter 3.35 用不了 fluwx 6.x。但 fluwx 5.x 系列也支持鸿蒙,而且对 Flutter 版本要求更低(Dart SDK >= 3.0 即可),5.7.7 是 5.x 最后一个版本。鸿蒙适配时间线是这样的:fluwx 从 5.1.0 开始试验性支持鸿蒙(changelog 原文:"试验性支持harmonyOS,目前受限于native sdk,只支持部分功能"),之后 5.2.7、5.4.0、5.5.x、5.7.x 一直在迭代鸿蒙端。所以 Flutter 3.35 + fluwx 5.7.7 是可以跑鸿蒙的。如果后续你把 Flutter 升到 3.38+,再切到 fluwx 6.0.6 就行——6.0.0-preview.10 的 changelog 写了"鸿蒙端加回来",说明 6.0 重构期间鸿蒙端一度被移除又加回来了,6.0.6 目前 HarmonyOS SDK=>1.0.19,鸿蒙端在持续维护。关于"已回合"——这个词在 flutter 鸿蒙生态里常见说法是"已合入",意思是代码已经合入主分支/正式发布。如果某个适配列表或文档里标注 fluwx"已合入",那就是说鸿蒙端的代码已经正式合进来了,可以用。另一个可能是你把"已回退"看成了"已回合",如果真是"已回退",那就是指鸿蒙适配一度被撤回——对应的就是 6.0.0-preview 阶段鸿蒙端曾短暂移除的情况,但 6.0.0-preview.10 已经加回来了,当前版本不受影响。另外有两点需要注意:fluwx 的 pub.dev 页面平台标签只标了 Android 和 iOS,没有标 HarmonyOS——这是因为 Flutter 的 pub.dev 平台标签体系里还没正式纳入 HarmonyOS,不代表不支持,只是标识还没跟上。鸿蒙端需要在 module.json5 里配置 querySchemes 才能检测微信是否安装,README 里有写:{ "module": { "querySchemes": [ "weixin" ] } }鸿蒙端调试签名不能用 IDE 自动签名,必须手动申请 debug 证书,这也是 fluwx README 明确提醒的。参考来源:fluwx changelog、fluwx README
点赞1
回复于8小时前
用 onTouch 处理按钮的触摸事件,但在真机上发现按下瞬间 Down 触发后,Move 状态紧接着也被触发,而且即使手指不移动,Move 也一直在打印,坐标值完全相同,同样的操作在模拟器上表现是正常的,这个在真机上是就是这样的还是说需要怎么处理一下?

评论8

浏览 37

发布于10小时前
我在做一个自定义弹窗,用的是 CustomDialogController 配合 @CustomDialog 装饰器,弹窗内容里放了一个 TextInput 输入框。结果发现一个很诡异的现象:弹窗能正常弹出,TextInput 也能看到,但点击输入框的时候,光标不出现,软键盘也不弹出来,就像点了没反应一样。如果我把同样的 TextInput 放在普通页面里,点击就正常弹出键盘。我试过:给 TextInput 加了 .focusable(true) 和 .defaultFocus(true),还是不行;在 onClick 里手动调 focusControl.requestFocus(),有时候能拿到焦点,但键盘还是不弹;把弹窗的 autoCancel 设成 false,点击遮罩层不关闭弹窗,键盘还是出不来。后来查了一下官方文档,发现 ArkUI 的弹窗是有焦点策略的:如果弹窗被设置为不获取焦点,那么它出现时就不会中断用户当前的操作,焦点会保留在原来的输入框上,软键盘也不会关闭。反过来,如果弹窗默认获取焦点,就会“抢走”输入焦点,导致弹窗内部的 TextInput 反而拿不到焦点。还有社区帖子明确说“自定义弹窗与键盘目前无法同时显示”。想请教几个问题:CustomDialog 里 TextInput 拿不到焦点、弹不出键盘,根本原因到底是什么? 是弹窗的焦点策略默认就把输入组件屏蔽了,还是弹窗的遮罩层抢走了焦点?官方文档提到的 focusable 参数,在 CustomDialog 和 openCustomDialog 这两种弹窗 API 上都能用吗?CustomDialogController 和 openCustomDialog 在焦点管理上有什么区别? 我看到 focusable 参数从 API 19 开始可以用来控制弹窗是否获取焦点。那如果我用的是老版的 CustomDialogController,有没有办法设置 focusable?还是说必须迁移到 openCustomDialog?如果弹窗本身需要接收点击(比如里面有按钮),但又不想抢走 TextInput 的焦点,应该怎么配置? 我看到有人说可以设置 focusable: false 来防止弹窗获取焦点。那设置 focusable: false 之后,弹窗里的按钮还能正常点击吗?弹窗的关闭手势(点击遮罩层或返回键)会不会受影响?TextInput 的 enableKeyboardOnFocus 属性在弹窗场景下有没有影响? 我看到文档说 enableKeyboardOnFocus 设为 false 时,只有通过点击、按键走焦才能弹出系统软键盘。如果弹窗里的 TextInput 是通过代码 requestFocus 获取的焦点,是不是必须把这个属性设成 true 才能让键盘弹出来?我看到有人说可以用 @Builder + bindSheet 或者 bindContentCover 来替代 CustomDialog,这几种弹窗方案在焦点管理和键盘交互上有什么区别?哪种对输入框最友好?如果只是做一个简单的表单弹窗,有没有更推荐的方案?

评论7

浏览 46

发布于10小时前
设备/环境:SGT-AL10 · HarmonyOS 7.0.0.105 · API 26 · DevEco Studio(hms SDK,UIDesignKit 声明 6.1.0(23)/6.1.1(24));应用 metadata 已配置 ohos.arkui.UIMaterial.state = "enable";targetAPIVersion ≥ 26;entry 模块;系统设置"沉浸光感" = 强(最高档)。问题现象:底部导航(悬浮胶囊 + 独立圆形)由普通 ArkUI 组件(Stack/Row)通过 systemMaterial(new uiMaterial.ImmersiveMaterial(...)) 接入沉浸式系统材质。HarmonyOS 7.0.0.105 SP6 系统更新之前:胶囊呈现真实玻璃质感(折射/光晕/通透)。SP6 更新之后:同一代码、同一设备、未改任何配置——胶囊变成纯透明的卡片(背后内容直接透出,无任何材质滤镜/折射/高光;看起来就像完全没有材质)。已按官方文档验证:按"沉浸光感"官方指南示例 1 的写法复刻(Column/Stack + .backgroundColor(Color.Transparent) 写在 .systemMaterial(...) 之前 + borderRadius + 顺序正确),同样失效。按"通用组件封装"实践(ImmersiveSurface:独立组件 + BuilderParam 内容 + 透明背景 + borderRadius + clip(true) + systemMaterial 最后),同样失效。运行时探针证据(关键):deviceInfo.apiAvailable('26.0.0') = true;uiMaterial.getMaterialInfo().state = 1(≠ DISABLE)→ 应用侧门全过;new uiMaterial.ImmersiveMaterial({ style: REGULAR, materialColor: '#80FF0000', interactive: true, lightEffect: {color: undefined} }) 传入 systemMaterial 后,50% 红色 materialColor 在画面上零差异(胶囊未变粉)——证明材质滤镜完全未被渲染(不是"样式选错/背景遮挡"类问题)。对照:同一设备上,系统组件的表面(如音乐条、系统设置预览)沉浸光感正常;HDS HdsTabs 官方悬浮页签(barFloatingStyle.systemMaterialEffect,materialType/materialLevel 模式)玻璃材质正常——唯独第三方应用里自定义 ArkUI 节点的 systemMaterial 不渲染。求助点:自定义 ArkUI 组件(Stack/Row/Column 等普通容器)的 systemMaterial 在 7.0.0.105(SP6) 是否被限制/降级?是否已有已知问题或需要新的启用条件?应用侧如何判定设备的沉浸光感算力档位(低/中/高)与全局材质等级?官方指南示例 5 提到 uiMaterial.getGlobalMaterialLevel() / uiMaterial.isImmersiveMaterialSupported(),但当前 SDK 的 ArkTS 声明中不存在这两个 API(能力清单 ArkUI.json 中有声明,since 26.0.0)——这是声明回退还是需要更高 SDK 补丁?如果自定义组件的材质确实无法恢复,官方推荐的自定义底部导航正确载体是什么(HDS 已确认可用,但存在自定义页签内容/动画限制)?代码片段(完整:普通 ArkUI 组件 + 沉浸光感)以下 = 生产组件中"普通 ArkUI 组件 + 材质接入"的完整相关代码(约 120 行)。 说明:生产组件在此之上还包含滑动指示器层与手势(PanGesture 拖拽切页、按压反馈、 动画图标),与本问题无关,故省略;如需完整工程可再提供。import { uiMaterial } from '@kit.ArkUI'; import { deviceInfo } from '@kit.BasicServicesKit'; interface MainDestination { index: number; outlineSymbol: Resource; fillSymbol: Resource; label: string; } @ComponentV2 export struct BottomNav { @Param selectedIndex: number = 0 @Event onSelect: (index: number) => void = () => {} @Local materialAvailable: boolean = false private readonly mainDestinations: MainDestination[] = [ { index: 0, outlineSymbol: $r('sys.symbol.message'), fillSymbol: $r('sys.symbol.message_fill'), label: 'Chat' }, { index: 1, outlineSymbol: $r('sys.symbol.person_crop_circle_fill_1'), fillSymbol: $r('sys.symbol.person_crop_circle_fill_1'), label: 'Contacts' }, { index: 2, outlineSymbol: $r('sys.symbol.gearshape'), fillSymbol: $r('sys.symbol.gearshape_fill'), label: 'Settings' } ]; private immersiveMaterial: uiMaterial.ImmersiveMaterial | undefined = undefined; aboutToAppear(): void { try { this.materialAvailable = deviceInfo.apiAvailable('26.0.0'); if (this.materialAvailable) { const info = uiMaterial.getMaterialInfo(); this.materialAvailable = info.state !== uiMaterial.MaterialState.DISABLE; } this.immersiveMaterial = this.materialAvailable ? new uiMaterial.ImmersiveMaterial({ interactive: true, lightEffect: { color: undefined } // 注:曾显式设置 style(ULTRA_THIN/THIN/REGULAR…)逐档测试,均无视觉差异 }) : undefined; } catch (err) { this.materialAvailable = false; this.immersiveMaterial = undefined; } } private surfaceFallbackColor(): ResourceColor { // 材质可用时透明(不遮挡材质);不可用时回退半透明浅底 return this.materialAvailable ? Color.Transparent : $r('sys.color.comp_background_tertiary'); } @Builder DestinationButton(d: MainDestination) { Column({ space: 2 }) { SymbolGlyph(this.selectedIndex === d.index ? d.fillSymbol : d.outlineSymbol) .fontSize(22) .fontColor([this.selectedIndex === d.index ? $r('sys.color.icon_emphasize') : $r('sys.color.icon_primary')]) Text(d.label) .fontSize(10) .fontColor(this.selectedIndex === d.index ? $r('sys.color.icon_emphasize') : $r('sys.color.icon_primary')) } .justifyContent(FlexAlign.Center) .layoutWeight(1) .height('100%') .backgroundColor(Color.Transparent) .onClick(() => { this.onSelect(d.index); }) .accessibilityGroup(true) .accessibilityText(d.label) .accessibilitySelected(this.selectedIndex === d.index) } build() { // 普通 ArkUI 组件:透明全宽 Row 宿主,仅定位两个"普通容器表面" Row({ space: 12 }) { // 表面 1:主胶囊(共享材质实例) Stack() { Row() { ForEach(this.mainDestinations, (d: MainDestination) => { this.DestinationButton(d) }, (d: MainDestination) => `${d.index}`) } .width('100%') .height('100%') } .layoutWeight(1) .height(56) // 普通容器 + 普通属性 .borderRadius(28) .clip(true) .shadow({ radius: 24, color: 'rgba(0,0,0,0.16)', offsetX: 0, offsetY: 6 }) .backgroundColor(this.surfaceFallbackColor()) // ← 写在 systemMaterial 之前(官方顺序) .systemMaterial(this.immersiveMaterial!) // ← 通用属性接入沉浸式系统材质 // 表面 2:独立圆形(同一材质实例) Stack() { Stack() { Text('A').fontSize(22).fontWeight(FontWeight.Medium).fontColor(Color.White) } .alignContent(Alignment.Center) .width(44) .height(44) .borderRadius(22) .backgroundColor('#0A59F7') } .alignContent(Alignment.Center) .width(56) .height(56) .borderRadius(28) .clip(true) .shadow({ radius: 24, color: 'rgba(0,0,0,0.16)', offsetX: 0, offsetY: 6 }) .backgroundColor(this.surfaceFallbackColor()) .systemMaterial(this.immersiveMaterial!) .onClick(() => { this.onSelect(3); }) .accessibilityGroup(true) .accessibilityText('Profile') } .width('100%') .padding({ left: 20, right: 20 }) .margin({ bottom: this.systemInsetVp() + 8 }) // 底部安全区留白 .backgroundColor(Color.Transparent) .hitTestBehavior(HitTestMode.Transparent) } }结构说明(避免"组件不普通"的误判):全程仅使用 Stack/Row/Column/Text/SymbolGlyph + 通用属性(width/height/borderRadius/clip/shadow/backgroundColor/onClick/accessibility);唯一与系统的耦合点 = 表面的 .backgroundColor(Color.Transparent) 与 .systemMaterial(...);两个表面共享一个 uiMaterial.ImmersiveMaterial 实例(aboutToAppear 中创建)。总结:就是我在修复一个问题终于修复成功的时候然后突然发现主界面底部胶囊退化,让我非常摸不着头脑,我修改别的东西为什么会影响到底部胶囊。想来想去,唯一怀疑的线索也只有昨天下午进行的一次系统更新。

评论34

浏览 1k

发布于2026-08-30 02:06
半本前瞻
|
技术支持
点赞1
回复于2026-08-31 01:24
表单在手机填一半转到平板继续,金额、发票图片、审批人多选都在V2模型里,怎样把未提交草稿按设备能力做差异同步,平板补完大段说明后回手机不丢失光标位置,且输入法候选不会因跨设备重新绑定而清空正在组合的中文拼音?

评论4

浏览 29

发布于10小时前
我在做一个混合开发的功能,Web 组件加载本地的 H5 页面,H5 页面里有个表单,提交的时候走的是 POST 请求。我想在 onInterceptRequest 里拦截这个请求,拿到表单数据后自己做处理,然后再把响应返回给 H5。代码大概是这样:textWeb({ src: this.pageUrl, controller: this.webController }) .onInterceptRequest((event) => { if (event) { const request = event.request console.log('method: ' + request.getRequestMethod()) const body = request.getRequestPostData() console.log('body: ' + JSON.stringify(body)) } })结果发现 getRequestPostData() 返回的一直是空的,getRequestMethod() 能正常拿到是 POST,但请求体就是拿不到。我试过:H5 那边确认表单数据是有提交的,用浏览器抓包能看到 payload 里有内容;换成 GET 请求拦截,getRequestUrl() 能正常拿到,说明拦截本身是生效的;把 getRequestPostData() 换成 getRequestPostDataString() 也试了,还是拿不到。后来查了一下官方文档,才发现 onInterceptRequest 接口本身就明确不支持获取 Post Data。官方原话是:“onInterceptRequest接口中无法获取Post Data,如果想要获取Post Data需使用SchemeHandler机制来进行拦截”。英文文档也写了:“You cannot obtain post data using the onInterceptRequest API. To obtain post data, use the SchemeHandler mechanism”。还有帖子提到,这是出于安全考虑,拦截请求时默认不暴露请求体数据。想请教几个问题:SchemeHandler 拦截 POST 请求的正确用法是什么? 我看到 SchemeHandler 提供了 ArkTS 和 NDK 两套接口。ArkTS 侧是通过 webview.WebSchemeHandler 来设置,需要在请求开始的回调里告知 Web 内核是否拦截,在请求结束的回调里清理资源。那 WebSchemeHandler 的具体 API 怎么用?有没有完整的 ArkTS 示例可以参考?SchemeHandler 拦截到的请求体,是通过什么对象拿到的? 我看到 NDK 侧有一个 ArkWeb_HttpBodyStream 结构体,用于在自定义 Scheme 请求拦截场景中获取 HTTP 请求的 body 数据,可以读取请求体的原始字节流。那 ArkTS 侧有没有对应的接口?还是说只能走 NDK?SchemeHandler 的设置时机有什么讲究? 文档提到“需要在 Web 组件初始化之后设置 SchemeHandler,否则会设置失败”,而且“若要拦截 Web 组件发出的第一个请求,可以通过 initializeWebEngine 方法提前进行 Web 组件初始化,再设置 SchemeHandler”。如果我的 Web 组件是动态创建的,这个初始化时序应该怎么安排?自定义 scheme 的注册规则是什么? 文档说“如果要拦截自定义 scheme 的请求,需要在 Web 组件初始化之前将自定义 scheme 注册到 Web 内核,初始化后再注册会失败”。那如果我要拦截的是普通的 https POST 请求,也需要提前注册吗?还是说 https 默认就可以拦截?SchemeHandler 和 onInterceptRequest 的适用场景有什么区别? 我现在的情况是只需要读一下 POST body 做日志记录,并不想替换响应内容。用 SchemeHandler 拦截的话,怎么做到“只读不改”,让请求继续走网络?有没有类似 return null 表示放行的机制?

评论3

浏览 75

发布于10小时前
卖报小作家
|
技术支持
尊敬的开发者,您好,关于您的反馈的问题,onInterceptRequest 接口出于安全考虑,设计上不暴露 POST 请求体数据,这是 API 的既定行为而非 Bug。要获取 POST body,需要改用 SchemeHandler 机制进行请求拦截。SchemeHandler 在 ArkTS 侧通过 webview.WebSchemeHandler 提供,支持在 onRequestStart 回调中通过 request.getHttpBodyStream() 获取请求体字节流,无需走 NDK。【实施步骤】步骤1:在 aboutToAppear 或 EntryAbility.onCreate 中调用 webview.WebviewController.initializeWebEngine() 提前初始化 Web 内核(确保能拦截到 Web 组件发出的第一个请求)步骤2:创建 WebSchemeHandler 对象,设置 onRequestStart 回调和 onRequestStop 回调步骤3:在 onRequestStart 回调中,通过 request.getHttpBodyStream() 获取 POST 请求体,通过 request.getRequestUrl()、request.getRequestMethod()、request.getHeader() 等获取请求基本信息步骤4:通过 this.controller.setWebSchemeHandler('https', this.schemeHandler) 将 SchemeHandler 设置到 controller,拦截 https 请求(https 默认支持拦截,无需提前注册自定义 scheme)步骤5:在 onRequestStop 回调中清理资源,避免内存泄漏【代码示例】ArkTS侧示例代码:import { webview } from '@kit.ArkWeb'; import { BusinessError } from '@kit.BasicServicesKit'; import { util } from '@kit.ArkTS'; @Entry @Component struct WebComponent { controller: webview.WebviewController = new webview.WebviewController(); schemeHandler: webview.WebSchemeHandler = new webview.WebSchemeHandler(); build() { Column() { Button('Reload') .fontSize($r('app.float.page_text_font_size')) .fontWeight(FontWeight.Bold) .onClick(() => { try { this.controller.loadUrl($rawfile('H5Index.html')); } catch (error) { let err: BusinessError = error; console.error(`web controller loadUrl error, ErrorCode: ${err.code}, Message: ${err.message}`); } }); Web({ src: 'resource://rawfile/H5Index.html', controller: this.controller }) .height('50%') .javaScriptAccess(true) .domStorageAccess(true) .fileAccess(false) .geolocationAccess(false) .onControllerAttached(() => { this.schemeHandler.onRequestStart((request: webview.WebSchemeHandlerRequest) => { try { console.info(`[schemeHandler] onRequestStart url: ${request.getRequestUrl()}`); console.info(`[schemeHandler] onRequestStart method: ${request.getRequestMethod()}`); console.info(`[schemeHandler] onRequestStart isMainFrame: ${request.isMainFrame()}`); console.info(`[schemeHandler] onRequestStart frame url: ${request.getFrameUrl()}`); let header = request.getHeader(); for (let i = 0; i < header.length; i++) { console.info(`[schemeHandler] onRequestStart header: ${header[i].headerKey} ${header[i].headerValue}`); } let stream = request.getHttpBodyStream(); if (stream) { console.info('[schemeHandler] onRequestStart has http body stream'); stream.initialize().then(() => { if (!stream) { console.info('[schemeHandler] onRequestStart initialize no stream'); return; } stream.read(stream.getSize()).then((buffer) => { if (!stream) { console.info('[schemeHandler] onRequestStart read no stream'); return; } console.info(`[schemeHandler] onRequestStart postDataStream readLength: ${buffer.byteLength}`); let decoder = util.TextDecoder.create('utf-8', { ignoreBOM: true }); let str = decoder.decodeToString(new Uint8Array(buffer), { stream: false }); let postData = decodeURIComponent(str); console.info(`[schemeHandler] onRequestStart postDataStream content: ${postData}`); this.getUIContext().showAlertDialog({ message: postData, confirm: { value: '关闭', action: () => { console.info('Close alert dialog'); this.controller.loadUrl($rawfile('H5Index.html')); } } } ); }).catch((error: BusinessError) => { let err: BusinessError = error; console.error(`[schemeHandler] onRequestStart read stream error, ErrorCode: ${err.code}, Message: ${err.message}`); }); }).catch((error: BusinessError) => { let err: BusinessError = error; console.error(`[schemeHandler] onRequestStart initialize stream error, ErrorCode: ${err.code}, Message: ${err.message}`); }); } else { console.info('[schemeHandler] onRequestStart has no http body stream'); } } catch (error) { let err: BusinessError = error; console.error(`[schemeHandler] onRequestStart error, ErrorCode: ${err.code}, Message: ${err.message}`); } return false; }); try { this.controller.setWebSchemeHandler('https', this.schemeHandler); } catch (error) { let err: BusinessError = error; console.error(`setWebSchemeHandler error, ErrorCode: ${err.code}, Message: ${err.message}`); } return null; }); } .justifyContent(FlexAlign.SpaceEvenly) .width('100%') .height('80%') } }  H5侧示例代码(所在目录:src/main/resources/rawfile):<!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>登录注册</title> </head> <body> <h1>注册</h1> <form action="https://www.demo.com" method="post"> <p style="font-family:arial;font-size:20px;">项目编码:<input type="text" name="code"></p> <p style="font-family:arial;font-size:20px;">项目名称:<input type="text" name="name"></p> <p style="font-family:arial;font-size:20px;">项目地址:<input type="text" name="address"></p> <p style="font-family:arial;font-size:20px;"> <input type="submit"> <input type="reset"> </p> </form> </body> </html>合作愉快。华为开发者联盟
点赞
回复于9小时前
使用 TaskPool 做文件批量解析,子线程抛出异常后主线程捕获不到错误信息,NAPI 对象在线程传递时还偶现内存崩溃,该怎么处理?

评论7

浏览 43

发布于10小时前
Z
|
推荐答复
两个问题的根因不同,分开说。一、子线程异常主线程捕获不到TaskPool 子线程的异常是能传回主线程的,但前提是你得写对。最容易踩的坑是:子线程函数里用了 Promise 但没有 await,异常就丢了。官方文档说得很清楚——如果并发异步函数里用了 Promise,建议用 await,这样 TaskPool 才能捕获 Promise 里的异常。不 await 的 Promise 抛异常,TaskPool 看不到,主线程自然 catch 不到。另外一种情况:你的函数里同步抛了异常但外层没包 try-catch,TaskPool 的 execute 本身返回 Promise,子线程异常会走 reject,主线程用 .catch 或 try/await 就能接到。如果你没接,那当然"捕获不到"。正确写法(@Concurrent 函数不能调用同文件内的函数,业务逻辑要内联或放独立文件 import):import { taskpool } from '@kit.ArkTS'; import { BusinessError } from '@kit.BasicServicesKit'; @Concurrent async function parseFile(filePath: string): Promise<string> { if (filePath.length === 0) { throw new Error('filePath is empty'); } return 'parsed: ' + filePath; } async function runBatch(): Promise<void> { const files: string[] = ['/data/a.txt', '', '/data/b.txt']; for (const file of files) { const task: taskpool.Task = new taskpool.Task(parseFile, file); try { const res: string = await taskpool.execute(task) as string; console.info(`success: ${res}`); } catch (e) { const err = e as BusinessError; console.error(`failed: code=${err.code}, msg=${err.message}`); } } }要点:子线程函数里的异步操作必须 await,主线程对 execute 的 Promise 必须 catch。二、NAPI 对象跨线程传递偶现内存崩溃这个根因很明确:napi_env 和 napi_value 不能跨线程共享。官方 FAQ 直说了——napi_env 和 ArkTS 线程强绑定,缓存 env 拿到别的线程用,直接崩(NDK线程开发中的Env使用问题)。napi_value 同理,不同 worker 间不共享(napi_env跨worker共享)。你在 TaskPool 子线程里拿主线程的 napi_env/napi_value 去调 NAPI 接口,就是典型的跨线程违规。偶现崩溃是因为时序问题——有时候碰巧线程还没切换上下文就调了,有时候就踩到了。解法是用线程安全函数 napi_create_threadsafe_function,在主线程创建,子线程通过它回调到主线程执行 NAPI 操作(使用Node-API接口进行线程安全开发)。核心代码模式:// C++ 侧:主线程创建线程安全函数 napi_value onStart(napi_env env, napi_callback_info info) { napi_value jsCb; size_t argc = 1; napi_get_cb_info(env, info, &argc, &jsCb, nullptr, nullptr); napi_value resourceName; napi_create_string_utf8(env, "ParseCallback", NAPI_AUTO_LENGTH, &resourceName); napi_threadsafe_function tsfn; napi_create_threadsafe_function(env, jsCb, nullptr, resourceName, 0, 1, nullptr, nullptr, nullptr, CallJs, &tsfn); // 把 tsfn 传给工作线程 // ... return nullptr; } // CallJs 在主线程执行,安全使用 napi_env static void CallJs(napi_env env, napi_value jsCb, void* context, void* data) { napi_value undefined; napi_get_undefined(env, &undefined); napi_call_function(env, undefined, jsCb, 0, nullptr, nullptr); } // C++ 子线程调用 void WorkerThread(napi_threadsafe_function tsfn) { // 不用 napi_env,直接用 tsfn napi_call_threadsafe_function(tsfn, nullptr, napi_tsfn_nonblocking); }如果你需要在 TaskPool 子线程把 NAPI 解析结果传回主线程,ArkTS 侧也可以用 taskpool.Task 的 sendData 把纯数据(不是 napi_value)发回主线程,避免在子线程碰任何 NAPI 对象。简单说:子线程只做纯计算和数据组装,NAPI 调用全部回到主线程或通过线程安全函数执行,不要把 napi_env/napi_value 带过线程边界。
点赞
回复于9小时前
用 HdsTabs 做底部 Tab,默认看起来像有"包边"。示例代码如下所示:HdsTabs({ index: this.currentTabIndex, controller: this.tabsController }) { TabContent() { } .tabBar(this.TabTextBuilder(this.tabTitles[0], 0)) // …… } .barFloatingStyle({ barWidth: { smallWidth: 280, mediumWidth: 300, largeWidth: 320 }, barBottomMargin: 8, gradientMask: { maskColor: Color.Transparent }, lightColor: Color.Transparent, systemMaterialEffect: { materialType: hdsMaterial.MaterialType.IMMERSIVE, materialLevel: hdsMaterial.MaterialLevel.EXQUISITE } }) .barPosition(BarPosition.End) .barOverlap(true) .barBackgroundColor(Color.Transparent) .barBackgroundBlurStyle(BlurStyle.NONE) .divider({ mode: DividerMode.NONE })最终的效果是:期望的效果是,无边框线的:

评论42

浏览 334

发布于2026-09-25 09:17
云上
|
采纳答复
这个问题的根因楼上老师们已经定位了:那圈"包边"是 systemMaterialEffect 沉浸光感材质(IMMERSIVE)自带的边缘高光,和毛玻璃是捆绑效果,三档 materialLevel 只是强度差异。我补充一个还没有人提到的中间路线——用低层 API 自己叠材质,把"系统毛玻璃质感"和"边缘光感"真正解耦:思路:背景模糊用 windowBlur / backgroundEffect,而不是 barBackgroundBlurStylebarBackgroundBlurStyle 的 COMPONENT_THIN 档观感确实比系统材质弱一截(楼主实测也证实了)。想要更接近 EXQUISITE 的磨砂质感,可以试 backgroundEffect,它提供可调参数,能逼近系统材质的观感:.barBackgroundColor(Color.Transparent) .backgroundEffect({ radius: 40, // 模糊半径,调到接近 EXQUISITE 的雾面感 saturation: 1.2, // 饱和度略提,模拟系统材质的通透感 brightness: 1.05, // 轻微提亮 colorOptions: [{ color: '#80FFFFFF', cornerRadius: 28 }] // 白色薄纱 + 圆角 })这个路径出来的效果介于 COMPONENT_THIN 和系统材质之间,且不会带边缘描边,多数设计稿能对上。如果必须要系统材质:换 MaterialType 而不是降档补一个实测细节:MaterialType.IMMERSIVE(沉浸光感)是"毛玻璃+边缘光"捆绑的来源,但 hdsMaterial 里还有其他 materialType(如标准材质),不同 type 的边缘表现不一样。可以试把 materialType 换掉、materialLevel 保持 EXQUISITE,部分 type 下毛玻璃质感保留而边缘高光明显减弱,这比无脑降到 SMOOTH 更接近"只要毛玻璃"的目标。具体各 type 的视觉差异建议在真机上对照 Demo 各跑一遍(模拟器的材质渲染和真机偏差较大)。最后说下取舍楼主自己实测的结论(两者不可兼得)在"只用 systemMaterialEffect 预设"的前提下成立;但走 backgroundEffect 自绘这条路,毛玻璃 + 无边框是可以同时拿到的,只是放弃了系统材质的动态光影(点光源、按压流光)。如果产品要求的是"静态毛玻璃无包边",自绘完全够用;如果要求系统级动态光影,那只能接受边缘光或等官方提供解耦参数,可以顺手在 DevEco Studio 的 Send Feedback 里提个需求。x
点赞1
回复于2026-09-30 07:46

我要提问题

月度答复贡献榜
用户头像
橙动创意
回帖893
粉丝57
关注
用户头像
心系天下
回帖678
粉丝17
关注
用户头像
蓝瘦的蜕变
回帖411
粉丝120
关注
用户头像
飞b6
回帖314
粉丝8
关注
用户头像
仙银
回帖261
粉丝95
关注
邀您回答
关于 HarmonyOS 开发者生态开放能力及商业化流程的意见与建议
斗音bug
热门标签
1

HarmonyOS 5

2

HarmonyOS 6

3

DevEco Studio

4

UI

5

HarmonyOS

6

ArkUI (方舟UI框架)

7

HarmonyOS 7

8

App开发

9

Ability框架

了解社区公约,与您携手共创和谐专业的开发者社区。
在 App 中查看