HarmonyOS 7设计师的 3D 思维养成:从平面构图到空间叙事

做平面 UI 久了,会养成一套肌肉记忆:先画框、再排内容、最后调留白和对齐。这套方法在 2D 里非常高效,但把它原样搬到空间里,做出来的东西往往"有纵深、没逻辑"——元素都浮起来了,用户却不知道自己该看哪、该往哪走。问题不在工具,在思维。

这一篇拆三个最需要补的思维转换,每个都配一个能直接落到 ArkUI 里的做法。

构图变成空间叙事:先想动线,再想画面

平面构图的核心目标是"一屏之内,信息读得顺"。空间设计的核心目标变成了"一段时间内,视角推得动"。

区别在于,平面作品是可以一眼看全的静态画面,空间作品是被观看的过程。你画的不是一张图,是一段路径:用户从哪进、先看到什么、被什么吸引往前走、最后停在哪。

落到实际操作上,平面稿通常先问"这块放什么";空间稿要先问三个问题:

  1. 用户的起始视点在哪?默认朝向是什么?
  2. 主任务在哪个焦平面?它需要独占还是和上下文共存?
  3. 从起始点到主任务,中间要不要给缓冲(一眼就看到全部,反而没有探索感)?

这三个问题决定了纵深怎么分层。把答案画成一张"叙事线"图,比直接摆元素有用得多。

图层变成空间层级:zIndex 不等于 Z 轴

设计工具里,图层是堆叠顺序;3D 工具里,层级是空间事实。这是最容易混淆的一处。

在 Figma 里把一层移到最上面,只是"盖住别的"。在空间里把元素放到 z 更大的位置,它同时获得了:更近的透视、更大的视觉尺寸(近大远小)、更强的注意力权重,以及可能的遮挡关系。一次赋值,四种后果。

所以在空间稿里,图层命名习惯要改。别再叫"背景层/内容层/弹窗层"这种按绘制顺序起的名字,改成按空间职责命名:

平面命名习惯空间命名建议含义
背景层环境层 Environment提供氛围,不参与交互,通常 z 最远
内容层主体层 Focus承当前主任务,占据舒适焦平面
浮层上下文层 Context与主体相关的补充信息,略靠前或靠后
弹窗层叠加层 Overlay需要打断当下的临时信息,最近处

改名字看着是小事,但它逼你在动手前就想清楚每个元素在纵深里的身份。改完名字还说不清"它在哪一层",说明这个元素的空间位置还没设计好。

像素变成体素:尺寸不再由画布决定

像素是绝对的,画布多大就是多大。体素是相对的,同一个元素在不同距离上,占屏尺寸不同。

这带来一个必须适应的约束:同一个组件,在不同 z 位置需要不同的视觉尺寸,但它的设计尺寸(比如 150vp 宽)应该不变。 尺寸变化交给透视和 scale,而不是改组件宽高。否则你会发现同一张卡片在近处清晰、远处文字糊成一团——因为透视缩放不会重排文字,只会把渲染结果整体缩掉。

实践里的做法是给每一层定一个"设计距离",再反推它需要的初始尺寸。近景按 1.0 倍设计,中景按 0.85 倍,远景按 0.7 倍,然后统一交给透视去处理。

案例:瀑布流商品页到空间货架

拿最常见的瀑布流商品页做对照。2D 版本是双列瀑布流,用户纵向滚动。空间版本做成一条弧形货架:中间商品正对用户、尺寸最大,两侧商品沿 Y 轴向外旋转并后退,形成"能走进去"的纵深感。

先看 2D 版本的结构(WaterFlow 双列),再把它改造成空间货架:

@Entry
@Component
struct SpatialShelfDemo {
  @State private goods: string[] = ['箱包', '鞋靴', '配饰', '数码', '户外', '美妆', '家居', '运动'];

  // 计算每个卡片相对中心的偏置:0 表示正中
  private offsetOf(index: number): number {
    const center = (this.goods.length - 1) / 2;
    return index - center;
  }

