目录

一、ArkUI 初印象

二、声明式 UI:编程范式的革新

(一)声明式与命令式的差异

(二)ArkUI 声明式 UI 的工作原理

三、ArkUI 常用组件大揭秘

(一)基础组件:搭建 UI 的基石

(二)容器组件:布局的魔法师

四、用组件声明 UI 的实战攻略

(一)创建项目与搭建基础结构

(二)组件的组合与嵌套

(三)响应式设计:适配不同设备

五、总结与展望


一、ArkUI 初印象

在鸿蒙系统应用开发的广袤天地中,ArkUI 无疑是一颗璀璨的明星,占据着举足轻重的地位。它就像是一位神奇的工匠,为开发者们打造出通往高效、优质应用开发的便捷通道,助力开发者构建出一个个令人惊艳的用户界面。

想象一下,当你打开手机上那些琳琅满目的 App,无论是简洁大气的社交类 App,还是功能丰富的购物类 App,又或是充满趣味的游戏类 App,它们那精致且交互流畅的界面背后,都离不开 UI 开发框架的精心雕琢。而 ArkUI,正是鸿蒙系统应用界面开发的得力助手,它以其独特的魅力和强大的功能,成为了众多开发者的心头好。 今天,就让我们一同走进 ArkUI 的世界,揭开它用组件声明 UI 的神秘面纱。

二、声明式 UI:编程范式的革新

(一)声明式与命令式的差异

在软件开发的长河中,编程范式不断演进,声明式 UI 与命令式 UI 宛如两条分岔的道路,引领着开发者走向不同的开发体验。

命令式 UI 开发就像是一位严谨的工匠,每一个步骤都需要开发者精心雕琢。以创建一个简单的登录界面为例,在命令式开发中,你需要先创建用户名输入框的视图对象,设置其位置、大小、样式等属性,比如设置宽度为 200 像素,高度为 30 像素,位置在页面左上角距离左边界 50 像素,距离上边界 80 像素;接着以同样的方式创建密码输入框和登录按钮的视图对象,并为登录按钮绑定点击事件处理函数,在函数内部编写验证用户名和密码的逻辑。整个过程就像一场细致入微的舞蹈,开发者需要精确地控制每一个动作的顺序和细节 ,代码较为繁琐。例如下面这段使用 Python 语言的 tkinter 库实现的简单登录界面代码,就体现了命令式开发的特点:


import tkinter as tk

def check_login():

username = input_name.get()

password = input_pass.get()

if username == "admin" and password == "123":

result_label.config(text="登录成功")

else:

result_label.config(text="用户名或密码错误")

root = tk.Tk()

root.title("登录界面")

name_label = tk.Label(root, text="用户名:")

name_label.pack()

input_name = tk.Entry(root)

input_name.pack()

pass_label = tk.Label(root, text="密码:")

pass_label.pack()

input_pass = tk.Entry(root, show="*")

input_pass.pack()

login_button = tk.Button(root, text="登录", command=check_login)

login_button.pack()

result_label = tk.Label(root, text="")

result_label.pack()

root.mainloop()

而声明式 UI 开发则更像是一位富有创意的设计师,只需描述出 UI 的最终模样,具体的实现过程则交给框架去完成。同样是这个登录界面,在声明式开发中,你可以使用类似 XML 或 JSON 的语法来描述界面结构,或者使用特定的声明式语言。比如使用 React 框架,通过 JSX 语法,你可以简洁地描述出登录界面包含一个用户名输入框、一个密码输入框和一个登录按钮,无需关心它们具体的创建和布局过程,框架会根据你的描述自动生成对应的 DOM 结构并进行渲染,代码量大幅减少,逻辑也更加清晰。下面是使用 HTML 和 CSS 创建的简单登录界面代码,虽不是严格意义上的声明式 UI 框架代码,但也能体现出声明式描述界面的简洁性:


<!DOCTYPE html>

<html>

<head>

<title>登录</title>

<meta charset="UTF-8">

<style>

body {

background: #f0f0f0;

}

