news 2026/10/2 20:40:34

【共创稿事节】HarmonyOS 7空间信息层级:焦点、景深与注意力引导

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【共创稿事节】HarmonyOS 7空间信息层级:焦点、景深与注意力引导

平面界面里,用户的眼睛被屏幕边界框着,注意力顶多在矩形内跳来跳去。空间界面没有这个框,用户能看的地方变多了,注意力反而更容易散。这时候设计的活儿就是主动引导:明确告诉用户"先看这里,再看那里"。焦点和景深是两把最顺手的工具。

焦点怎么建立

让一个元素成为视觉焦点,可用的手段不止放大一种。把它们列全了,才好知道什么时候用哪个:

手段具体做法强度副作用
尺度放大元素、缩短视距强占视野,挤压周围
亮度提高brightness,焦点更亮中过亮会刺眼
对比焦点明、背景暗,或反色强对比过强显生硬
位置放在视线中心、中轴线上强与舒适区绑定
颜色焦点用饱和色,背景降饱和中品牌色过多会失效
运动焦点有微动,背景静止强滥用会干扰阅读
清晰度焦点实,背景虚强算力开销

这些手段单独用都成立,但叠两到三种就够。七种全上,用户看到的是一团互相打架的信号,焦点反而没了。经验值是:尺度 + 清晰度作为主手段,亮度或颜色作为辅助,运动只在需要"抓住"用户时用。

一个常见问题:焦点一堆,等于没有焦点。空间界面里,同一时刻的强焦点建议只留一个,其余降一档。

景深(DoF)为什么能引导注意力

景深原本是光学概念——镜头对焦在某段距离上,那段距离内清晰,前后逐渐模糊。人眼本身也有这个机制,所以"清晰 vs 模糊"天然对应"关注 vs 忽略",不需要额外学习。

在 ArkUI 里没有真正的物理景深相机,但可以用视觉信号模拟,而且效果够用:

  • 模糊:blur(value)给离焦层加模糊,值越大越虚,单位 px;
  • 亮度:brightness(value)乘数调亮度,值小于 1 变暗(1 为原样);
  • 饱和度:saturate(value)降饱和(1 为原样),让离焦内容退成灰调;
  • 透明度:opacity降透明,让离焦层更"退后";
  • 线性渐变模糊:linearGradientBlur可以只在某个方向上渐次模糊,适合做"近处清晰、远处渐散"的空间纵深。

组合起来就是一套"离焦权重":

// 离焦程度 0~1:0 为完全聚焦,1 为完全离焦@Builderdefocused(level:number){Column(){// 组件内容}.blur(level*14)// 模糊随离焦加深.brightness(1-level*0.35)// 变暗,退到次要位置.saturate(1-level*0.6)// 降饱和,收掉颜色干扰.opacity(1-level*0.25)// 稍微透明}

这几个值按同一个level联动,比各调各的要稳。聚焦态level = 0,完全一致地回到原样。

视觉权重怎么分配

多层信息同时在场时,给每层定一个"权重预算",避免所有东西都在喊"看我"。下面是一份可直接套用的起始表,权重总和控制在 100% 以内:

层级尺度亮度系数饱和度模糊 px透明度权重预算
焦点1.01.051.001.055%
次焦点0.950.90.80~40.9525%
内容0.90.80.76~100.915%
环境0.80.60.514~200.85%

这套值不是硬规定,是"起步价"。真正落地时按场景调,但层级之间要拉开可见的差距,相邻两层差别太小,用户读不出主次。

焦点切换的参数化实现

把上面这张表写成一个可复用的焦点档位,用枚举表达语义,代码里就不会到处散落魔法数字。

// 焦点档位:越靠前权重越高enumFocusLevel{Focus=0,// 焦点Secondary=1,// 次焦点Content=2,// 内容Ambient=3// 环境}// 每个档位对应一组视觉参数interfaceFocusStyle{blur:numberbrightness:numbersaturate:numberopacity:numberscale:number}functionstyleOf(level:FocusLevel):FocusStyle{switch(level){caseFocusLevel.Focus:return{blur:0,brightness:1.05,saturate:1.0,opacity:1.0,scale:1.0}caseFocusLevel.Secondary:return{blur:3,brightness:0.9,saturate:0.8,opacity:0.95,scale:0.96}caseFocusLevel.Content:return{blur:8,brightness:0.78,saturate:0.68,opacity:0.9,scale:0.92}default:return{blur:16,brightness:0.6,saturate:0.5,opacity:0.8,scale:0.88}}}

案例:空间化通知中心的聚焦切换

手机通知中心就是把一堆通知平铺排列,用户靠滑动和分组找重点。空间化后,可以让通知卡片围成一圈或几排,用户把视线落在哪张卡上,那张卡就自动进入焦点档,其余按距离退到次焦点、内容、环境档。

