首页/新闻资讯/正文详情

〖共创稿事节〗HarmonyOS 7 新特性实战(41):地图何时全屏——分栏里的临时合并与退出复原

发布时间:2026/11/5 23:37:44 来源:云帆数科 栏目:资讯中心
〖共创稿事节〗HarmonyOS 7 新特性实战(41):地图何时全屏——分栏里的临时合并与退出复原
# 〖共创稿事节〗HarmonyOS 7 新特性实战41地图何时全屏——分栏里的临时合并与退出复原平板分栏做好之后点「在地图上选」打开 3D 地图屏幕上出现了三样东西左栏被地图盖住右栏还挂着另一张地图页中间那条 4vp 的拖动手柄还骑在分隔线上。一张地图两个窗口一条缝。这件事的难点不在「怎么让地图变大」。把覆盖层的容器宽度从 948 改成整窗是一行的事。难的是三个问题什么时候该变大、变大之后怎么回去、以及变大期间那些按宽度摆位的东西怎么办。一、分栏之后地图变成了两张先把现场说清楚。首页探索页和右栏那张地图页是两个不同的组件左栏是ShanhaiWorldPageContent地图覆盖层长在它内部右栏是MAP_PAGE这个 destination渲染的是ShanhaiWorldMapPage。分栏状态下点开地图覆盖层只铺满它所在的容器也就是左栏。于是位置打开地图前打开地图后左栏navBar探索页地图覆盖层948vp 宽右栏content地图常驻页地图常驻页没变栈没动过中间4vp 拖动手柄4vp 拖动手柄还骑着屏幕宽 1440vp左栏 948vp右栏 492vp中间一条线。用户点的是「看地图」看到的是一张被切成两半的地图。二、先回答「谁该全屏」分栏不是全局开关是逐页决定的。这个应用里各页的归属很明确页面该不该全屏理由3D 地图沉浸探索全屏看的是整幅地貌切一半就没法读异兽详情分栏左栏列表要一直在方便连点着看古籍目录 / 篇章分栏目录是导航正文是被导航的内容主题弹层 / 超分查看器全屏弹层天然盖住一切判据其实只有一句这一页的内容是不是「一张图」。是图就全屏是「列表 内容」就分栏。地图属于前者而且是唯一一个「内容在左栏、右栏反而是另一张地图」的页面——这也是它最先暴露问题的原因。三、为什么不把覆盖层搬出去最直接的想法是把覆盖层从首页里搬出来挂到整窗那一层。试过三条路都不划算。搬到 Navigation 外面覆盖层的云幕过渡、区域停留定时器、场景就绪回调全绑在首页组件上搬出去等于把这些状态一起搬家云幕那套动效要重写。做成NavDestinationMode.DIALOG的 destination主题弹层和超分查看器就是这么做的hideNavBar(true)一收内容区拿到整窗宽度DIALOG 自然满屏。机制是现成的但同样要把云幕和停留定时器搬进 destination而且云幕是首页的招牌动效回归风险不小。清空栈再切Stack模式语义最直白但退出时重建栈会重放转场动画观感容易花。最后选的是第四条不搬组件把分栏临时合并。左栏拉满整窗、右栏让到 0覆盖层还铺在自己的容器里只是这个容器此刻就是整窗。代价是三个布局属性都要跟着改而且退出时必须能原样回去。好处是覆盖层的代码一行没动。四、三个属性缺一不可三个都是Navigation的布局属性语义见 Navigation 组件参考navBarWidth是导航栏宽度navBarWidthRange是它的合法区间minContentWidth是内容区的最小宽度。三者叠在一起才决定最终谁占多宽。.navBarWidth(this.effectiveNavBarWidth()) .navBarWidthRange([SPLIT_MIN_NAV_BAR, this.effectiveNavBarUpperBound()]) .minContentWidth(this.effectiveMinContentWidth())三个都走取值函数函数内部判断「现在是不是沉浸态」。少改任何一个都会留一条缝属性平时沉浸时漏改的表现navBarWidth用户拖出来的 948窗口宽 1440地图停在 948右边半屏还是地图页navBarWidthRange上限1000窗口宽1440 被夹回 1000右边剩 440minContentWidth3600右栏被硬留 360左栏最多到 1080第二条最容易被忽略navBarWidth传了整窗宽但navBarWidthRange的上限还是 1000框架会把它夹回去表现是「明明写了 1440量出来 1000」。第三条同理minContentWidth是硬约束不归零就永远差一截。三条改完实测布局树里NavBar [0,86][2879,1920]窗口 2880 宽右栏NavDestination数量从 1 变成 0——那一栏被压到零宽连节点都不渲染了。五、合并的时机在云幕里「沉浸态」用什么判据是这个改动里最容易写错的地方。第一版用的是showWorldMap也就是用户点下「在地图上选」那一刻。结果打开地图的瞬间右栏先被抽走、左栏先撑满云幕还没升起来——一次没有遮挡的重排肉眼就是「屏幕闪了一下」。正确的判据是mapOverlayMounted覆盖层的实际挂载态private isImmersiveMapActive(): boolean { return this.mapOverlayMounted this.shouldSplitLayout(); }这个值由云幕过渡在CLOUD_CLOSE_GATE_MS760ms那一刻翻转而云幕本身的上升动画是 1100ms。也就是说合并发生在云幕已经铺了大半的时候两张图对比就能看出差别400ms 时云幕只盖左栏、分隔线还在900ms 时云幕已经是整幅。合并这一下没有单独的视觉事件它搭在云幕上升的过程里。关闭时同理方向相反showWorldMap先翻 false云幕升起760ms 后才卸载覆盖层并复原分栏——复原也在云幕里。第二个条件是shouldSplitLayout()手机单栏时左栏本来就是整窗再去拉满只是白改一次布局属性。它只看窗口宽高不看测量结果。六、开关不能读结果判据里不能用isSplitLayout()。那个方法量的是「两栏是不是真的都在屏幕上」Navigation宽减去 navBar 宽差值超过 100vp 才算分栏。合并之后 navBar 就等于整窗差值是 0它会翻成 false——然后「是不是沉浸态」变成 false合并被取消navBar 缩回去差值又超过 100又变成沉浸……在两帧之间来回抖。这是这个项目里第二次栽在同一件事上。第一次是分栏开关本身拿测量结果去驱动mode()Stack态两栏等宽、判据恒为假永远进不了Split。结论是一样的——开关读窗口结果读测量两者不能混。七、复原不需要代码一开始打算「记住合并前的宽度退出时恢复」。写的时候发现根本不需要/** * 左栏实际生效的宽度。 * * 沉浸时拉满整窗其余时候就是用户拖出来的 splitNavBarWidth。 * **这里只读不写** —— 退出沉浸不需要「恢复」动作因为用户那个值从头到尾没被动过。 */ private effectiveNavBarWidth(): number { if (this.isImmersiveMapActive()) { return this.navigationWidthVp; } return this.splitNavBarWidth; } /** 左栏宽度上限。沉浸时必须放到整窗否则 navBarWidth 会被 range 夹回 1000。 */ private effectiveNavBarUpperBound(): number { if (this.isImmersiveMapActive()) { return this.navigationWidthVp; } return SPLIT_MAX_NAV_BAR; } /** 右栏最小宽度。沉浸时归零否则 Navigation 一定给右栏留 360vp。 */ private effectiveMinContentWidth(): number { if (this.isImmersiveMapActive()) { return SPLIT_IMMERSIVE_MIN_CONTENT; } return SPLIT_MIN_CONTENT; }沉浸时返回窗口宽但不把它写回splitNavBarWidth。用户拖出来的那个值从头到尾没被动过退出时函数走 else 分支自然就是原值。「不写回」这件事必须守住写回去的代价是永久的splitNavBarWidth会在下次拖动手势结束时被saveShanhaiSplitWidth()落盘存进去的就是那个被污染的满宽之后每次冷启左栏都是满的。实测退出后NavBar [0,86][1896,1920]与沉浸前的 1896 一致。八、还有两样东西杵在那儿左栏拉满之后有两样东西不会自动消失因为它们不是按 navBar 宽度排版的。拖动手柄。它按splitNavBarWidth定位合并后那个位置正好在地图中间而且它还能拖一拖就从地图里拽出一条缝。条件里加一条Builder SplitHandle() { // 沉浸地图开着时不画手柄此刻左栏被拉满整窗手柄仍按 splitNavBarWidth // 定位会明晃晃地骑在地图中间而且它还能拖一拖就从地图里拽出一条缝。 if (this.isSplitLayout() !this.isOverlayLayerVisible() !this.isImmersiveMapActive()) { Column() { Column() .width(this.splitDragging ? SPLIT_HANDLE_GRIP_WIDTH 1 : SPLIT_HANDLE_GRIP_WIDTH) .height(this.splitDragging ? SPLIT_HANDLE_GRIP_HEIGHT 16 : SPLIT_HANDLE_GRIP_HEIGHT) .borderRadius(SPLIT_HANDLE_GRIP_WIDTH / 2) .backgroundColor(this.isDarkMode ? #8CF2E9D8 : #663B3229) } .width(SPLIT_HANDLE_WIDTH) .height(100%) .justifyContent(FlexAlign.Center) .backgroundColor(#00000000) .position({ x: this.splitNavBarWidth - SPLIT_HANDLE_WIDTH / 2, y: 0 }) .gesture( PanGesture({ fingers: 1, direction: PanDirection.Horizontal, distance: 1 }) .onActionUpdate((event: GestureEvent) { const next: number this.splitDragStartWidth event.offsetX; this.splitNavBarWidth Math.min( this.splitNavBarUpperBound(), Math.max(SPLIT_MIN_NAV_BAR, next) ); }) ) } }宽屏侧栏。侧边导航是 109vp 固定宽在SideShell()里无条件渲染底栏那个hideBottomNav管不到它。不处理的话「全屏」就只是「地图变宽了」左边还立着一条导航。这里没有复用hideBottomNav它在宽屏下还代表「二级页」接进来会让所有二级页在平板上都丢掉侧栏改动面远大于这件事。新加一个hideSideNav只在地图挂载时传 trueProp hideSideNav: boolean false; Builder private SideShell() { Row() { if (!this.hideSideNav) { ShanhaiSideNav({ activeTab: this.activeTab, isDarkMode: this.isDarkMode, onSwitch: (index: number) { this.onSwitch(index); } }) Column() {} .width(1) .height(100%) .backgroundColor(this.dividerColor) .opacity(0.55) } Column() { // 当前 tab 的内容 } .layoutWeight(1) .height(100%) } .width(100%) .height(100%) .backgroundColor(this.shellBackground) }九、返回键把应用退了前面几节都改完地图能铺满整窗、能复原、手柄和侧栏都不见了。然后按了一下返回键——应用退到桌面。排查过程很短因为栈里的东西很清楚右栏那张常驻地图页仍然在栈里只是被压成零宽节点还在系统返回键先派给它而它的onBackPressed干的第一件事是terminateSelf().onBackPressed(() { // 右栏常驻页不吃「出栈」这一下出栈只会让右栏变成一片白。 // 栈里只剩它时按返回 离开应用。 try { const context this.getUIContext().getHostContext() as common.UIAbilityContext; context.terminateSelf(); } catch (err) { /* ... */ } return true; })它的设计前提是「栈里只剩我 用户在主界面按返回」。分栏之后这个前提不成立了左栏才是主界面右栏只是常驻页而地图覆盖层盖在两者之上。修法是在它前面补一句判据if (this.consumeOverlayBack()) { return true; }阅读流那四个 destination目录 / 篇章 / 专题 / 异兽详情早就调了这个方法只有这一页漏了——它是分栏之后才有的页面写的时候没考虑「上面还可能压着一个浮层」。改完再按返回地图收起、分栏复原、应用还在。十、验收三条退出路径地图有三条退出路径每条都要能把分栏复原。退出方式判据结果点页头返回箭头云幕收起后NavBar回到 1896右栏NavDestination回到 1 个通过按系统返回键同上改之前是terminateSelf()通过点地图上的区域停 900ms → 自动收起 → 分栏复原 → 当前区域变「西山」通过这些约束固化成了门禁六组断言合并条件必须同时看挂载态与窗口断点、三个布局属性都必须走取值函数、满宽不得写回状态值、手柄必须排除沉浸态、常驻页的返回键必须先消费浮层、宽屏侧栏必须由独立开关控制。反向验过两处删掉手柄的沉浸判据、把minContentWidth换回常量 360门禁都直接报错。全量 45 个校验脚本复跑 45/45 通过。还剩什么没验模拟器上 3D 场景不可用走的是平面地图回退。平面图按ImageFit.Contain保持比例所以在 1440vp 宽的窗口里地图本身只占中间一条竖带两侧是云海天幕——这不是分栏的问题是回退模式的取景方式但「3D 场景铺满整窗」这件事没有证据。手机档没上机。单栏时判据恒为 false三个布局属性与改前完全一致逻辑上不会有变化但没有截图。还有一处已知的不一致沉浸期间isSplitLayout()会翻成 false右栏宽度是 0测量结果自然不成立。目前受影响的只有「栈空补地图」那个守护而沉浸期间栈里本来就有常驻页不需要补。哪天有别的逻辑开始依赖这个判据得回来重新看一遍。

