03 ArkUI 组件、状态与多端适配

一、详细知识点

1. 声明式 UI

ArkUI 的核心思想是"状态描述界面"。开发者声明当前状态下界面应该是什么样,状态变化后框架更新界面。

ts 复制代码
@State selectedTab: number = 0

selectedTab 改变时,依赖它的 UI 会重新计算。

2. 基础组件

组件 作用 demo 场景
Text 标题、摘要、正文 新闻标题和内容
Button 用户命令 刷新、收藏、返回
List / ListItem 长列表 首页新闻列表
Column / Row 基础布局 页面主体、卡片按钮区
Blank 弹性占位 顶部栏左右分布
Toggle / Slider 设置项 深色模式、字体大小

3. 状态装饰器

装饰器 场景 边界
@State 当前组件内部可变状态 不适合跨页面共享大状态
@Prop 父传子展示数据 子组件不应修改
@Link 父子双向绑定 谨慎使用,避免状态流混乱
@Builder 复用局部 UI 结构 不要写复杂业务逻辑

4. 列表性能

列表是移动应用高频性能点。卡片组件要稳定,避免每个 item 做大量同步计算。数据更新时优先生成新数组,便于框架识别变化。

5. 多端适配

设备 UI 策略 交互策略
手机 单列、底部区域易点击 单手操作
平板 列表 + 详情分栏 鼠标、键盘、触控都可用
折叠屏 根据窗口宽度切换布局 展开不中断状态
车机 大字号、高对比、少输入 降低驾驶干扰
穿戴 卡片化、短信息 极简操作

二、本章 demo

Demo 1:新闻卡片组件

components/NewsCard.ets

ts 复制代码
@Component
export struct NewsCard {
  article: NewsArticle
  onOpen: (id: string) => void = () => {}
  onFavorite: (id: string) => void = () => {}

  build() {
    Column() {
      Text(this.article.title).fontSize(20).fontWeight(FontWeight.Bold)
      Text(this.article.summary).fontSize(14).opacity(0.72)
      Row() {
        Button('查看').onClick(() => this.onOpen(this.article.id))
        Button(this.article.favorite ? '取消收藏' : '收藏')
          .onClick(() => this.onFavorite(this.article.id))
      }
    }
  }
}

Demo 2:设置页状态

pages/SettingsPage.ets

ts 复制代码
Toggle({ type: ToggleType.Switch, isOn: this.setting.darkMode })
  .onChange((isOn: boolean) => {
    this.onDarkModeChange(isOn)
  })

Demo 3:浏览器版验证

运行 demo/web-preview 后,在设置页切换深色模式和字体大小,检查列表和详情的视觉变化。

三、面试题与详细答案

1. ArkUI 的声明式 UI 和传统命令式 UI 有什么区别?

命令式 UI 是找到控件后手动修改,例如设置某个 Text 的内容;声明式 UI 是状态改变后重新描述 UI。ArkUI 中 @State 变化会驱动界面更新,开发者关注状态和 UI 的映射关系。

2. @State 适合保存哪些数据?

适合保存当前组件内部使用、会影响 UI 的数据,如加载状态、当前 tab、输入框内容、列表数据。跨页面长期共享的数据不应散落在多个 @State 中,应该抽到 Store 或 Service。

3. 长列表为什么容易卡顿?

长列表 item 多,任何复杂布局、同步计算、图片解码、频繁状态变更都会放大成本。优化方向包括拆分稳定组件、减少不必要重绘、控制图片尺寸、分页加载和缓存。

4. 如何做手机和平板适配?

不要只按屏幕像素写死布局。手机优先单列,平板可以分栏;文本和卡片高度要能随字体变化;触控区域要足够大;横屏时要检查内容是否过宽或过挤。

四、五倍扩展知识点矩阵

1. ArkUI 组件能力地图