// NotificationOrbit.ets —— 通知卡片环形排布,聚焦项自动升权@Entry@Componentstruct NotificationOrbit{// 当前聚焦的卡片索引,-1 表示无聚焦@StatefocusIndex:number=-1// 示例通知数据privatenotices:string[]=['日程提醒','系统更新','消息回复','待办临近','快递到达','账单提醒']// 根据与聚焦项的距离推导档位:越远越离焦privatelevelFor(index:number):FocusLevel{if(this.focusIndex<0)returnFocusLevel.Content// 未聚焦时全部等权constdist=Math.abs(index-this.focusIndex)if(dist===0)returnFocusLevel.Focusif(dist===1)returnFocusLevel.Secondaryif(dist===2)returnFocusLevel.ContentreturnFocusLevel.Ambient}build(){Stack({alignContent:Alignment.Center}){ForEach(this.notices,(text:string,index:number)=>{Column(){Text(text).fontSize(16).fontColor(Color.White)}.width(160).height(96).borderRadius(16).backgroundColor('#1E2740')// 用角度把卡片摆成一圈,转头的动作对应切换聚焦.rotate({angle:index*30,centerX:'50%',centerY:'700%',perspective:1200}).applyFocus(this.levelFor(index))// 自定义扩展:套用焦点档位.onHover((isHover:boolean)=>{// 视线/指针落在哪张卡上,哪张卡成为焦点this.getUIContext()?.animateTo({duration:220,curve:Curve.Friction},()=>{this.focusIndex=isHover?index:-1})})},(text:string)=>text)}.width('100%').height('100%').backgroundColor('#0B1020')}}// 通过 AttributeModifier / 自定义修饰器把 FocusStyle 落到组件上@Extend(Column)functionapplyFocus(level:FocusLevel){.blur(styleOf(level).blur).brightness(styleOf(level).brightness).saturate(styleOf(level).saturate).opacity(styleOf(level).opacity).scale({x:styleOf(level).scale,y:styleOf(level).scale})}

这套逻辑的关键是档位由"距离"推导,而不是每张卡单独设状态。聚焦项一动,整排的权重自动重排,不用维护一堆if。onHover在这里只是示意入口,实际项目里换成onFocus、视线追踪回调或者指针位置都可以。

命中卡片 i

用户视线/指针移动

落在哪张卡片

focusIndex = i

按距离推导档位

i 本身:Focus 档

i±1:Secondary 档

更远:Content / Ambient 档

前移 + 去模糊 + 提亮

轻微后退 + 微模糊

后退 + 强模糊 + 降饱和

聚焦与离焦的对照

维度聚焦(Focus)离焦(Defocus)
距离感近,前移远,后退
清晰度实,blur=0虚,blur 随距离递增
亮度略提亮压暗
颜色保持饱和降饱和
动效前移、轻微呼吸静止、退让
交互接收输入关闭命中

小小经验

  • 同一时刻一个强焦点。两个同等强度的焦点会互相削弱,用户的视线会在两者间来回跳。
  • 模糊是"降权",不是装饰。如果只是想加个好看的虚化,别用 blur,它会被用户读成"这里不用看"。
  • 聚焦切换要快。200~250ms 左右,比深度层级切换(300~400ms)更快,因为它是高频动作。
  • 给离焦内容留"回来的路"。离焦不等于消失,保留轮廓和轻度可读性,用户才知道可以移回去。
  • 亮度优先于模糊做降权。模糊开销大,能用亮度和饱和度区分的场合,别急着上 blur。

容易出问题的地方哦

  • 所有元素一起提亮做焦点。提亮是全屏相对概念,全都亮等于全都没亮,得留暗部做对比。
  • blur 值给太大。超过 20px 的内容基本认不出,用户会以为加载失败,而不是"这里次要"。
  • 聚焦态还保持可点。离焦的卡片如果还能点,用户误触后会觉得"我没看它怎么触发了",建议离焦层关闭或降低命中优先级。
  • 只改视觉不改顺序。焦点在视觉上是前面的,但如果zIndex没跟着调,它可能被后面的卡片盖住。
  • 动画里同时改太多属性。blur、brightness、scale 一起重算,低端设备容易掉帧,建议聚焦切换时限制在 2~3 个属性同时变化。
  • 忽略个体差异。有的人对运动敏感,大范围的聚焦动画可能引起不适,建议给系统级的"减少动效"开关留一个退化路径。
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/10/2 20:38:10

【LeetCode Hot100】199.二叉树的右视图和56.合并区间

【LeetCode Hot100】199.二叉树的右视图和56.合并区间 摘要 这篇文章用来记录我在练习 hot100 中题号199和题号56的做题过程。 199. 二叉树的右视图 先来看199题——二叉树的右视图。题目见下图&#xff1a;第一次思路 我第一次的做题思路是既然我们是要右视图&#xff0c;那么…

作者头像 李华
网站建设 2026/10/2 20:37:07

Superpowers实战:为Codex CLI构建规划记忆与审查的AI协作层

你用过Codex CLI吗&#xff1f;如果你和我一样&#xff0c;花了几周时间让它处理真实项目&#xff0c;大概率会碰到同一个尴尬&#xff1a;小任务很惊艳&#xff0c;一旦涉及多文件修改、跨模块重构、需要遵守项目里既有约定时&#xff0c;它就变成一个“健忘的天才”——上下文…

作者头像 李华
网站建设 2026/10/2 20:35:38

UART通信详解:从物理层电平到STM32 HAL库配置与调试实战

UART在我眼里一直是通信协议里最“亲民”的那个。它只有两根数据线&#xff0c;没有时钟线&#xff0c;协议帧结构简单到看一眼就能记住&#xff0c;可它承载了无数嵌入式设备从调试到量产的全过程。我最早接触单片机就是从点亮LED和printf重定向开始的&#xff0c;而那个print…

作者头像 李华
网站建设 2026/10/2 20:34:57

System Prompt 膨胀:你的 AI 有多少预算给了“自我介绍“?

&#x1f44b; Hi&#xff0c;带娃的我热爱 AI 大模型应用落地、意识解码与 AI 开发工具链 。 &#x1f4a1; 创业路上&#xff0c;用技术换时间&#xff0c;一起把 AI 变成生产力 &#x1f680; >System Prompt 膨胀&#xff1a;你的 AI 有多少预算给了"自我介绍"…

作者头像 李华