相关推荐

无人机 GNSS 定位故障全解析:遮挡、多路径、干扰与欺骗的判别、处理与预防
无人机 GNSS 定位故障全解析:遮挡、多路径、干扰与欺骗的判别、处理与预防

前言 本文面向一线无人机飞手与运维工程师,聚焦飞行中最常见也最致命的 GNSS 定位故障。全文系统梳理信号遮挡、多路径反射、射频干扰、欺骗、星况与 DOP 劣化五类问题,逐类给出成因、原理、判别、处理与预防。读完你可以快速判断"飞机为什么不知道… · 2026/11/2 23:49:52

PLC系统设计与实操流程,一篇讲清楚
PLC系统设计与实操流程,一篇讲清楚

一、PLC 系统设计五步核心流程1. 需求分析(设计基础)1) 明确控制对象:电机、阀门、传感器、执行器等设备类型与数量;2) 信号梳理:a) 输入信号(DI/AI):按钮、传感器(光电 … · 2026/11/2 23:40:33

地面站参数龄期详解:从差分龄期判读到异常排查与处置的完整指南
地面站参数龄期详解:从差分龄期判读到异常排查与处置的完整指南

地面站参数龄期详解 本文面向使用 RTK 定位的无人机飞手、地面站操作员与编队运维人员,聚焦地面站上「参数龄期」这一常被忽视却直接决定定位精度的指标。文章从龄期定义讲起,说明 0-1 正常、3 异常的判读依据,梳理异常成因与处置流程&#… · 2026/11/3 1:10:50

EasyU优启通PE维护盘实战指南:制作、启动与核心操作全解析
EasyU优启通PE维护盘实战指南:制作、启动与核心操作全解析

1. 为什么一个PE维护盘值得单独拿出来聊装系统、修引导、救数据、清病毒,这些活儿但凡干过几次的人都知道,真正决定效率的往往不是你手速多快,而是手边那套PE环境靠不靠谱。EasyU(圈内习惯叫优启通)就是在这个场景下被… · 2026/11/5 16:49:35

Rust原来很简单二:所有权系统
Rust原来很简单二:所有权系统

Part 2 核心篇 —— 所有权系统 本篇覆盖 第 6 ~ 10 章:所有权、借用与引用、生命周期、字符串与切片、内存模型。 ⚠️ 这是全书最重要的一篇。 把它吃透,Rust 从此“很简单”;跳过它,你会处处碰壁。请慢下来,动手敲每一段代码。 第 6 章 所有权:Rust 的第一性原理 6… · 2026/11/5 16:26:08

基于Hadoop+Spark的民宿智能推荐系统设计与实现
基于Hadoop+Spark的民宿智能推荐系统设计与实现

1. 项目概述:大数据时代的民宿智能推荐这个毕业设计项目融合了当前大数据领域最主流的技术栈,构建了一个完整的民宿推荐系统解决方案。作为一名长期从事大数据系统开发的工程师,我认为这个选题非常贴合实际应用场景——随着旅游业的复苏和共享… · 2026/11/5 14:59:25

ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计
ADS122U04IPWR+STM32F427ZI工业级温度测量信号链设计

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 14:10:41

UART接口24位ADC搭配RS485,解决远距离温度监控难题
UART接口24位ADC搭配RS485,解决远距离温度监控难题

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 14:10:41

UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践
UART接口24位ADC搭配PIC18F46K22的RTD与热电偶测温实践

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 14:10:41

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:07

多智能体协作系统架构设计与实践优化
多智能体协作系统架构设计与实践优化

1. 多智能体协作系统的时代背景2017年Transformer架构的诞生彻底改变了人工智能的发展轨迹。当行业还沉浸在单一大模型带来的性能突破时,Anthropic的研究团队已经将目光投向了更前沿的领域——如何让多个智能体通过协作产生超越单体能力的系统智能。这就像交响乐团中… · 2026/11/5 0:00:39

大模型系统性入门实战指南:从原理到部署微调的全链路路线
大模型系统性入门实战指南:从原理到部署微调的全链路路线

提到大模型的系统性入门,我先说个结论:这事真不难,难的是资料太散、路线太多,今天这个框架明天那个工具,新人很容易在“收藏夹吃灰”和“教程看到一半放弃”之间反复横跳。市面上关于大模型的内容少说有几十万篇&#… · 2026/11/5 0:00:39

鸿蒙文件系统沙箱机制解析与开发实践
鸿蒙文件系统沙箱机制解析与开发实践

1. 鸿蒙文件系统沙箱机制深度解析作为一名从Android转向鸿蒙开发的工程师,我深刻体会到文件系统访问是迁移过程中最先遇到的"拦路虎"。在Android上运行良好的文件读写代码,在鸿蒙真机环境却频频出现文件写入后神秘消失或直接抛出权限拒绝错误的… · 2026/11/5 0:00:39

双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试
双极步进电机控制实战:DRV8818PWPR与PIC18F86K22驱动调试

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:27:59

STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析
STM32F207ZG + DRV8818PWPR 步进电机驱动实战解析

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:03

DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案
DRV8818PWPR+dsPIC30F4013工业级双极步进电机控制方案

/* MD / 富文本中的 .toc(含博客园搬家等嵌套结构);.toc-box 在侧栏,不受影响 */#content_views .toc,/* 编辑器常在目录前后插入空 p(:empty 仍占 20px),一并去掉避免顶空隙 */#content_views.markdown_views > p:empty:has(+ .toc),#content_views.markdown_views … · 2026/11/5 10:28:07

了解更多?预约专属演示

我们的顾问将为您一对一讲解产品与方案

企业微信二维码