分类 常见组件 解决问题 质量关注点
文本 Text 标题、摘要、正文 字体缩放、截断、无障碍
操作 Button 用户命令 防重复点击、状态反馈
容器 ColumnRow 基础布局 自适应、间距一致
层叠 Stack 浮层、角标 遮挡和点击区域
列表 ListListItem 长数据 性能、复用、分页
表单 TextInputToggleSlider 输入和设置 校验、回显、保存
媒体 Image 图标、封面 尺寸、缓存、占位
导航 Navigation 或页面状态 多页面 参数、返回栈、恢复
反馈 加载、空状态、错误提示 状态表达 可恢复和可解释
主题 颜色、字体、间距 一致体验 深色模式和品牌治理

2. 状态来源拆解

状态 示例 生命周期 应放位置
页面临时状态 当前 tab、loading 页面存在期间 @State
组件展示数据 卡片标题、摘要 父组件传入 @Prop 或普通入参
表单双向编辑 开关、输入框 编辑期间 @Link 或回调
业务共享状态 收藏、登录用户 跨页面 Store/Service
持久化状态 主题、字号 重启后保留 Preferences/Store
远程状态 新闻列表 随接口变化 Repository
派生状态 收藏数量 由基础状态计算 函数或 getter
错误状态 加载失败 一次请求期间 Page
空状态 无收藏 数据结果 Page + Component
权限状态 已授权/拒绝 系统决定 PermissionService

3. 布局原则

不要用固定高度硬压内容。鸿蒙应用要面对字体缩放、横竖屏、平板、折叠屏和多语言。布局应该优先使用内容自适应、百分比宽度、合理间距和可滚动区域。

ts 复制代码
Column() {
  Text(this.article.title)
    .fontSize(20 * this.fontScale)
    .fontWeight(FontWeight.Bold)
  Text(this.article.summary)
    .fontSize(14 * this.fontScale)
    .opacity(0.72)
}
.width('100%')
.padding(16)

4. 组件拆分标准

问题 如果答案是"是" 处理
这块 UI 会重复出现吗 拆组件
这块 UI 有独立输入输出吗 拆组件
父页面已经超过可读范围吗 拆组件
组件需要知道网络吗 只传数据和回调
组件需要知道路由吗 通常否 由页面处理跳转

5. 多端适配决策

手机
平板
折叠展开
获取窗口宽度
宽度是否足够
单列列表
列表 + 详情分栏
保持状态并切换布局
底部或顶部操作
左列表右详情
避免重置 selectedId

五、ArkUI demo 扩展任务

任务 操作 验证
增加搜索框 首页顶部加输入 输入关键字过滤列表
增加分类 tab Stage/ArkUI/Release 点击分类更新列表
增加空状态组件 搜索无结果 显示可恢复提示
增加加载骨架 模拟请求延迟 首屏不突兀
增加错误重试 Service 抛错 页面出现重试按钮
增加分栏布局 平板宽屏 左列表右详情
增加字体缩放 设置页 slider 页面文字同步变化
增加深色模式 设置页 switch 背景和文字变化
增加收藏角标 卡片上显示 收藏状态明显
增加按钮禁用 loading 时禁用刷新 防重复点击
增加列表滚动保持 返回首页 位置不突兀
增加详情字号 详情正文适配 不截断

扩展示例:空状态组件设计

ts 复制代码
@Component
export struct EmptyView {
  message: string
  actionText: string = ''
  onAction: () => void = () => {}

  build() {
    Column() {
      Text(this.message)
      if (this.actionText.length > 0) {
        Button(this.actionText).onClick(() => this.onAction())
      }
    }
  }
}

空状态不是"没有内容就空白",而是告诉用户发生了什么、是否可以恢复、下一步怎么做。

六、视觉和交互质量清单

检查项 标准
字体 标题、正文、辅助信息层级清楚
间距 页面、卡片、按钮间距一致
对比度 深浅模式都能读清
点击区域 按钮不贴边、不太小
滚动 长内容可滚动,不遮挡
状态反馈 点击、加载、失败都有反馈
空状态 用户知道下一步
横屏 内容不挤压
平板 不浪费大屏
字号放大 不溢出、不重叠

七、扩展面试题