form {

background: #fff;

padding: 20px;

max-width: 400px;

margin:0 auto;

box-shadow:0 0 10px rgba(0,0,0,0.3);

}

input[type="text"], input[type="password"] {

display: block;

margin-bottom: 10px;

padding: 10px;

width: 100%;

border: 1px solid #ccc;

border-radius: 5px;

font-size: 16px;

}

input[type="submit"] {

background: #4CAF50;

color: #fff;

padding: 10px 20px;

border: none;

border-radius: 5px;

font-size: 16px;

cursor: pointer;

}

</style>

</head>

<body>

<form action="" method="post">

<h1>登录</h1>

<label for="username">用户名:</label>

<input type="text" name="username" id="username" required>

<label for="password">密码:</label>

<input type="password" name="password" id="password" required>

<input type="submit" value="登录">

</form>

</body>

</html>

(二)ArkUI 声明式 UI 的工作原理

ArkUI 的声明式 UI 背后蕴含着一套精妙的机制。它就像是一个高效的生产流水线,通过代理和拦截器实现数据与前端 view 的同步更新。当你在代码中定义了一个数据模型,比如一个包含用户信息的对象,代理就会像一个忠实的助手,将这个数据模型进行代理,并与拦截器建立紧密的联系。拦截器则如同一个敏锐的观察者,时刻监听着数据的变化。一旦数据发生更新,拦截器就会迅速做出反应,重写数据的 set 方法,同时自动触发前端 view 的更新,让界面能够实时反映数据的最新状态 。

为了更好地理解,我们可以将其类比为建筑施工流程。假设你要建造一座房子,你首先会有一个详细的设计图纸(对应数据模型),包工头(代理)负责拿着图纸去组织工人施工。而监工(拦截器)则时刻关注着施工过程,一旦图纸有任何修改(数据更新),监工就会立刻通知工人按照新的图纸进行调整(更新前端 view),整个过程无需你亲自去指挥每一个工人的具体动作,大大提高了效率。在这个过程中,开发者无需手动编写大量更新 UI 的代码,只需要专注于数据的定义和业务逻辑的实现,ArkUI 会自动完成数据到 UI 的映射和更新,让开发过程变得更加高效和便捷。

三、ArkUI 常用组件大揭秘

在 ArkUI 的庞大组件库中,有着各种各样的组件,它们就像一个个功能各异的积木块,开发者可以根据自己的需求将它们组合起来,搭建出理想的应用界面。下面,我们就来深入了解一下那些常用的组件。

(一)基础组件:搭建 UI 的基石

基础组件是构建用户界面的基本元素,它们各自具备独特的功能和丰富的属性,是组成复杂页面的基石。

  • Text 组件:作为显示文本的基础组件,Text 就像是一位忠实的 “信息传递者”,将各种文字信息清晰地展示在用户面前。它支持多种属性设置,fontSize 可以调整文字大小,fontColor 能够改变字体颜色,fontWeight 能让文字变得加粗或纤细,fontStyle 可以设置为斜体风格,decoration 还能为文本添加下划线、中划线等装饰 。例如,在一个新闻详情页中,你可以这样使用 Text 组件来展示新闻标题:

Text('震惊!某地区发生重大事件')

.fontSize(20)

.fontWeight(FontWeight.Bold)

.fontColor(Color.Blue);

通过这些属性的组合,能够让新闻标题更加醒目,吸引用户的注意力。除了这些,textAlign 属性可以设置文本的对齐方式,当 Text 组件本身的宽度大于文本内容长度时,该属性就会发挥作用,可取值为 Start(默认值,根据文字书写方向对齐,如中文从左往右排版则靠左对齐)、Center(文本居中对齐)、End(根据文字书写相反方向对齐,如中文从左往右排版则靠右对齐)。maxLines 和 textOverflow 属性可以设置文本显示的最大行数和截取方式,默认折行显示不截取,若设置了这两个参数,文本最多显示到指定行数,多余文本可通过 textOverflow 指定截取方式,取值为 Clip(超出 maxLines 展示行截断内容展示)、Ellipsis(超出 maxLines 展示行省略号) 。

  • Button 组件:Button 组件是实现用户交互的关键,它就像一扇通往各种操作的 “大门”,用户通过点击按钮来触发相应的事件 。它不仅可以设置基本的文本内容,还支持多种样式定制。你可以通过 width 和 height 属性来调整按钮的大小,backgroundColor 设置背景颜色,fontColor 改变字体颜色,border 为按钮添加边框,enabled 属性可以控制按钮是否可用 。比如,在新闻详情页的底部,可能会有一个 “分享” 按钮,代码可以这样编写:

