一、课程笔记
1.1 ArkUI框架介绍
ArkUI(方舟UI框架)为应用的UI开发提供了完整的基础设施,包括简介的UI语法、丰富的UI功能(组件、布局、动画,以及交互事件),以及实时界面预览工具等,可以支持开发者进行丰富页面的开发。
1.1.1 基于关键的应用UI开发底座,深度融合语言/编译器/图型
1.1.2 极简开发、高性能、跨设备、跨平台
1.1.3 声明式UI开发范式
(1)简介
基于ArkTS的声明式开发范式的方舟开发框架是一套极简、高性能、支持跨设备的UI开发框架,提供了构建HarmonyOS应用UI所必需的能力。声明式UI是系统选用的新一代开发范式,通过数据驱动UI变化,UI逻辑分离,更直观,更高效。声明式语法能够主力开发人员将更多精力聚焦于业务逻辑,减少对细节实现的关注,进而提升编码效率和代码可读性。
(2)声明式开发范式与传统命令时开发范式有什么区别?
通过下图可显然看出,基于ArkTS的声明式开发范式所编写的代码更为简洁、优雅。命令式编程,因名得意,是开发者一步步告诉计算机执行一系列操作,获得期望结果的过程。而声明式编程则是告诉计算机期望的结果,具体的实现是有程序根据特定的算法自动推算出来。
相较于命令时开发范式,声明式开发范式主要具有以下优点:
- 对于系统使用方而言,通过设计声明式接口,开发者无需关心底层,实现细节,可将更多注意力放在上层业务上。
- 对于系统实现方而言,借助生命时接口在保证上层使用者接口相对稳定的前提下,系统能够持续迭代优化。
- 而对于整个系统而言,这种方式能够更全面地收集信息,并依据相应策略优化系统行为,从而提升系统效率
1.1.4 常用组件
ArkUI提供了丰富的UI组件库,并且都符合HarmonyOS设计规范的全量控件。
(1)基础组件
基础组件,常用于展示页面的基础元素,例如Button、Text、Image等。
· Button组件
Button组件,通常响应用户的点击操作。其样式大致分为普通按钮、胶囊按钮和圆形按钮。当Button作为容器使用时,可通过添加子组件的方式实现包含文字或者图片等元素的按钮。
· Text组件
Text组件,是文本组件,常用于在用户视图中展示内容。比如,显示文章文字。
它提供的两种文字加载模式:
- 一种是直接加载文本,他只需要在Text组件内设置文字字符串即可;
- 另一种是采用资源方式加载。但这种方式需要在代码过程中预先配置好资源。
· Image组件
Image组件,可以实现在应用中显示图片。其支持png、JPG、bmp、svg,以及gif等过重图片格式。可用于丰富应用界面使用。
(2)布局容器组件
布局容器组件,用于界面上组织组件的排列,例如Row、Column、List、grid、swiper等。
· Row、Column组件——线性布局
线性布局,是开发中最常用的布局方式。通过线性容器Row和Column构建,其子元素在线性方向上依次排列。Row容器内子组件按照“水平方向”排列;Column容器内子组件按照“垂直方向”排列。
· Swiper组件
Swiper组件具有滑动、轮播显示能力。它本身是一个容器组件。当设置多个子组件后,可以对这些子元素进行轮播展示
· List组件
List组件,即列表,是一种复杂组件。当列表项达到一定数量,超出屏幕大小时,会自动提供滚动功能。适用于呈现同类数据类型,或者数据类型集合,如图片和文本。
· Grid组件
Grid网格组件是由行和列分割而成的单元格组成。通过指定项目所在的单元格实现各种布局,具有较强的页面均分和子组件占比控制能力,是一种重要的自适应布局。
瀑布流容器,同样由行和列芬格的单元格组成。 瀑布流容器同样由行和列分割的单元格组成,通过自身排列规则可以将大小不同的项目自上而下如瀑布般紧密布局。
(3)导航组件
导航组件,用于实现页面跳转或切换,例如Navigation、Tabs等。
· Navigation组件
Navigation是路由容器组件,主要包含导航页和子页。
导航页由标题栏和工具栏组成。其中,导航页可以通过hideNavBar属性隐藏,它不存在于页面栈中。导航页与子页,以及子页之间可以通过路由操作切换。
· Tabs组件
Tabs组件的页面由TabContent和TabBar两部分组成。TabContent是内容页,而TabBar是导航页签栏。根据不同导航类型,其布局有所不同,可以分为底部导航、顶部导航、侧边导航。相应的导航栏分别位于底部、顶部和侧边。
· 其他组件
除了上述组件外,还有很多组件。如,
- 图案密码锁组件(以九宫格图案方式输入密码,适用于密码验证场景)
- 滑动条组件(用于快速调节设置值,如音量、亮度调节等应用场景)
- 自定义弹窗组件
- 弹窗选择器组件(这些组件具备滑动或下拉效果,能够给用户提供选择,在选择日期、时间、地点等场景下经常出现。)
1.1.5 更多功能简介
(1)ArkTS/C++混合开发能力,高性能编码
为实现ArkTS与C++的混合开发能力, ArkUI基于XComponent组件,可支持重载场景下的高性能开发。开发者可将高负载渲染能力,用C++构建为动态库,而引用逻辑则采用ArkTS编码。例如,
- 适用场景1:使用XComponent组件,实现需独立渲染的游戏地图等
- 使用场景2:相机的预览与显示等功能
(2)应对多设备页面布局的差异问题
为应对多设备页面布局的差异问题,ArkUI提供了自适应布局和响应式布局,以此实现一套代码适配多个设备的布局效果。
(3)应对多设备交互的差异问题
同时,由于不同设备的交互方式存在差异,如用户在PC上使用鼠标、键盘交互;在手机和平板上使用触摸交互。ArkUI提供了交互归一事件,以及组件交互归一方式,屏蔽交互差异,统一交互逻辑。
(4)实施开发预览,所见即所得
ArkUI与DevEco Studio紧密配合,提供了实时预览功能,真正实现所见即所得。 预览器效果与目标设备的UI呈现效果一致,并且子啊编辑过程中同步更新。预览器和代码可双向预览,实时查看和编辑组件属性。 除此之外,IDE中还提供组件级预览和多设备预览,全方位帮助开发者实现预览功能。
1.2 声明式UI语法——案例:待办列表
通过该案例,更好的了解ArkTS声明式UI语法。
声明式UI的显著特征:
- 声明式描述(开发者只需要将注意力集中在UI应该呈现的最终结果上,至于其内部复杂的实现过程则无需理会)
- 状态驱动视图更新(在开发时我们并非对UI进行操作,而是通过改变状态数据间接触发UI的变化)
1.2.1 声明式描述
如下图所示,在Row组件中有两个组件,先声明了Image,后声明了Text。这段代码清晰的描述了图标和文本横向排列的布局。这就是声明式描述。
简言之,代码就是按照用户看到的界面来编写的。而具体地实现,则交由框架来处理。
1.2.2 状态驱动视图更新
在ArkTS中,状态是驱动UI变化的数据,视图则是与状态相关联的UI内容。当状态发生改变时,框架会自动更新与该状态相关连的视图,从而实现内容的动态变化。
以下图为例,使用@State装饰器将变量isComplete转变为状态变量。在进行UI描述时,利用这个状态变量建立起状态与视图之间的依赖关系。
1.2.3 使用组件声明式UI
自定义组件,可以通过多种组件组合,封装为可重用、可组合的UI单元。还是通过“案例:待办事项”,观察代办列表中的每一个待办项,理解自定义组件的许多特性。
(1)观察待办列表项
下图所示,灰色部分就是每一个待办项的内容。它们具有结构相同、功能都是展示待办事项及其完成状态。所以,我们没必要为每一个待办项重新创建一个全新的组件。这就给组件的重用营造了机会。
我们使用struct声明一个名为ToDoItem的结构。然后通过@Component装饰器将这个结构转化为一个自定义组件。这样ToDoItem这个结构就可以成为整个页面的组成部分,并能够被重复使用。
(2)观察待办列表
待办列表包含了待办标题,以及每一项的内容,是一个完整的页面。其功能是展示待办列表的所有内容。我们通过struct声明其组件名为ToDoListPage。同样使用@Component使其成为自定义组件。不过ToDoListPage还有一个特殊之处——它使用了@Entry装饰器。@Entry装饰器的作用表明这个组件是一个入口页面。可以通过UIAbility进行加载,也可以通过路由来访问。
(3) 如何将组件在页面中展示出来?
我们在声明完成自定义组件后,还需要对齐进行UI描述,这样才能在页面中展示出来。我们要在struct结构体内配置build函数——这里就是自定义组件进行声明式UI描述的地方。
build函数使用大括号包裹需要描述的UI。在UI描述中,通过大括号和缩进的方式来区分不同组件,以及组件内部的内容。
(4)介绍ToDoListPage自定义组件的结构
在ToDoListPage这个自定义组件内部
有作为容器的column,
column内部包含了用于显示文字的text组件
以及我们刚刚封装好的ToDoItem自定义组件,
通过合理的对页面内容进行抽象,提取出结构相同且功能明确的UI单元,并将它们组合为自定义组件,再对自定义组件进行合理组合,我们就能够完成应用界面的开发。
1.2.4 处理组件生命周期执行流程
回顾一下自定义组件和页面的关系。自定义所见是被@Component装饰的UI单元,它可以将多个系统组件组合在一起,实现UI的复用。同时它可以调用组件自身的生命周期方法,页面是应用的UI界面,可以由一个或者多个自定义组件组成。其中被@Entry装饰的自定义组件是页面的入口组件,也就是页面的根节点。一个页面有且仅有一个这样的入口组件,而且只有被at entry装饰的组件才可以调用页面的生命周期方法。
如图所示,在待办页面出现和消失的过程中,会触发由@Entry装饰的自定义组件的生命周期。
这个生命周期包含aboutToAppear()、onPageShow()、onPageHide()、aboutToDisappear()这些方法。由于页面是由一个或者多个自定义组件构成的,所以在这个过程中,也会触发自定义组件的生命周期,包括aboutToAppear()、aboutToDisappear()这两个方法。
下面我们详细了解一下每个生命周期函数的执行流程。
(1)aboutToAppear()
当组件即将出现时,会调用aboutToAppear函数。具体的执行时机实在创建自定义组件的新实例之后执行其build函数之前。在这个函数中,我们可以对状态变量进行修改。这些修改会在后续执行build函数时生效。
(2)onPageShow()
每当页面显示的时候,onPageShow的函数就会触发。比如,在路由跳转过程中,应用介入前台等场景下。需要注意的是,这个函数仅在被@Entry装饰的自定义组件中生效。
(3)onBackPress()
当用户点击返回按钮或侧滑返回时,则会先触发onBackPress函数回调。随后页面进入隐藏状态或应用进入后台。此时onPageHide函数也会被触发。需要注意的是,这个函数仅在被@Entry装饰的自定义组件中生效。
(4)onPageHide()
当页面隐藏时,会触发onPageHide函数。如在路由跳转过程中,以及引用进入后台等情况。需要注意的是,这个函数仅在被@Entry装饰的自定义组件中生效。
(5)aboutToDisappear()
这个函数在自定义组件销毁之前执行。开发者可以在这个函数回调中释放UI资源,从而减少应用锁占用的内存。
1.2.5 配置属性与布局
组件的默认样式一般并不能直接满足实际需要,所以需要调整使之显示更加合理。ArkUI中支持通过点运算符的方式为内置组件配置属性。
(1)标题
(2) 待办项
(3) 如何实现UI交互
默认情况下,待办项都显示未完成,可以点击该项来标记任务完成。比如,前面的圆圈变为对钩、整个待办项中的内容变灰、文字中加上删除线。这样用户就能直观看出该任务已经完成了。
这样我们就需要额外引入一个状态变量控制视图显示状态。比如,一个被@State修饰的isComplete变量,就可以建立起状态与视图的绑定关系。
那么,这两种展示效果是如何切换的呢?对于这种根据不同条件控制页面内容显示或隐藏的情况,可以通过if、else条件渲染语句。
- 图表部分的代码实现如下:
- 文字部分的代码实现如下:
- 改变组件的状态
(4) 渲染列表数据
列表控件中的每一项并不需要独立定义自定义组件,可以使用forEach语法,快速在页面上创建具有相同布局的内容。
forEach语法需要接受两个参数:
- 数据源
- 生成器函数
1.3 布局你的页面
1.3.1 布局的定义
布局,指用特定的组件或者属性来管理用户页面缩放至UI组件的大小和位置。
1.3.2 常见的布局
常见的几种布局有:线性布局、层叠布局、相对布局
(1)线性布局
线性布局,是页面开发中,最基础且最常见的布局方式之一。它能使元素在页面中实现水平或垂直方向的排列。线性布局可通过线性容器Row和Column构建。Row容器中的组件会按照从左至右的顺序排列;Column容器中的组件会按照从上至下的顺序排列。
(2)层叠布局
层叠布局,用于在屏幕上预留一块区域来显示组件中的元素,可实现元素重叠的效果。它通过Stack组件实现。层叠布局在页面堆叠和定位方面能力较强,常用于广告、卡片堆叠效果等场景。
(3)相对布局
相对布局,它支持给容器内部的子元素设置相对位置关系,便于对多个子组件进行对齐和排列。RelativeContainer是采用相对布局的容器,支持子元素设置相对位置关系,适用于复杂界面场景下多个子组件的对齐和排列。子元素可指定兄弟元素作为锚点,也可以指定父容器作为锚点,并基于锚点来进行相对位置布局。
问题来了!在什么场景下使用相对布局更合适呢?
如图所示,一个容器内有5个item组件分别位于容器内的左上、右上、右下、左下和中间位置。
如果使用线性布局,由于其特点是让元素在页面中沿水平或垂直方向排列,所以至少需要一个column多个的row容器才能实现这个页面布局。
但是,如果使用相对布局,这样就会更加简洁,只需一个RelativeContainer容器,然后设置组件基于容器的相对位置,就能实现该页面布局。
(4)更多布局
1.3.3 页面的布局结构
页面的布局,通常是分层结构。组件按照布局的要求依次排列构成应用的界面。布局组件除了能放置基础组件外,也可以放置其他布局组件。通过多层布局的嵌套,可以实现更加复杂的页面布局。
在实际应用开发过程中要保证整体的布局效果,可以参考以下流程:
- 分析页面的布局结构
- 分析页面的元素构成
- 选用合适的布局容器组件或属性控制页面中各个元素的位置和大小
当我们拿到UX设计时给出的设计图后,我们需要对页面进行拆解。先确定页面的布局结构,再分析页面上的内容分别用哪些组件实现,最后选取合适的容器组件承载这些组件。
页面拆解完成后,我们就得到了页面组件的组件树。
1.3.4 Column/Row容器使用样例
还是回到这个登录页面案例,所有组件基本上都是垂直方向布局的,所以依次放置于Column容器即可。但其中又有两处组件是水平排列的。那么就要在Column容器中嵌套Row容器来实现。
(1)Column/Row容器基础知识
引入两个轴的概念:主轴、交叉轴。主轴和交叉轴永远垂直。但注意,并不是所有铅垂方向的轴都是主轴!
我是这么记忆的:
- Column容器中的元素内容默认垂直排列,那么主轴方向就是垂直的;同理,Row容器的元素内容默认水平排列,那么主轴方向就是水平的。
- 主轴和交叉轴又是永远垂直的。
- 所有水平方向的轴,正方向一律向右;所有铅垂方向的轴,正方向一律向下。
所以,我们只需要记住主轴是谁?交叉轴就是另一个即可。这样不容易混淆。
(2)Column/Row容器介绍
(3)子组件的对齐方式
· 在主轴方向上
· 在交叉轴方向上
1.4 组建简单页面
1.4.0 回顾登录页面案例的组件分析
1.4.1 显示图片——Image组件
(1)设置图片数据源
(2)设置图片大小
(3)设置图片外边距
(4)设置图片缩放类型
- contain:让图片保持宽高比进行缩放或者放大,确保图片完全显示在边界内;
- Cover:使用Cover来让图片保持宽高比进行缩放,使图片两边都大于或等于显示边界;
- Auto:使用Auto图片会根据自身尺寸和组件尺寸进行适当的缩放,在保持比例的同时填充视图;
- Fill:使用Fill会使图片充满显示边界;
- ScaleDown:使用ScaleDown能让图片保持宽高比显示图片缩小或者保持不变;
- None:使用None表示图片,按照原有尺寸显示。
1.4.2 文本显示Text
(1)添加子组件——Span
Span可以作为Text组件的子组件来显示文本内容。当Text和Span同时配置文本信息时,Span的内容会覆盖Text的内容。
(2)设置文本内容
(3)设置文本大小
(4)设置文本粗细
(5)设置文本颜色
(6)设置文本装饰线及颜色
(7)文本超长处理
1.4.3 文本输出TextInput
(1)设置提示文本
(2)设置最大输入字符数
(3)设置文本框输入类型
(4)设置OnChange事件
该事件中,value为获取的用户输入的文本信息,可用于用户登录时的账号、密码校验。
1.4.4 按钮Button
(1)设置按钮类型
(2)设置按钮自定义样式
(3)设置按钮点击事件
1.4.5 组建登录页面
(1)添加Image图标和Text文本
(2)账号、密码输入
(3)登录与注册
(4)其他登录方式
这里需要再引入一个知识点:轻量化UI复用机制——@Builder的使用。开发者可将一些重复使用的UI元素抽象成一个方法,然后在build方法内调用。
1.5 案例:页面与数据
课程中的第2个案例,“页面与数据”案例需要大家自己动手根据文档指引,一步步完成。
我已将最终代码上传到Gitee,大家可以自行拉取——仓库:page-and-data01。
二、习题整理
2.1 判断题
1. Button作为容器使用时可以通过添加子组件实现包含文字、图片等元素的按钮,其类型包括胶囊按钮、圆形按钮、普通按钮。
答案:正确
2. Resource是资源引用类型,用于设置组件属性的值,可以定义组件的颜色、文本大小、组件大小等属性。
答案:正确
3. 在Column容器中的子组件默认是按照从上到下的垂直方向布局的,其主轴的方向是垂直方向,在Row容器中的组件默认是按照从左到右的水平方向布局的,其主轴的方向是水平方向。
答案:正确
2.2 单选题
1. 关于ForEach循环渲染的描述错误的是:
- A. arr数据源,为Array类型的数组。
- B. itemGenerator为子组件生成函数,为数组中的每个元素创建对应的组件。
- C. keyGenerator为数组项唯一键值生成函数,为数据源arr的每个数组项生成唯一且持久的键值,函数返回值为开发者自定义的键值生成规则。
- D. ForEach基于数组类型数据来进行循环渲染,需要与容器组件配合使用,且可以返回任意子组件。
答案:D
2. Image不支持哪种图片格式:
- A. svg
- B. eps
- C. gif
- D. bmp
答案:B
3. 下面哪个组件层次结构是错误的:
- A. List>ListItem>Column
- B. Column>List>ListItem
- C. Grid>Row>GridItem
- D. Grid>GridItem
答案:C
4. 需要在主轴上使第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半,通过下列哪种方式设置:
- A. justifyContent(FlexAlign.SpaceBetween)
- B. justifyContent(FlexAlign.SpaceAround)
- C. justifyContent(FlexAlign.SpaceEvenly)
- D. justifyContent(FlexAlign.Center)
答案:B
解析:FlexAlign
2.3 多选题
1. 关于ImageFit的类型和说明正确的是:
- A. Contain:保持宽高比进行缩小或者放大,使得图片完全显示在显示边界内。
- B. None:保持原有尺寸显示。
- C. Fill:不保持宽高比进行放大缩小,使得图片充满显示边界。
- D. Scale:保持宽高比显示,图片缩小或者保持不变。
- E. Cover:ImageFit的默认值,保持宽高比进行缩小或者放大,使得图片两边都大于或等于显示边界。
答案:ABCE
解析:ImageFit
2. Row容器的主轴是水平方向,交叉轴是垂直方向,其参数类型为VerticalAlign (垂直对齐),VerticalAlign 定义了以下几种类型?
- A. Top
- B. Bottom
- C. Start
- D. End
- E. Center
答案:ABE
3. TextDecorationType不包含哪几种类型?
- A. None
- B. LineThrough
- C. TopLine
- D. Bottomline
答案:CD
三、心得体会
N/A