5. 如何设计一个可复用 ArkUI 组件?

可复用组件要有明确输入、明确输出和低业务耦合。输入通过属性传入,输出通过回调传出。组件不应直接请求网络、不应直接操作全局路由,也不应知道父页面完整业务流程。

6. 为什么列表 item 不应写太复杂?

列表 item 会大量重复,复杂布局和同步计算会被放大,导致滚动卡顿。应把复杂计算提前到数据层,item 只做展示;图片要限制尺寸并考虑缓存;状态变化要尽量局部化。

7. 深色模式为什么不能只改背景色?

深色模式涉及背景、文字、边框、阴影、图标、状态色和图片适配。如果只改背景,文字可能对比不足,卡片阴影可能不自然,图标可能不可见。颜色应集中管理。

8. 如何处理字体放大带来的布局问题?

避免固定高度,允许文本换行,重要容器可滚动,按钮文案不要过长。测试时要把字体调到较大值,看标题、卡片、详情和设置项是否溢出或遮挡。

@Link 会形成双向绑定,简单表单很方便,但复杂业务中过多双向绑定会让状态变化来源不清。跨页面或业务状态更适合事件回调和 Store 管理。

10. 如何判断一个页面达到可上线 UI 质量?

核心路径可用,加载、失败、空状态完整;不同设备和字号下不溢出;交互有反馈;状态变化可预测;视觉层级清晰;组件可复用;无明显卡顿和遮挡。

八、ArkUI 知识点详解库

1. UI 质量首先是状态质量

页面不好维护,根源通常不是组件太多,而是状态混乱。一个页面要明确数据状态、加载状态、错误状态、空状态、选择状态和编辑状态。状态清楚,UI 才稳定。

2. 组件职责要小而完整

NewsCard 只负责展示一篇文章和暴露点击事件,不负责查询文章、不负责导航、不负责保存收藏。职责越清楚,组件越可复用。

3. 列表要按数据量设计

4 条数据和 4000 条数据的写法不能完全一样。数据少可以简单渲染,数据多要考虑分页、懒加载、缓存、图片尺寸和滚动性能。

4. 布局要考虑文本增长

中文、英文、多语言、字体放大都会让文本长度变化。固定高度和固定宽度容易溢出。可上线 UI 会为最长文案和最大字号留空间。

5. 空状态是功能的一部分

收藏为空、搜索无结果、网络失败、权限拒绝都不应该显示空白。空状态要解释原因,并提供返回、重试或修改条件的入口。

6. 加载状态要避免误操作

加载时按钮是否禁用、是否允许再次刷新、是否保留旧数据,都要按场景设计。无限转圈没有意义,要有超时和失败状态。

7. 深色模式要成体系

深色模式不是反转颜色,而是设计一套背景、文本、边框、状态、阴影和图标规则。局部硬编码颜色会破坏整体一致性。

8. 无障碍不是后期补丁

字体可放大、对比度足够、点击区域足够、信息不只靠颜色表达,这些应从组件设计阶段考虑。

9. 平板不是放大的手机

平板有更多空间,应考虑分栏、侧边栏、详情同屏、键盘鼠标操作。简单把手机页面拉宽会浪费空间。

10. 视觉层级服务任务

标题、摘要、按钮、辅助信息的视觉权重要反映用户任务。不要让所有文字一样大,也不要让次要按钮比主要操作更抢眼。

九、ArkUI 场景化实战库

场景 UI 目标 状态目标 验收
首页首屏 快速看到内容 loading -> data 不白屏
新闻详情 阅读沉浸 selectedId 有效 返回正常
收藏页 展示筛选结果 favorite 派生 数量正确
设置页 即时反馈 setting 更新 主题变化
搜索 快速过滤 keyword 状态 无结果提示
分类 降低信息密度 category 状态 切换稳定
弱网 不阻塞用户 error 状态 可重试
空收藏 引导下一步 empty 状态 可返回首页
字体放大 可读性 fontScale 不溢出
平板横屏 利用空间 layout 状态 不拉伸
快速点击 防误操作 disabled 状态 不重复提交
返回恢复 保持上下文 selected/scroll 不重置体验

