ARTICLE DETAIL

资讯详情

深耕网站视觉设计与运营推广的一线实战洞察。

悬浮窗有 6 个状态,第 5 个叫“在悬浮球里“

悬浮窗有 6 个状态,第 5 个叫“在悬浮球里“ 起因我一开始以为悬浮窗和悬浮球是同一套东西的两种外观。写代码的时候才发现它们分别在两个文件里各有各的判断接口各有各的创建接口。而在其中一个模块里还有一个函数叫bind。翻完声明文件之后我对这两个能力的理解变了。而且有个发现让我停了很久悬浮窗的状态枚举里有一个状态直接叫“在悬浮球里”。一、两个模块两张门票文件有两个不是同一个ets/api/ohos.window.floatView.d.ts约 40 KBets/api/ohos.window.floatingBall.d.ts约 24 KB各自的入口函数几乎对称。悬浮窗模块functionisFloatViewEnabled():boolean;// 第 87 行functioncreate(config:FloatViewConfiguration):PromiseFloatViewController;// 第 105 行悬浮球模块functionisFloatingBallEnabled():boolean;// 第 46 行functioncreate(config:FloatingBallConfiguration):PromiseFloatingBallController;// 第 60 行两个都返回Promise都有独立的 enabled 判断。这里有个容易踩的点isFloatViewEnabled()和isFloatingBallEnabled()是两个独立开关。系统可能支持悬浮窗但不支持悬浮球反过来也一样。你的代码如果只判断其中一个就去创建另一个会在运行时失败。二、bind()把两者绑成一个整体悬浮窗模块里有这么一对函数第 150 行和第 173 行functionbind(floatViewController:FloatViewController,floatingBallController:floatingBall.FloatingBallController,floatingBallParams:floatingBall.FloatingBallParams):Promisevoid;functionunbind(floatViewController:FloatViewController,floatingBallController:floatingBall.FloatingBallController):Promisevoid;注意参数类型floatView模块的bind函数签名里直接引用了floatingBall命名空间下的类型。两个模块在这里合流了。把它们绑起来之后得到的是一个组合形态悬浮球当常驻的小入口悬浮窗当展开后的内容面板。用户点球出窗、收起成球两个控制器之间由系统负责同步。这个设计解释了后面两节会看到的现象。三、证据在状态机里第 5 个状态叫在悬浮球里FloatViewState在第 742 行共六个状态enumFloatViewState{STARTED1,// 第 750 行HIDDEN2,// 第 760 行STOPPED3,// 第 768 行IN_SIDEBAR4,// 第 776 行IN_FLOATING_BALL5,// 第 784 行ERROR6// 第 792 行}[配图位 1ohos.window.floatView.d.ts 第 742 行FloatViewState 枚举全貌导入后用编辑器图片按钮插入插完删除本行]IN_FLOATING_BALL这个状态是上一节bind()的直接体现。悬浮窗被收进悬浮球时它不是停止了也不是一般的隐藏而是进入了一个专门的、可以被bind重新唤起的状态。另外注意不可见这件事有三种完全不同的情况。HIDDEN被隐藏IN_SIDEBAR被收进了侧边栏IN_FLOATING_BALL被收进了悬浮球三者的恢复路径不一样能不能恢复也不一样。如果你的判断写成状态不是STARTED就重新创建悬浮窗那这几种情况你都会处理错。正确做法是分别处理尤其IN_FLOATING_BALL要走unbind或重新bind的路径而不是重新create。顺带说这个枚举也是从 1 开始没有 0。和上一篇写画中画时看到的PiPState一致。四、对比一下悬浮球只有两个状态FloatingBallState在第 386 行enumFloatingBallState{STARTED1,// 第 393 行STOPPED2// 第 400 行}只有两个。这个对比很说明问题悬浮窗的生命周期比悬浮球复杂得多。悬浮球有就是有、没有就是没有而悬浮窗要在屏幕、侧边栏、悬浮球之间来回流转所以需要六个状态来表达。如果你的产品里悬浮球只是一个常驻的入口那它的状态处理会很简单复杂度和坑都在悬浮窗这边。五、getFloatViewLimits()主动查询限制这是我在这个模块里觉得最实用、也最少被提到的一个函数第 190 行functiongetFloatViewLimits(templateType:FloatViewTemplateType):FloatViewLimits;传入模板类型返回这个模板下的限制。FloatViewLimits定义在第 667 行三个字段minSize:window.Size;// 第 675 行maxSize:window.Size;// 第 683 行ratioLimits:ArrayRatioLimit;// 第 691 行而RatioLimit在第 642 行只有两个字段minRatio:number;// 第 650 行maxRatio:number;// 第 658 行这套 API 的价值在于它是查询式的不是约定式的。悬浮窗能开多大、宽高比要在什么范围内不是文档里定死的常量而是可以运行时问出来的。ratioLimits是数组说明同一个模板下可能存在多段合法的宽高比区间而不是一个连续范围。如果你的窗口尺寸计算假设了一个最小值到一个最大值遇到分段限制就会算错。这类先问限制再设尺寸的写法比按经验设一个尺寸然后被系统拒绝靠谱得多。六、两个模板枚举起点不一样悬浮窗的模板第 545 行enumFloatViewTemplateType{ROUNDED_RECTANGLE0,// 第 553 行HORIZONTAL_BAR1// 第 561 行}悬浮球的模板第 408 行enumFloatingBallTemplate{STATIC1,// 第 416 行NORMAL2,// 第 424 行EMPHATIC3,// 第 432 行SIMPLE4// 第 440 行}悬浮窗的从 0 开始悬浮球的从 1 开始。两个模块同一个 SDK同一个能力域枚举起点不一致。这已经是本系列第三次遇到这种情况了断点枚举从 0 开始画中画状态从 1 开始现在这两个模板又各走各的。结论很简单也很实用不要用真假值判断枚举。用比较具体成员或者用switch穷举。顺便注意一个语义细节悬浮窗模板是几何形状圆角矩形、横向条悬浮球模板是视觉强调程度静态、普通、强调、简洁。两套分类逻辑不在一个维度上不要试图映射。七、stopReason是字符串FloatViewStateChangeInfo在第 700 行state:FloatViewState;// 第 708 行stopReason:string;// 第 733 行第二个字段的类型是string不是错误码。这和上一篇画中画里的stateChange回调一致那边的第二个参数reason也是字符串。这个设计有好有坏。好处是信息量大能直接读到为什么停。坏处是不能用switch穷举判断也不能做本地化映射只能拿去做日志。如果你的代码要根据停止原因做分支处理得自己写字符串匹配。这在对版本升级敏感的代码里是个隐患因为字符串内容可能随版本调整而类型系统拦不住这种变化。相对稳妥的做法是只把reason用于日志分支逻辑仍然基于state。八、悬浮球的一个细粒度能力FloatingBallTextUpdateAnimationType在第 465 行enumFloatingBallTextUpdateAnimationType{ANIMATION_NONE0,// 第 473 行ANIMATION_OPACITY1// 第 481 行}这个枚举是给悬浮球上的文字发生变化这个场景用的有两个选项不动画或者淡入淡出。颗粒度到这一步说明悬浮球上的文字更新是个被认真对待的场景。如果你的悬浮球要显示未读数、状态文字这类会变的内容这个参数值得设一下否则文字会硬切观感差。几处和常见理解不一样的地方悬浮窗和悬浮球是两个模块各有独立的isFloatViewEnabled()和isFloatingBallEnabled()判断一个不等于判断另一个bind()能把两者绑成一个整体参数签名里直接引用了另一个模块的类型FloatViewState的六个状态里有一个叫IN_FLOATING_BALL这是绑定的直接体现不可见有三种HIDDEN、IN_SIDEBAR、IN_FLOATING_BALL三者恢复路径不同悬浮球只有两个状态复杂度远低于悬浮窗的六个getFloatViewLimits()可以运行时查询尺寸和宽高比限制ratioLimits还是数组说明限制可能是分段的两个模板枚举起点不一致一个从 0 一个从 1stopReason是字符串只能当日志用不适合做分支判断写浮窗功能之前建议先想清楚一件事你要的是悬浮窗、悬浮球还是两者绑定后的组合形态。这三个答案对应的代码结构差别很大而bind这套 API 的存在本身就说明官方认为第三种是常见的做法。补充说明本篇没有跑通截图。手边没有真机模拟器也无法验证悬浮窗的实际窗口行为所以文中只做声明层面的核对每个结论都标了行号可以自行打开对照。涉及运行期表现的地方我按注释原文转述没有替官方补充结论。本系列其他文章我把 HarmonyOS 的折叠屏 API 翻了一遍10 个折叠状态你大概只处理了 3 个我读了 HarmonyOS 的断点声明有 5 个档位高度断点算的其实是宽高比画中画起不来的三种原因设备支持、设置开关、窗口可见是三件事
返回列表