Button('分享')

.width(100)

.height(40)

.backgroundColor(Color.Green)

.fontColor(Color.White)

.border({ width: 2, color: Color.Black })

.onClick(() => {

// 这里编写分享的逻辑代码

console.log('分享按钮被点击');

});

这样,一个美观且功能齐全的分享按钮就创建好了。此外,Button 组件还可以添加子组件来实现不同的展示样式,比如在按钮中同时显示文本和图标,使其更加直观和吸引人。例如:


Button() {

Row({ space: 5 }) {

Image($r('app.media.share_icon')).width(20).height(20);

Text('分享');

}

}

.width(120)

.height(40)

.backgroundColor(Color.Green)

.fontColor(Color.White)

.border({ width: 2, color: Color.Black })

.onClick(() => {

// 分享逻辑代码

console.log('分享按钮被点击');

});

  • Image 组件:Image 组件用于展示图片,它就像一个精美的 “相框”,将各种图片资源完美地呈现出来。通过 src 属性指定图片的来源,可以是本地资源或者网络地址 。width 和 height 属性控制图片的大小,objectFit 属性则决定图片如何适应指定的尺寸,可取值为 Fill(拉伸图片以填满整个容器)、Contain(保持图片的纵横比,缩放图片使其完全包含在容器内)、Cover(保持图片的纵横比,缩放图片使其覆盖整个容器,可能会裁剪部分图片)等 。在新闻详情页中,通常会有一张与新闻内容相关的配图,使用 Image 组件可以这样展示:

Image($r('app.media.news_picture'))

.width(300)

.height(200)

.objectFit(ImageFit.Cover);

这样就能以合适的方式展示新闻配图,为用户提供更丰富的视觉体验。同时,Image 组件还支持一些其他属性,如 interpolation 属性可以设置图像插值,取值为 High(高使用率,使用更复杂算法估计像素值,提高图像视觉质量,增加计算成本)、Medium(中度使用)、Low(低使用率),用于在图像处理中解决图片放大出现锯齿状的问题 。cachedImage 属性可以设置图片是否缓存,retryCount 属性可以设置加载失败时的重试次数,placeholder 属性可以设置图片加载时的占位符等,这些属性能够进一步优化图片的展示效果和加载性能。

(二)容器组件:布局的魔法师

容器组件在 UI 布局中起着至关重要的作用,它们就像一位位神奇的 “魔法师”,能够将子组件进行合理的排列和组合,实现灵活多样的布局效果。

  • Column 组件:Column 容器组件如同一个垂直方向的 “收纳大师”,它会将子组件按照从上到下的顺序依次排列 。通过设置 space 属性,可以调整子组件之间的垂直间距;justifyContent 属性用于控制子组件在主轴(垂直方向)上的对齐方式,可取值为 FlexAlign.Start(子组件与主轴方向的起点位置对齐)、FlexAlign.Center(子组件与主轴方向的中间位置对齐)、FlexAlign.End(子组件与主轴方向的终点位置对齐)、FlexAlign.SpaceBetween(把主轴空间平均分配到子组件之间)、FlexAlign.SpaceAround(首尾子组件和起点、终点的距离是子组件之间距离的一半)、FlexAlign.SpaceEvenly(首尾子组件和起点、终点的距离等同于是子组件之间距离);alignItems 属性则用于控制子组件在交叉轴(水平方向)上的对齐方式,可取值为 HorizontalAlign.Start(在交叉轴的起点位置)、HorizontalAlign.Center(在交叉轴的中间位置)、HorizontalAlign.End(在交叉轴的终点位置) 。在电商商品展示页面中,我们可以使用 Column 组件来布局商品信息。例如:

Column() {

Image($r('app.media.product_picture')).width(200).height(200);

Text('时尚潮流上衣').fontSize(16).fontWeight(FontWeight.Bold);

Text('价格:199元').fontSize(14).fontColor(Color.Red);

Button('加入购物车').width(120).height(40).backgroundColor(Color.Green).fontColor(Color.White);

}

.width('100%')

.padding(10);

这样,商品的图片、名称、价格和操作按钮就会按照垂直方向有序地排列,形成一个清晰的商品展示区域。

  • Row 组件:Row 容器组件则是水平方向的 “组织者”,它会将子组件从左到右依次排列 。其属性的使用方式与 Column 组件类似,space 属性控制子组件之间的水平间距,justifyContent 控制子组件在主轴(水平方向)上的对齐方式,alignItems 控制子组件在交叉轴(垂直方向)上的对齐方式 。比如在电商商品展示页面的顶部,可能会有一个导航栏,使用 Row 组件可以这样实现:

Row() {

Button('首页').width(80).height(40).backgroundColor(Color.LightGray).fontColor(Color.Black);

Button('分类').width(80).height(40).backgroundColor(Color.LightGray).fontColor(Color.Black);

Button('购物车').width(80).height(40).backgroundColor(Color.LightGray).fontColor(Color.Black);

Button('我的').width(80).height(40).backgroundColor(Color.LightGray).fontColor(Color.Black);

}

.width('100%')

.height(50)

.backgroundColor(Color.White);

通过这样的布局,导航栏中的各个按钮会在水平方向上整齐排列,方便用户进行操作。

  • Stack 组件:Stack 组件就像一个 “层叠艺术家”,它允许子组件进行层叠排列,后一个子组件会覆盖在前一个子组件之上 。通过 alignContent 属性可以设置子组件在 Stack 容器内的对齐方式,取值有 Alignment.TopStart(子组件在 Stack 内靠左上角对齐)、Alignment.Top(子组件在 Stack 内靠顶部水平居中对齐)、Alignment.TopEnd(子组件在 Stack 内部靠右上角对齐)、Alignment.Start(子组件靠 Stack 左边侧竖直居中对齐)、Alignment.Center(子组件居中对齐,默认值)、Alignment.End(子组件靠右竖直居中对齐)、Alignment.BottomStart(子组件左下角对齐)、Alignment.Bottom(子组件底部水平居中对齐)、Alignment.BottomEnd(子组件右下角对齐) 。在电商商品展示页面中,我们可以利用 Stack 组件来实现一些特殊的效果,比如在商品图片上添加一个 “新品” 标识。示例代码如下:

Stack() {

Image($r('app.media.new_product_picture')).width(200).height(200);

Text('新品').fontSize(12).fontColor(Color.White).backgroundColor(Color.Red).padding(5)

.alignSelf(Alignment.TopStart);

}

.width('100%')

.padding(10);

在这段代码中,商品图片作为底层组件,“新品” 标识作为上层组件,通过 alignSelf 属性将其定位在图片的左上角,从而实现了在图片上叠加标识的效果。

四、用组件声明 UI 的实战攻略

(一)创建项目与搭建基础结构

现在,让我们一起开启实战之旅。首先,我们要在开发工具中创建一个新的鸿蒙应用项目,这就像是为我们的应用大厦打下坚实的地基 。以 DevEco Studio 为例,打开它后,在欢迎界面点击 “New Project”。在弹出的窗口中,我们需要进行一系列的配置 :

  • 配置项目:为项目取一个富有意义的名字,比如 “SocialApp”,并设置一个合适的包名,例如 “com.example.socialapp” 。同时,选择项目的类型为 “Empty Ability (Java)”,这将为我们创建一个基本的鸿蒙应用项目结构 。
  • 引入 ArkUI 框架:创建好项目后,我们要引入 ArkUI 框架,让它成为我们构建 UI 的得力助手。在项目的 “build.gradle” 文件中,添加 ArkUI 的依赖库,如下所示:

dependencies {

implementation 'com.huawei.ohos:arkui-framework:1.0.0'

}

添加依赖后,点击 “Sync Now” 按钮,让项目同步依赖库,确保 ArkUI 框架能够正常使用 。

  • 搭建基础页面结构:接下来,我们要搭建基础的页面结构。在 “src/main/java/com/example/socialapp” 目录下,找到 “MainAbilitySlice.java” 文件,这是应用的主页面切片。在这个文件中,我们可以使用 ArkUI 的组件来构建页面的基本框架。例如:

import ohos.aafwk.ability.AbilitySlice;

import ohos.agp.components.*;

import ohos.agp.window.dialog.ToastDialog;

public class MainAbilitySlice extends AbilitySlice {

@Override

public void onStart(Intent intent) {

super.onStart(intent);

super.setUIContent(ResourceTable.Layout_ability_main);

// 获取布局容器

DirectionalLayout container = (DirectionalLayout) findComponentById(ResourceTable.Id_container);

// 创建Text组件

Text helloWorldText = new Text(this);

helloWorldText.setText("Hello, ArkUI!");

helloWorldText.setTextSize(20);

helloWorldText.setTextColor(Color.BLACK);

// 创建Button组件

Button clickMeButton = new Button(this);

clickMeButton.setText("Click Me");

clickMeButton.setTextSize(18);

clickMeButton.setTextColor(Color.WHITE);

clickMeButton.setBackgroundColor(Color.BLUE);

// 为Button添加点击事件

clickMeButton.setClickedListener(new Component.ClickedListener() {

@Override

public void onClick(Component component) {

new ToastDialog(getContext()).setText("Button Clicked!").show();

}

});

// 将Text和Button组件添加到布局容器中

container.addComponent(helloWorldText);

container.addComponent(clickMeButton);

}

@Override

public void onActive() {

super.onActive();

}

@Override

public void onForeground(Intent intent) {

super.onForeground(intent);

}

}

在上述代码中,我们首先获取了布局容器,然后创建了一个 Text 组件和一个 Button 组件,并设置了它们的属性 。接着,为 Button 组件添加了点击事件,当按钮被点击时,会弹出一个提示框 。最后,将 Text 和 Button 组件添加到布局容器中,完成了基础页面结构的搭建 。

(二)组件的组合与嵌套

现在,我们已经搭建好了基础页面结构,接下来,让我们以社交 App 个人资料页面为例,来展示如何组合和嵌套组件,打造出个性化的 UI 设计 。社交 App 的个人资料页面通常包含头像、昵称、简介和一些功能按钮,我们可以使用 ArkUI 的组件将它们巧妙地组合在一起 。


@Entry

@Component

struct ProfilePage {

build() {

Column() {

// 头像部分

Image($r('app.media.profile_avatar'))

.width(100)

.height(100)

.objectFit(ImageFit.Cover)

.borderRadius(50)

.alignSelf(HorizontalAlign.Center);

// 昵称部分

Text('张三')

.fontSize(20)

.fontWeight(FontWeight.Bold)

.textAlign(TextAlign.Center)

.margin({ top: 10 });

// 简介部分

Text('热爱生活,喜欢探索新事物')

.fontSize(14)

.textAlign(TextAlign.Center)

.margin({ top: 5 });

// 功能按钮部分

Row() {

Button('编辑资料')

.width(100)

.height(40)

.backgroundColor(Color.LightGray)

.fontColor(Color.Black)

.margin({ top: 10, right: 10 });

Button('关注')

.width(100)

.height(40)

.backgroundColor(Color.Green)

.fontColor(Color.White)

.margin({ top: 10 });

}.alignSelf(HorizontalAlign.Center);

}.width('100%').padding(20);

}

}