十、扩展面试题库

11. ArkUI 页面为什么要同时设计 loading、error、empty、data?

真实应用不会永远成功返回数据。loading 解决等待,error 解决失败,empty 解决成功但无数据,data 解决正常展示。缺任何一个状态,用户都会在某些场景下看到空白或错误体验。

12. 如何避免组件过度封装?

组件抽象要基于复用和复杂度,而不是为了文件数量。只用一次、逻辑很短、未来变化不确定的 UI 可以先留在页面中;重复出现或职责清晰的 UI 再拆。

13. 如何设计列表卡片的点击区域?

主要点击区域要清晰,按钮之间要有足够间距,卡片整体点击和局部按钮点击不要冲突。收藏按钮、查看按钮和卡片进入详情的行为要一致可预期。

14. 为什么 UI 也需要验收清单?

UI 问题很多不是编译错误,而是体验问题。验收清单能覆盖字号、横屏、深色模式、空状态、错误状态、按钮点击和列表滚动,减少人工遗漏。

15. 如何从 demo UI 演进到生产 UI?

先补齐状态,再统一组件,再抽主题变量,再做多端适配,再补无障碍和性能检查。不要一开始只追求视觉复杂度,缺状态和边界的 UI 不能上线。

十一、ArkUI 知识体系补全

领域 必会内容 实战场景 质量要求
基础组件 Text、Button、Image、Blank 标题、操作、图标 对齐、尺寸、可读
容器布局 Column、Row、Stack、Flex、Grid 页面、卡片、面板 自适应、不溢出
列表 List、ListItem、LazyForEach 新闻流、设置项 滚动稳定、分页
表单 TextInput、Toggle、Slider、Checkbox 搜索、设置、筛选 校验、回显、禁用
导航 Navigation、NavDestination、router 首页、详情、设置 参数安全、返回正确
状态管理 @State、@Prop、@Link、@Provide/@Consume、Observed/ObjectLink 父子通信、跨层级共享 来源明确
Builder @Builder、局部 UI 复用 空状态、标题栏、操作区 不塞业务逻辑
动画 属性动画、显隐动画、转场 收藏反馈、页面切换 不影响性能
手势 click、swipe、drag、longPress 卡片操作、滑动删除 防误触
绘制 Canvas、Shape、Path 图表、徽章、进度 性能可控
媒体 Image、Video、Audio 相关能力 封面、播放 占位、错误、缓存
主题 颜色、字体、间距、深浅模式 全局风格 集中管理
无障碍 字号、对比、朗读、触控区域 老年用户、弱视用户 不只靠颜色表达
多端 phone/tablet/foldable 分栏和响应式 状态不中断

十二、导航与页面栈设计

简单项目可以用页面状态模拟,但业务项目需要稳定的导航模型。导航设计要解决:页面路径、参数传递、返回栈、深链、异常参数、状态恢复。

ts 复制代码
interface DetailParams {
  articleId: string
  from: 'home' | 'favorites' | 'search'
}

function validateDetailParams(params?: DetailParams): string | undefined {
  if (!params || params.articleId.length === 0) {
    return undefined
  }
  return params.articleId
}

导航规则:

  • 列表到详情只传 id,不传整个对象。
  • 参数缺失时显示空状态或返回安全页面。
  • 返回逻辑要考虑来源页。
  • 页面恢复后要能重新查数据。
  • 深链进入时要补齐上下文。

十三、状态管理深入

状态模式 适合场景 风险 替代方案
@State 组件内部状态 跨页面复用困难 Store
@Prop 父到子展示 子组件不能改父状态 回调
@Link 表单双向编辑 状态来源不清 明确事件
@Provide/@Consume 跨层级共享 隐式依赖 状态容器
Observed/ObjectLink 对象属性观察 嵌套更新复杂 不可变模型
Store 单例 小型共享状态 生命周期不清 Repository + 持久化

