我是兰瓶Coding,一枚刚踏入鸿蒙领域的转型小白,原是移动开发中级,如下是我学习笔记《零基础学鸿蒙》,若对你所有帮助,还请不吝啬的给个大大的赞~

开篇

实话实说,很多界面“看着能打”,一上手就泄气:点不着、慢半拍、弹窗跳你脸上,夜间模式还刺眼。别怪用户“矫情”,在鸿蒙(HarmonyOS / OpenHarmony)生态里,多设备、多形态、分布式协作就是日常,UI/UX 一旦偷懒,体验立刻原形毕露。今天我们不摆花架子,从原则到工具、从设计到落地,把鸿蒙端上如何做好看且好用的界面说清楚;顺手给上ArkUI/ArkTS的实战代码,拿去改名就能跑。🙂

前言:为什么“好看的界面”常常不好用?

因为场景被忽视:车上、中控屏、手表、小折叠、平板、甚至与手机协同的“超级终端”,输入法、可视距离、交互方式统统不同。鸿蒙的价值在于:系统级分布式能力 + 一致的设计语言(ArkUI + 设计令牌)。换句话说,别把每个屏当“孤岛”;你在一个屏上做的决定,最好能“自然地”在其他屏延续。

一张图看懂:鸿蒙 UI/UX 的“骨架”

[设计目标] → 一致、易学、可预期、无打扰
     │
[设计令牌/主题] → 颜色/字体/间距/动效曲线
     │
[布局与导航] → 栅格/自适配/分栏/分屏/手势导航
     │
[状态与反馈] → 可点击即反馈/加载占位/空状态/错误恢复
     │
[动效与节奏] → 传达层级/引导注意/弱提醒
     │
[可访问性] → 对比度/大字体/语音辅助/触控热区
     │
[跨设备一致] → 超级终端协同/分布式状态同步

核心设计原则(用人话说透)

  1. 一致性(Consistency)
    组件行为在不同页面、不同设备保持相同心智模型:返回逻辑、手势区域、状态颜色不“换口味”。

  2. 可预期(Predictability)
    交互后立即给反馈:轻震、涟漪、骨架屏别省;二级加载用渐进式渲染,不要“黑屏等奇迹”。

  3. 信息有层次(Hierarchy)
    当屏信息>7个元素,必须建层级:视觉权重(字号/对比)、空间分组(卡片/分组标题)、动效先后引导。

  4. 克制的动效(Subtle Motion)
    动效是“语法”,不是烟花:入场≤300ms、状态切换≤200ms;曲线用加速-减速而非匀速。

  5. 自适配优先(Responsive First)
    先画栅格与断点,再摆组件;不要硬写 px,把密度和留白当“一等公民”。

  6. 无打扰(Calm Design)
    通知/弹窗分级:极少数“打断式”,大多数“低打扰”(Banner/Toast/角标),驾驶/运动等场景更要克制。

  7. 可访问性(A11y)
    触控热区≥44dp,文字可达动态字体级别,色彩对比建议主文本≥4.5:1

设计令牌(Design Tokens):把“审美”变成可复用资产

在鸿蒙端,主题/样式最好都落到“令牌”上:颜色、字号、间距、圆角、动效曲线 → 一处定义,多处复用。

// /common/theme/Tokens.ets
export const Tokens = {
  color: {
    brand: '#3460ff',
    brandBg: '#EDF2FF',
    textPrimary: '#111827',
    textSecondary: '#6B7280',
    danger: '#EF4444',
    success: '#10B981',
    surface: '#FFFFFF',
    surfaceAlt: '#F8FAFC'
  },
  radius: { xs: 6, sm: 10, md: 14, lg: 20 },
  space:  { xs: 6, sm: 10, md: 16, lg: 24, xl: 32 },
  font:   { h1: 28, h2: 22, h3: 18, body: 16, small: 14 },
  motion: { fast: 120, base: 200, slow: 280 } // 毫秒
}

暗色模式:只需切换令牌表即可,无需满项目搜颜色替换。

布局与导航:栅格、分栏、分屏,一个都不能少

栅格 + 断点(ArkUI 示例)

// /pages/Home.ets
import { Tokens } from '../common/theme/Tokens'

@Entry
@Component
struct Home {
  @State cols: number = 2

  onPageShow() {
    const w = px2vp(Screen.width); // 逻辑宽度
    this.cols = w >= 900 ? 4 : (w >= 600 ? 3 : 2);
  }