在这段代码中,我们使用 Column 组件作为最外层的容器,它将内部的组件按照垂直方向排列 。在 Column 组件中,首先是一个 Image 组件用于展示头像,通过设置 width、height、objectFit 和 borderRadius 属性,让头像呈现为圆形并适应指定的尺寸 。接着是两个 Text 组件,分别用于显示昵称和简介,通过设置 fontSize、fontWeight、textAlign 和 margin 等属性,调整文本的样式和位置 。最后是一个 Row 组件,它将两个 Button 组件水平排列,实现了功能按钮的布局 。通过这样的组件组合和嵌套,我们就实现了一个简单而美观的社交 App 个人资料页面 。

(三)响应式设计:适配不同设备

在如今这个多设备的时代,应用需要在手机、平板、智能手表等不同设备上都能有良好的显示效果,这就需要我们利用 ArkUI 的响应式设计能力 。ArkUI 提供了多种实现响应式设计的方式,让我们的应用能够自适应不同设备的屏幕尺寸和分辨率 。

  • 原子布局能力:ArkUI 的原子布局能力就像是一个智能的布局大师,它能够根据设备的屏幕尺寸和方向,自动调整组件的大小和位置 。例如,我们可以使用 Flex 布局来实现灵活的组件排列 。在下面的代码中,我们创建了一个包含三个按钮的 Row 组件,通过设置 flexGrow 属性,让按钮能够根据剩余空间自动分配大小 :

Row() {

Button('按钮1').flexGrow(1);

Button('按钮2').flexGrow(1);

Button('按钮3').flexGrow(1);

}.width('100%');

这样,在不同设备上,这三个按钮都会均匀地占据 Row 组件的空间,实现了响应式的布局效果 。

  • 媒体查询:媒体查询就像是一个敏锐的观察者,它能够根据设备的特性,如屏幕大小、屏幕方向、分辨率等,来动态地调整组件的样式和布局 。我们可以使用媒体查询来为不同的设备定义不同的样式规则 。例如,当屏幕宽度小于 600px 时,我们将按钮的背景颜色设置为红色 :

@Entry

@Component

struct ResponsiveApp {

build() {

Column() {

Button('点击我')

.width(200)

.height(50)

.backgroundColor(this.$media.query('(max-width: 600px)')? Color.Red : Color.Blue)

.fontColor(Color.White);

}.width('100%').height('100%');

}

}

在上述代码中,通过this.$media.query('(max-width: 600px)')来判断屏幕宽度是否小于 600px,如果满足条件,则将按钮的背景颜色设置为红色,否则设置为蓝色 。

  • 多态组件:多态组件就像是一个神奇的变形金刚,它能够根据设备的类型和屏幕尺寸,自动切换到最合适的布局和样式 。ArkUI 提供了一些多态组件,如 Tabs、List 等,它们在不同设备上会有不同的展示效果 。例如,Tabs 组件在手机上可能以底部导航栏的形式展示,而在平板上可能以侧边栏的形式展示 ,这样就能更好地适应不同设备的交互方式 。通过合理运用这些响应式设计的手段,我们可以让应用在各种设备上都能展现出最佳的用户体验 。

五、总结与展望

通过今天的探索,我们深刻领略了 ArkUI 使用组件声明 UI 的独特魅力和强大功能。声明式 UI 编程范式为我们带来了简洁性、可维护性和高效性的显著提升,让我们从繁琐的 UI 更新代码中解放出来,专注于业务逻辑的实现。ArkUI 丰富的组件库,无论是基础组件还是容器组件,都为我们构建各种类型的应用界面提供了丰富的素材和灵活的布局方式 。

在实战过程中,我们学会了创建项目、搭建基础结构,以及如何巧妙地组合和嵌套组件,打造出个性化的 UI 设计 。同时,利用 ArkUI 的响应式设计能力,我们能够让应用在不同设备上都能展现出良好的用户体验 。

如果你对鸿蒙应用开发充满热情,那么 ArkUI 绝对是你不可错过的强大工具 。希望大家能够勇敢地尝试使用 ArkUI 进行鸿蒙应用开发,将自己的创意和想法转化为一个个精彩的应用 。相信在不久的将来,我们能够看到更多基于 ArkUI 开发的创新应用,在鸿蒙生态中绽放出绚丽的光彩 。

Logo

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

更多推荐