  build() {
    Column() {
      // 空间货架:用 Stack 承载纵深,Row 决定横向顺序
      Stack({ alignContent: Alignment.Center }) {
        ForEach(this.goods, (item: string, index: number) => {
          // offset 越大离中心越远,旋转角度、后退距离、缩放同步增大
          const offset = this.offsetOf(index);
          const angle = offset * -9;                       // 两侧向用户方向内收
          const dz = -Math.abs(offset) * 34;               // 越远越后退
          const scale = 1 - Math.abs(offset) * 0.08;       // 越远越小

          Column() {
            Row()
              .width('100%')
              .aspectRatio(0.8)
              .backgroundColor('#DCE6F2')
              .borderRadius(12)
            Text(item).fontSize(14).margin({ top: 6 })
          }
          .width(120)
          .padding(8)
          .backgroundColor(Color.White)
          .borderRadius(14)
          .shadow({ radius: 10, color: '#12000000', offsetY: 3 })
          // 关键:横向位移 + 纵深位移 + 绕自身 Y 轴旋转,三者用同一个 perspective
          .translate({ x: offset * 96, y: 0, z: dz })
          .rotate({ x: 0, y: 1, angle: angle, perspective: 1000 })
          .scale({ x: scale, y: scale })
          .zIndex(100 - Math.abs(offset)) // 越靠中心越靠前(仅影响绘制顺序)
        }, (item: string) => item)
      }
      .width('100%')
      .height(300)
    }
    .width('100%')
    .height('100%')
    .justifyContent(FlexAlign.Center)
  }
}

跑起来会看到一条内收的弧线。这里有几个设计上的取舍要交代:

  • angle 取负值让两侧卡片朝用户转,模仿真实货架把商品面向顾客的角度;如果取正值,就变成"背过去"的感觉,适合做"离场/次要"的语义。
  • dz 用绝对值,所以纵深的顶点在正中,两侧对称后退,符合"中心是主角"的叙事。
  • 所有卡片的 perspective 统一为 1000,不统一的话远近视距不同,弧线会歪。

如果项目需要更真实的货架(比如能左右滑动浏览),可以把 offset 换成受手势控制的状态值,滑动时整体偏移,中间卡片被"选中"后放大。这样货架就从静态排布变成了可操作的导航结构。

平面思维和空间思维,六处对照

维度平面思维空间思维
组织逻辑网格与分栏纵深与焦平面
单位像素/点(绝对)距离与角度(相对)
层级图层堆叠顺序空间位置与遮挡
阅读一眼看全随时间推进
反馈视觉样式切换视觉 + 空间位移 + 声音
主角构图中心舒适焦平面上的焦点

叙事结构图

向左

向右

选中

用户进入页面

环境层: 背景氛围

主体层: 弧形货架阵列

用户滑动或凝视

货架整体左移

货架整体右移

目标卡片前移放大

详情在上下文层展开

退出: 卡片回落, 货架复位

这张图讲的其实是一条动线。平面稿里同类关系通常画成"页面 A → 页面 B"的跳转图;空间稿里则应画成"视点如何移动、层级如何切换"的过程图。改掉画图习惯,思维才真的转过来。

几条经验

  • 先画动线再定构图。空间设计里,顺序本身就是信息。
  • 图层命名按空间职责,别按绘制顺序。命名不清,说明位置没想清。
  • 尺寸交给透视,别手动改组件宽高。同一组件在不同 z 上用 scale 区分。
  • 同屏统一透视值。perspective 不一致,纵深关系就不可信。
  • 别让每个元素都"3D"。真正的空间感来自少数几个关键层级,其余的保持安静。

注意一下下哦

  • 把纵深当成装饰堆料。每个卡片都转角度、都加阴影,结果是满屏噪声,用户找不到焦点。
  • 用 zIndex 代替真实 Z。视觉上"看起来分层了",但透视、遮挡全对不上,一动就穿帮。
  • 忽略文字的可读性。旋转角度超过约 15 度后,小字号文本会明显变形,别让语义关键信息处于大角度上。
  • 纵深方向和交互方向打架。左右滑动却让元素在 Z 轴上跑,用户的物理直觉会抗拒。
  • 只设计静态画面。空间稿没有过渡状态就等于没设计,进出场、选中、复位都得画出来。

#鸿蒙 #HarmonyOS 7(API 26)

Logo

讨论HarmonyOS开发技术,专注于API与组件、DevEco Studio、测试、元服务和应用上架分发等。

更多推荐