  build() {
    Column({ space: Tokens.space.md }) {
      Text('发现').fontSize(Tokens.font.h1).fontWeight(FontWeight.Bold)
      Grid({ columns: this.cols }) {
        ForEach(this.mockCards(), (card) => {
          GridItem() {
            Card().backgroundColor(Tokens.color.surface).borderRadius(Tokens.radius.lg) {
              Column({ space: Tokens.space.sm }) {
                Text(card.title).fontSize(Tokens.font.h3)
                Text(card.desc).fontColor(Tokens.color.textSecondary).fontSize(Tokens.font.small)
              }.padding(Tokens.space.md)
            }.onClick(() => this.onCardTap(card))
          }
        })
      }.margin({ top: Tokens.space.md })
    }.padding(Tokens.space.lg).backgroundColor(Tokens.color.surfaceAlt)
  }

  private mockCards() { /* …返回卡片数据… */ }
  private onCardTap(card) { /* …导航… */ }
}

分屏与分栏(Master-Detail 模式)

  • ≥900dp:左列表 + 右详情
  • 600–900dp:单列 + 抽屉
  • <600dp:全屏栈式导航

规则先定清楚,交互与动效自然顺畅。

状态与反馈:骨架屏、空状态、错误页“铁三角”

// Skeleton 占位
@Component
struct ListSkeleton {
  build() {
    Column({ space: 12 }) {
      ForEach(Array.from({length: 6}), (_, i) => {
        Row() {
          Shimmer({ width: 56, height: 56, radius: 8 }) // 头像骨架
          Column({ space: 8 }) {
            Shimmer({ width: '60%', height: 16, radius: 4 })
            Shimmer({ width: '40%', height: 14, radius: 4 })
          }.margin({ left: 12 })
        }
      })
    }
  }
}

空状态写作:一句话解释 + 一步可行动作(按钮/刷新/授权)。

错误恢复:本地兜底 → 重试按钮 → 反馈通道,别把“重试”藏三级菜单。

动效:控制节奏,而不是“炫酷一时”

// 关键区块的入场过渡
@State show: boolean = false

build() {
  Column() {
    Button('加载数据').onClick(() => {
      this.show = false
      animateTo({ duration: Tokens.motion.base }, () => this.show = true)
    })
    if (this.show) {
      Column() {
        // 内容…
      }
      .transition(TransitionEffect.OPACITY) // 简洁的淡入
    }
  }
}

动效准则

  • 入场 ≤300ms;状态切换 ≤200ms。
  • 避免“位移+缩放+阴影+模糊”一锅炖;一次改变不超过两种维度。
  • 关键动效可配轻震反馈(如按钮成功)。

可访问性(A11y):把“可用”做给所有人

  • 触控热区 ≥44dp;表单项间距 ≥12dp;多选/单选点击区域包含标签文本。
  • 文本对比主内容 ≥4.5:1;暗色模式注意蓝色系“发光感”。
  • 给交互控件添加无障碍描述焦点顺序
Button('提交')
  .accessibilityText('提交表单')
  .accessibilityGroup(true)

表单与反馈:高转化的“三件套”

  1. 内联校验:离焦即校,不要“一键提交才报十条错”。
  2. 分段提交:长表单拆段,有进度与草稿保存。
  3. 成功页:别只说“成功”,给下一步行动(返回/查看/分享)。
// 表单片段(内联校验示意)
@State email: string = ''
@State emailErr: string = ''

TextInput({ placeholder: '邮箱' })
  .onChange((v) => {
    this.email = v
    this.emailErr = /\S+@\S+\.\S+/.test(v) ? '' : '邮箱格式不正确'
  })
if (this.emailErr) {
  Text(this.emailErr).fontColor(Tokens.color.danger).fontSize(12)
}

主题与暗色模式:一键反转不是“把黑改成白”

  • 对比关系保持不变:强调色只变亮度,不要乱改色相
  • 阴影→亮边(暗色里阴影弱化),投影与层级要重设。
  • 插画/图片:准备浅/深双套或用 CSS 滤镜/着色。
// 主题切换(示意)
@State dark: boolean = false
const theme = this.dark ? DarkTokens : Tokens;

资源与国际化:从 Day 1 就考虑

  • 多语言资源目录/resources/zh_CN, /en_US
  • 长度膨胀:德语/俄语会很长;按钮文字尽量用可扩展空间
  • 日期/货币/单位:别写死,交给格式化函数。

性能与流畅性:60FPS 靠“少做事 + 做该做的事”

  • LazyForEach 按需渲染,长列表分帧加载
  • 图片尽量用合适分辨率缓存;矢量图标优先。
  • 避免在 UI 线程做重计算,后台/异步处理后差分更新