状态设计问题通常比组件 API 更重要。页面越复杂,越要把状态拆成:输入状态、远程数据状态、派生状态、提交状态、错误状态。

十四、动画、手势与绘制

能力 用法 注意
属性动画 收藏、展开收起、按钮反馈 动画时长短,避免拖慢操作
页面转场 详情打开、设置进入 转场不要掩盖加载失败
手势点击 卡片、按钮 防重复点击
长按 菜单、复制 给明显反馈
滑动 删除、切换 tab 防止和列表滚动冲突
拖拽 排序、调整 保持状态一致
Canvas 图表、进度 控制重绘频率
Shape 图标、标记 优先复用组件

十五、多端布局方案




窗口信息
内容宽度
单列:列表 -> 详情
主列表 + 弹出详情
左列表 + 右详情
保留 selectedId
返回栈管理

验收标准:

  • 手机上操作路径短,按钮不贴边。
  • 平板上内容不被拉得过宽。
  • 横屏时卡片、详情、设置项不重叠。
  • 折叠屏展开时不丢失当前阅读文章。
  • 字体放大后仍然可读、可点击、可滚动。

十六、UI 练习套件

练习 目标 验收
搜索页 输入、过滤、空状态 无结果有提示
分类页 tab 状态 切换不丢收藏
分栏详情 平板布局 左右联动
动画收藏 属性动画 收藏反馈明显
滑动操作 手势 不误触列表滚动
深色主题 主题变量 所有页面可读
大字号 无障碍 无重叠
错误页 失败可恢复 有重试
骨架屏 首屏体验 加载不突兀
图片占位 媒体失败 不破坏布局

十七、补充面试题

页面状态切换适合小 demo,逻辑简单;Navigation 或路由能力适合真实页面栈,能处理返回、参数、深链和页面恢复。业务复杂后应使用稳定导航模型。

17. 如何设计 ArkUI 主题系统?

主题系统要集中管理颜色、字体、间距、圆角、阴影和状态色。页面只引用语义变量,例如 primary、surface、textPrimary,而不是硬编码颜色值。

18. 为什么动画也要纳入性能检查?

动画会影响渲染频率和用户操作响应。过长、过多或触发范围过大的动画会导致卡顿。动画应服务反馈和理解,不应干扰任务完成。

19. 如何处理多端状态保持?

布局切换时不要重建业务状态。把 selectedId、搜索词、收藏集合等放在页面或 Store 中,布局只根据窗口宽度选择展示方式。

20. UI 架构如何支持长期迭代?

建立组件库、主题系统、状态规范、导航规范和验收清单。每个页面按同一套模式处理加载、失败、空状态和数据展示,长期迭代成本会明显下降。

相关推荐
●VON10 小时前
纯ArkUI实现7层拟物3D环形进度图:零依赖的视觉革命
服务器·3d·app·鸿蒙·von
aqi0015 小时前
一文速览 HarmonyOS 6.0.1 引入的十个新特性
android·华为·harmonyos·鸿蒙·harmony
三声三视16 小时前
鸿蒙 ArkTS 国际化实战全攻略:多语言切换、格式本地化与 RTL 布局一步到位
华为·harmonyos·鸿蒙
空中海16 小时前
04 Stage 模型、系统能力与数据架构
架构·鸿蒙
●VON16 小时前
鸿蒙Widget开发实战:3张卡片实现桌面-App全链路同步
华为·app·harmonyos·鸿蒙·von
key_3_feng17 小时前
Pura X Max 鸿蒙深度优化方案
华为·鸿蒙
●VON18 小时前
鸿蒙首个双AI引擎饮食App:豆包+DeepSeek如何协同工作
人工智能·app·鸿蒙·von·豆包·deepseek
UnicornDev4 天前
【Flutter x HarmonyOS 6】魔方计时APP——计时逻辑实现
flutter·华为·harmonyos·鸿蒙·鸿蒙系统
前端技术4 天前
鸿蒙ArkTS 自定义底部导航栏(Tabs+@Builder 极简实现)
harmonyos·鸿蒙