当前位置: 首页 > news >正文

鸿蒙应用开发UI基础第八节: ArkTS声明式UI与页面基础结构 - 鸿蒙

【学习目标】

  1. 理解声明式UI与命令式UI的核心差异,建立“数据驱动视图”的核心认知;
  2. 熟练掌握ArkTS页面核心结构(@Entry/@Component + build函数),能独立搭建标准页面骨架;
  3. 掌握vp/fp/px/lpx等尺寸单位的适用场景与适配原则,熟练使用系统原生尺寸转换方法,养成规范的单位使用习惯;
  4. 学会使用@State状态变量,实现“数据修改→UI自动刷新”的基础交互;
  5. 能快速定位并解决多根组件、UI不刷新、尺寸适配等新手高频页面问题。

【课前铺垫】

从本节开始,我们正式进入ArkTS UI开发的核心阶段:声明式UI开发。这是鸿蒙官方推荐的主流开发方式,也是让应用“看得见、可交互”的关键。本节将围绕“页面基础结构”展开,从页面核心组成、多设备尺寸适配,到数据驱动UI刷新,全方位解析声明式UI的核心逻辑,学好这些内容能为后续组件、布局、状态管理的学习筑牢基础。

先思考几个核心问题,带着问题学习更高效:

  • 为什么鸿蒙优先推荐声明式UI?它比传统命令式UI更高效的核心原因是什么?
  • 一个可运行的ArkTS页面,哪些结构是缺一不可的?少了会导致什么问题?
  • vp和fp是什么,有什么区别?为什么同样的尺寸在平板和手机上显示效果不同?
  • 修改变量后UI不刷新,大概率是哪里出了问题?
  • 特殊场景需要px与vp/fp互转时,如何使用系统原生方法实现?

一、工程结构

本节创建新工程AppDemo(基于鸿蒙API 12+/Stage模型),聚焦讲解UI页面的基本组成和声明式UI,工程核心目录结构如下:

AppDemo
├── AppScope                 # 应用全局配置目录
│   └── app.json5            # 全局配置(包名/应用名称/图标/版本等)
├── entry                    # 主模块目录(Entry HAP,应用核心代码包)
│   ├── src/main
│   │   ├── ets              # ArkTS代码核心目录
│   │   │   ├── common       # 新增:通用工具/常量目录
│   │   │   │   └── constants  
│   │   │   │       └── LayoutConstants.ets # 通用布局常量
│   │   │   ├── entryability # UIAbility组件目录
│   │   │   └── pages        # Page页面目录
│   │   │       └── Index.ets    # 工程默认首页
│   │   ├── resources        # 资源文件目录(字体/文字/数值等放这里)
│   │   │   └── base
│   │   │       ├── element
│   │   │       │   ├── float.json # 字体大小(fp)/数值型资源
│   │   │       │   └── string.json # 字符串型资源(页面文字/提示语等)
│   │   │       └── profile
│   │   └── module.json5     # 模块配置文件
└── 其他目录(构建/测试/配置相关)

二、声明式UI与命令式UI核心差异

两种UI开发模式的本质区别在于关注焦点UI更新逻辑,通过对比能更清晰理解声明式UI的优势:

1. 核心思维

  • 命令式UI:关注“怎么做”,需要开发者编写每一步操作指令(创建组件→设置属性→添加事件→手动更新),全程掌控UI的绘制和修改。
  • 声明式UI:关注“是什么”,只需描述UI的最终状态和数据关联关系,框架自动处理渲染、更新逻辑,数据变化时UI自动刷新。

2. 代码对比(实现“点击按钮变色”)

命令式UI(iOS原生Swift)