协同与分布式场景的小心机

  • 跨端接力:同一任务在手机→平板→中控屏连贯继续,状态同步用“分布式数据/对象”。
  • 多屏一致:视觉与交互骨架一致,细节随场景适配(驾驶时减少文本输入)。
  • 中断恢复:电话/语音导航来了又走,回来回到刚才那一帧

设计—开发协作工具链(靠谱清单)

  • DevEco Studio:ArkUI 预览、Layout Inspector、Profiler(布局/帧率/内存)。
  • ArkUI Inspector:看组件树、边距、重绘边界。
  • Token 化输出:设计端(Figma/Sketch)用插件导出色板/字号/间距→ 令牌文件(JSON/TS)。
  • 图标规范:统一视口(24/32),对齐像素网格;浅/深模式双套
  • 动效曲线库:统一贝塞尔/时长,避免“每人来一口”。

可复用 UI 模板:卡片、底部栏、弹窗

卡片(信息密度友好)

@Component
struct InfoCard {
  @Prop title: string
  @Prop desc: string
  @Prop icon: Resource

  build() {
    Row() {
      Image(this.icon).width(32).height(32)
      Column({ space: 6 }) {
        Text(this.title).fontSize(18).fontWeight(FontWeight.Medium)
        Text(this.desc).fontSize(14).fontColor('#6B7280')
      }.margin({ left: 12 })
      Blank()
      Image($r('app.media.chev_right')).width(20).height(20)
    }
    .padding(16)
    .backgroundColor('#fff')
    .borderRadius(16)
    .shadow({ radius: 12, color: 'rgba(0,0,0,0.06)' })
  }
}

底部操作栏(大拇指友好)

// 48~56dp 高度,安全区适配
Row() {
  Button('取消').type(ButtonType.Normal).layoutWeight(1)
  Button('确定').type(ButtonType.Capsule).layoutWeight(1)
}.padding({ left: 16, right: 16, bottom: 16, top: 10 })

非打断式弹层(Sheet 替代硬弹窗)

@State showSheet: boolean = false

Button('选择城市').onClick(() => this.showSheet = true)
if (this.showSheet) {
  Sheet() {
    // 内容列表…
  }
  .height('60%')
  .backgroundBlurStyle(BlurStyle.Thick) // 背景虚化
  .onClose(() => this.showSheet = false)
}

评审清单(上线前逐条过!)

  • 断网/弱网:骨架与错误页正常?
  • 暗色模式:对比度、插图、阴影处理正常?
  • 动效:入场≤300ms、切换≤200ms?
  • 可访问性:热区≥44dp、读屏描述齐全?
  • 性能:首屏 < 1s(冷启动骨架≤200ms),滚动稳定 60FPS?
  • 分布式:接力/多端状态一致?
  • 文案:动词优先、句子短、错误可恢复指引?

七天冲刺路线(给团队的排期模版)

  • D1:场景梳理 → 用户旅程 → 信息架构 & 栅格断点
  • D2:令牌落库(颜色/字号/间距/动效)→ 基础组件装配
  • D3:关键流程(注册/搜索/下单…)线框 → 高保真
  • D4:ArkUI 模板搭建(卡片/导航/表单/列表)
  • D5:状态与动效(骨架/空状态/错误/过渡)
  • D6:暗色/国际化/可访问性走查
  • D7:弱网/异常/分布式接力联测 + 指标基线

常见“翻车瞬间”(都是血泪)

  • 把颜色写死在组件里,导致暗色一换全项目“拉跨”。
  • 列表 1000+ 项一次渲染,滑一下掉帧到你怀疑人生。
  • 成功 Toast 一直挡按钮,用户连点三次。
  • 表单只在提交时报错,用户填了 2 分钟被全清空。
  • 弹窗滥用:二连弹 + 权限弹 + 评分弹,转化暴跌。

结语:UI 是“产品的语气”,UX 是“产品的态度”

在鸿蒙生态里做 UI/UX,比“画个好看的界面”难一点点,但也有章可循令牌化 → 栅格与断点 → 状态与动效 → 可访问性 → 分布式协同。当你把这些“工程化”,审美就变成了“可复制的生产力”。🎯

你要的资料包(我可以继续补充)

  • ArkUI 组件速查 & 模板片段
  • 设计令牌 JSON/TS 样板(含浅/深)
  • 骨架/空态/错误插画占位套件(浅/深双版)
  • 性能与可访问性检查脚本(DevEco 配置说明)

(未完待续)

Logo

作为“人工智能6S店”的官方数字引擎,为AI开发者与企业提供一个覆盖软硬件全栈、一站式门户。

更多推荐