import UIKitclass ViewController: UIViewController {var btn: UIButton!override func viewDidLoad() {super.viewDidLoad()btn = UIButton(type: .system)btn.setTitle("点击变色", for: .normal)btn.backgroundColor = UIColor(red: 0/255, green: 125/255, blue: 255/255, alpha: 1)btn.setTitleColor(.white, for: .normal)btn.frame = CGRect(x: 100, y: 200, width: 200, height: 80)btn.addTarget(self, action: #selector(btnClick), for: .touchUpInside)self.view.addSubview(btn)}@objc func btnClick() {btn.backgroundColor = UIColor(red: 255/255, green: 103/255, blue: 0/255, alpha: 1)}
}

声明式UI(ArkTS)

// 引入通用布局常量
import { LayoutConstants } from '../common/constants/LayoutConstants';// 声明页面入口
@Entry
// 声明组件
@Component
struct Index {// 状态变量:被@State修饰,数据与UI绑定,修改后自动刷新@State btnColor: string = "#007dff";// build()内定义组件层级和属性build() {Column({ space: 20 }) {Button("点击变色").backgroundColor(this.btnColor) .width(200).height(80).fontSize($r('app.float.font_size_normal')).onClick(() => {// 点击修改颜色this.btnColor = "#ff6700"; });}.width(LayoutConstants.FULL_WIDTH) // 设置根组件宽度.height(LayoutConstants.FULL_HEIGHT) // 设置根组件高度.justifyContent(FlexAlign.Center);}
}

三、ArkTS页面核心结构

一个可运行的ArkTS页面,必须包含入口标记、组件标记、结构体、UI构建函数四大核心部分,缺一不可。

1. 核心组成详解

组成部分 作用说明 核心禁忌
@Entry 页面入口标识,告知系统该组件可作为独立页面加载 一个文件仅能有一个@Entry,否则编译报错
@Component 自定义组件标识,所有UI组件(页面级/子组件级)都需添加 无此标识,结构体无法作为UI组件使用,编译直接报错
struct ArkTS组件的核心载体,基于结构体实现,无需继承类 命名需大驼峰(如HomePage),小写开头会报语法警告
build()函数 唯一的UI构建函数,仅负责描述UI结构 1. 禁止编写业务逻辑(console.log/网络请求等);2. 必须只有一个根组件

2. 核心禁忌(新手必避)

  • ❌ 禁止一个文件多个@Entry:编译直接报错,需拆分组件或页面。
  • ❌ 禁止build()函数多根组件:多根组件报错In an '@Entry' decorated component, the 'build' method can have only one root node, which must be a container component. <ArkTSCheck>
  • ❌ 禁止在build()函数写非UI逻辑:如console.log、网络请求等,需封装到独立方法中,在事件回调(如onClick)或生命周期中调用。

四、多设备尺寸适配

4.1 为什么需要尺寸适配?—— 屏幕底层逻辑

(1)屏幕尺寸的核心定义

我们常说的6.7英寸手机 11英寸平板,这里的“英寸”是屏幕 发光区域对角线的物理长度
物理尺寸

  • 单位换算:1英寸 = 2.54厘米
  • 计算公式:$\text{对角线长度} = \sqrt{\text{屏幕宽度}^2 + \text{屏幕高度}^2}$

(2)影响显示效果的三大核心概念

  • 物理尺寸:屏幕实际大小(英寸),决定设备握持感;
  • 分辨率:屏幕横向和纵向的物理像素总数(px),如1080×2340,代表屏幕“精细度”;
  • 像素密度(PPI):每英寸屏幕包含的物理像素数,是影响显示效果的核心参数。PPI数值越高,像素点越密集,屏幕显示越细腻(手机PPI≈400+,平板PPI≈200+)。

(3)适配的核心痛点

px(物理像素)是屏幕硬件的最小显示单元,直接与屏幕PPI绑定,导致相同px值在不同设备上视觉大小差异极大:

  • 100px按钮在普通手机(中等PPI)上大小适中;
  • 在高清屏上,因像素点更密,100px按钮视觉上极小;
  • 在低像素平板上,因像素点更疏,100px按钮视觉上极大。

为解决这种差异,让开发者无需手动换算不同设备的像素,同时满足“视觉大小一致+无障碍适配+多语言适配”需求,鸿蒙引入了vp/fp单位。使用虚拟像素,使元素在不同密度的设备上具有一致的视觉大小。

虚拟像素

4.2 鸿蒙核心尺寸单位(按使用优先级排序)

单位 完整名称 正确定义 特性 适用场景
vp 虚拟像素(virtual pixel) 系统根据屏幕密度自动换算的逻辑单位,保证视觉大小一致 多设备上显示大小一致,与物理像素无关 宽、高、间距、边距等布局
fp 字体像素 专门用于字体的单位,在 vp 基础上支持系统字体大小缩放 跟随系统字体大小设置,支持无障碍 所有文字的 fontSize
px 物理像素 屏幕硬件最小显示单元,直接对应物理像素点 不同设备上显示大小差异极大,无自适配 Canvas、像素级精准绘制
lpx 逻辑像素(旧) 按设计稿宽度(默认720)等比缩放的单位。 无密度适配、无字体缩放,API9+已淘汰 仅老项目兼容,新项目禁止使用

4.3 系统原生尺寸转换方法

鸿蒙系统在UIContext中内置了以下尺寸转换方法,适配当前UI实例所在屏幕的虚拟像素比例:

  • vp2px(value: number): number:将vp单位值转换为px单位值;
  • px2vp(value: number): number:将px单位值转换为vp单位值;
  • fp2px(value: number): number:将fp单位值转换为px单位值;

调用规则:需通过当前组件的this.getUIContext()获取上下文后调用,且建议增加空值安全处理:

const pxValue = this.getUIContext()?.vp2px(100) ?? 100;

注意:getUIContext() 禁止在 build() 中直接调用,应在 onClick、生命周期等可获取完整上下文的位置使用。

4.4 核心配置文件

(1)全局通用布局常量

路径:entry/src/main/ets/common/constants/LayoutConstants.ets

export class LayoutConstants {public static readonly FULL_WIDTH: string = '100%';public static readonly HALF_WIDTH: string = '50%';public static readonly FULL_HEIGHT: string = '100%';public static readonly BASE_PADDING: number = 24;public static readonly BASE_SPACE: number = 16;
}

(2)字体大小资源文件(float.json)

路径:entry/src/main/resources/base/element/float.json

{"float": [{"name": "font_size_normal","value": "20fp"},{"name": "font_size_medium","value": "24fp"},{"name": "font_size_large","value": "30fp"},{"name": "font_size_counter","value": "26fp"},{"name": "button_size_width","value": "200vp"}]
}

(3)文字资源文件(string.json)

路径:entry/src/main/resources/base/element/string.json

{"string": [{"name": "page_title_main","value": "从页面结构、尺寸适配到数据驱动的全方位解析"},{"name": "page_title_home","value": "我的首页"},{"name": "btn_click_change","value": "点击变色"},{"name": "text_counter","value": "当前计数:"},{"name": "btn_change_color","value": "点击按钮修改颜色"}]
}

4.5 适配黄金法则

  1. 通用布局抽常量:100%/50%等全项目通用百分比,抽离到LayoutConstants
  2. 字体大小抽离:所有fontSize必须通过$r('app.float.xxx')引用float.json,不推荐硬编码;
  3. 页面文字抽离:所有页面/按钮/提示文字通过$r('app.string.xxx')引用string.json,不推荐硬编码;
  4. 单位使用规范:布局优先用vp/百分比,文字必须用fp(支持无障碍缩放);仅Canvas可用px,新项目禁用lpx;
  5. 转换慎使用:特殊场景需转换时,仅使用系统原生UIContext方法,不推荐自定义换算。

五、核心实战:@State与数据驱动UI(完整示例)

import { LayoutConstants } from '../common/constants/LayoutConstants';@Entry
@Component
struct Index {// @State 基础状态装饰器:修改后自动驱动UI刷新@State btnColor: string = "#007dff";@State count: number = 0;build() {Column({ space: LayoutConstants.BASE_SPACE }) {Text($r('app.string.page_title_main')).fontSize($r('app.float.font_size_medium'))// 按钮颜色由状态变量控制Button($r('app.string.btn_click_change')).backgroundColor(this.btnColor).width($r('app.float.button_size_width')).height(50) // 硬编码高度 默认单位vp 如果使用字符串需添加单位("50vp")不推荐.fontSize($r('app.float.font_size_normal')).onClick(() => {this.btnColor = "#ff6700";});// 计数器展示Text() {Span($r('app.string.text_counter'))Span(`${this.count}`)}.fontSize($r('app.float.font_size_counter'));// 计数器按钮组Row({ space: 16 }) {Button("计数增加").onClick(() => {this.count++;});Button("计数减少").onClick(() => {this.count--;});}}.width(LayoutConstants.FULL_WIDTH).height(LayoutConstants.FULL_HEIGHT).justifyContent(FlexAlign.Center);}
}

【新手排查】UI不刷新常见原因:普通变量仅能设置初始值,修改后无法驱动UI刷新;需为动态变量添加 @State 装饰器才能实现“数据变化→UI更新”。

六、内容总结

  1. 核心语法规则
    • ArkTS页面必须包含@Entry+@Component+struct+build()四大核心部分;
    • build()函数仅描述UI,禁止编写业务逻辑,且只能有一个根组件;
    • 多根组件报错示例:
    build() {Text("标题");Button("按钮");
    }
    
    解决方案:使用Column/Row/Stack等容器组件包裹所有子组件,确保仅有一个根组件:
    build() {Column() {Text($r('app.string.page_title_home'));Button($r('app.string.btn_change_color'));}
    }
    
  2. 资源管理规范
    • 通用百分比抽离到LayoutConstants,字体大小在float.json管理,所有页面文字在string.json管理,不推荐硬编码;
    • 布局优先用vp/百分比,文字大小必须用fp,不推荐px/lpx;

七、下节预告

本节我们掌握了页面的基本组成、数据驱动逻辑、资源引用以及屏幕尺寸适配概念,下一节将学习线性布局容器(Column/Row),掌握主轴、交叉轴的对齐规则,学会像搭积木一样排列UI组件,实现登录页、首页等常见页面的布局开发。

http://www.jsqmd.com/news/408257/

相关文章:

  • gin框架使用zap,在日志中加入trace_id
  • 2026年北京隔音室厂家电话推荐:主流厂商联系方式汇总 - 品牌推荐
  • 云手机的核心价值是什么?
  • 2026年聚氨酯发泡保温厂家联系电话推荐:全国优质供应商汇总 - 品牌推荐
  • 写代码自动识别房间杂乱程度,给出整理顺序,颠覆房间乱到无从下手。
  • 基于python的高校教职工教师健康监护管理系统 企业员工健康管理系统
  • 2026年环卫服务优质供应商推荐榜资质设备双优:重庆环卫公司、云南环卫公司、单位环卫、四川环卫公司选择指南 - 优质品牌商家
  • 荧光显微镜哪个品牌好?2026年荧光显微镜品牌厂家推荐与排名,解决成本与数据准确性核心痛点 - 品牌推荐
  • 算力服务器的作用都有哪些?
  • 2026年2月深度盘点:基于技术自主性与行业适配性维度下的光学显微镜品牌厂家榜单 - 品牌推荐
  • 应急项目临建活动板房供应商推荐 - 优质品牌商家
  • 医疗AI登Nature!全球首个可溯源系统,罕见病诊断迎来革命
  • 小红书代运营口碑推荐:2026年评测精选指南,抖音运营公司/短视频获客/小红书代运营,小红书代运营公司推荐排行榜 - 品牌推荐师
  • Actipro UI FOR WinForms 2026
  • 大模型微调实战总结:小白也能学会的模型优化流程与收藏技巧!
  • 2026年聚氨酯发泡保温厂家联系电话推荐:全领域应用解决方案 - 品牌推荐
  • 2026钢模板厂家深度选型指南:如何为基建项目匹配最佳模板方案? - 博客湾
  • ZylSerialPort.NET v1.87 cRACK
  • springMVC-RequestMapping注解
  • P3002 [USACO10DEC] Threatening Letter G
  • 全球国际视野:工业AI智能体排名
  • 2026最新盘点:十大高清免费版权图片素材网站推荐,免费版权可商用 - 品牌2026
  • 好写作AI | 一句话翻来覆去说不清?AI帮你精炼语言,表达更精准
  • 2026年度中国荧光显微镜品牌厂家TOP5综合评估与选型指南 - 品牌推荐
  • 2026年聚氨酯发泡保温厂家联系电话推荐:专业选择与联系要点 - 品牌推荐
  • 2026最全 Java 面试八股文汇总(含答案解析)
  • 2026年荧光显微镜品牌厂家推荐:生产与科研场景深度评测,解决稳定性与数据痛点并附购买排名 - 品牌推荐
  • 好写作AI | 平时作业太多?分分钟搞定小论文和读后感!
  • 2026矿山行业振动监测系统优质产品推荐榜:无线振动传感器机构哪家强/振动传感器机构哪家好/振动监测系统公司/选择指南 - 优质品牌商家
  • 意义行为原生论:智能时代意义哲学的创造性建构——兼论其与中国传统知行智慧的会通