鸿蒙NEXT场景化开发:ArkUI入门体验

412 阅读16分钟

ArkUI 自2021 推出以来,每年随着 API 版本的更新都会新增新的 API,截止 2024 年底,HarmonyOS 已经更新至 5.0.0 版本,该版本API能力级别为API 12 Release。

本章将介绍ArkUI基础组件和高级组件的使用,在 ArkUI 中,组件是 UI 构建和显示的最小单元,UI(用户界面) 由多个组件组合而成。

1.1 前期准备

首先创建一个名为 MyStack 的 ArkUI 项目,创建步骤如下:

  1. 安装并启动 DevEco-Studio。
  2. 点击“欢迎使用”页面右上角的“新建项目”按钮。
  3. 在“应用模版”弹窗中选择 Empty Ability 模版,点击 Next 按钮;
  4. 在“创建项目”弹窗中修改 Project name 为MyStack,点击 Finish 按钮;

完成上述步骤后,DevEco-Studio 将创建一个HarmonyOS 项目,并打开工程开发面板。

1.2 常见布局组件

多个组件的组合时,需要依赖布局组件进行页面排版,常见的基础布局组件有Row、Column 和 Stack,其中Row 和Column 组件属于线形布局,用于实现水平方向和垂直方向的元素排列,Stack 组件属于层叠布局,通过子元素的依次入栈来实现重叠布局排列。

选择左侧“项目目录”面板中的 Index.ets 文件,将build()函数中的内容替换为Row 组件和 Text 组件,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {

  build() {
    Row(){
      Text('欢迎使用')
        .fontSize(17)
        .fontColor(Color.Gray)
      Text('ArkUI')
        .fontSize(17)
        .fontColor(Color.Blue)
    }
    .width('100%')
  }
}

点击右侧面板中的“预览器”按钮,DevEco-Studio 将加载内置的项目预览器,开发者将可以实时查看代码预览的效果。如图 1-1 所示。

图 1-1 预览器预览当前项目

Row 组件实现容器内子元素的水平方向的布局能力,当Row 组件中放入两个 Text 组件时,Text 组件将按照水平方向进行排版。通过为Text 组件添加fontSize、fontColor 修饰器,可以设置 Text 组件显示的文本的字体大小和字体颜色。

下一步,添加元素间距和设置Row 组件内子元素在水平方向上的排布方向,如图 1-2 所示。

//第1章/Index.ets
@Entry
@Component
struct Index {

  build() {
    Row({ space: 10 }) {
      Text('欢迎使用')
        .fontSize(17)
        .fontColor(Color.Gray)
      Text('ArkUI')
        .fontSize(17)
        .fontColor(Color.Blue)
    }
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

图 1-2 Row+space+justifyContent

Row 组件提供space 参数,允许开发者调整Row 组件中子元素之间的间距,justifyContent 修饰器作用于Row 组件本身,用于设置容器内子元素在容器主轴上的排列方式,Row 组件的主轴为水平方向,因此justifyContent 修饰器可以设置子元素在水平方向的对齐方式,对齐方向从左到右依次为:Start(首端)、Center(中心)、End(尾端)。

下一步,添加一个Column 组件和 Text 组件与Row 组件相组合,如图 1-3 所示。

//第1章/Index.ets
Column({space:15}) {
  Row({ space: 10 }) {
    Text('欢迎使用')
      .fontSize(17)
      .fontColor(Color.Gray)
    Text('ArkUI')
      .fontSize(17)
      .fontColor(Color.Blue)
  }
  .width('100%')
  .justifyContent(FlexAlign.Center)

  Text('ArkUI(方舟UI框架)为应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。')
      .fontSize(14)
      .fontColor(Color.Gray)
}

图 1-3 Row+Column

Column 组件实现容器内子元素的垂直方向的布局能力,当Column 组件的闭包中有Row 组件和Text 组件两个子元素时,Column 组件将实现子元素的垂直排列。Column 组件与Row 组件同样可以通过设置space 参数来调整子元素之间的间距。

下一步,添加一个Stack 组件,并使用十六进制颜色值设置背景颜色,如图 1-4 所示。

//第1章/Index.ets
Stack() {
  Column({ space: 15 }) {
    Row({ space: 10 }) {
      Text('欢迎使用')
        .fontSize(17)
        .fontColor(Color.Gray)
      Text('ArkUI')
        .fontSize(17)
        .fontColor(Color.Blue)
    }
    .width('100%')
    .justifyContent(FlexAlign.Center)

    Text('ArkUI(方舟UI框架)为应用的UI开发提供了完整的基础设施,包括简洁的UI语法、丰富的UI功能(组件、布局、动画以及交互事件),以及实时界面预览工具等,可以支持开发者进行可视化界面开发。')
      .fontSize(14)
      .fontColor(Color.Gray)
  }
}
.width('100%')
.height('100%')
.backgroundColor('#c2e9fb')
.expandSafeArea([SafeAreaType.SYSTEM], [SafeAreaEdge.TOP, SafeAreaEdge.BOTTOM])

图 1-4 Row、Column 和Stack

Stack 组件用于设置子元素的堆栈方式,通过从上至下的代码优先级来呈现组件的堆叠效果。backgroundColor 修饰器用于设置组件的背景填充色,与fontColor 修饰器效果类似,可使用系统内置颜色和十六进制颜色值来设置填充效果。

expandSafeArea 修饰器用于控制组件扩展其安全区域,安全区域是指页面的显示区域,默认不与系统设置的非安全区域比如状态栏、导航栏区域重叠,默认情况下开发者开发的界面都被布局在安全区域内。expandSafeArea 修饰器允许开发者设置组件绘制内容突破安全区域的限制,设置其属性SYSTEM、TOP、BOTTOM,则Stack 组件将会突破系统默认、态栏和导航栏区域,达到沉浸式效果。

以上是关于Row、Column 和Stack 组件的使用案例,通过熟练使用基础布局组件,将可以高效地对 ArkUI 组件进行组合来实现丰富的页面效果。

1.3 文本和图片

文本是应用中最为常见的元素,用户从文本中读取内容和获取信息。图片让应用不再单调,炫彩的图片让应用充满活力。文本与图片的组合,可以让应用更加精美和直观。

创建一个名为 MyGraphics 的新的 HarmonyOS 项目,并打开工程开发面板。将build()函数中的内容替换为Column 组件和 Text 组件,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {
  
  build() {
    Column(){
      Text('Hello World')
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

添加fontSize 和fontWeight 修饰器到 Text 组件上,在预览器中查看Text 组件文本的变化,如图 1-5 所示。

@Entry
@Component
struct Index {

  build() {
    Column(){
      Text('Hello World')
        .fontSize(23)
        .fontWeight(FontWeight.Medium)
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

图 1-5 设置字体大小和加粗

fontWeight 修饰器允许开发者调整文本显示时字体的加粗样式,常常与fontSize 修饰器配合使用。

在Index 视图中创建两个状态变量:email、password,变量声明的代码需要放置在build()函数同级结构且不允许重复,声明好的变量可用于存储内容与绑定视图状态,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {
  @State email: string = ''
  @State password: string = ''

  build() {
    ...
  }
}

下一步,在Column 组件中添加TextInput 组件,TextInput 组件显示的内容绑定声明好的状态变量,如图 1-6 所示。

//第1章/Index.ets
Column(){
  Text('Hello World')
    .fontSize(23)
    .fontWeight(FontWeight.Medium)

  TextInput({ text: this.email, placeholder: '用户名/邮箱'})
    .width('95%')
    .contentType(ContentType.EMAIL_ADDRESS)
    .maxLength(9)
    .margin(10)
    .onChange((value: string) => {
      this.email = value
    })

  TextInput({ text: this.password, placeholder: '请输入密码'})
    .width('95%')
    .type(InputType.Password)
    .maxLength(9)
    .margin(10)
    .onChange((value: string) => {
      this.password = value
    })
}
.height('100%')
.width('100%')
.justifyContent(FlexAlign.Center)

图 1-6 使用 TextInput

与 Text 组件显示文本不同,TextInput 组件需要绑定状态变量来存储用户输入的文本内容。在 ArkUI 中,状态变量的声明使用@State 装饰器声明,@State 装饰器提供了存储管理能力,在状态变量发生变化时将自动触发视图的刷新。

TextInput 组件用于显示用户输入的内容。type 修饰器允许开发者指定TextInput 组件输入的文本类型,默认值为Normal,可设置EMAIL_ADDRESS(邮箱地址)、Password(密码)等类型。其中 Password 类型场景下,TextInput 组件输入的文本支持切换隐藏和显示状态。

maxLength 修饰器允许开发者设置文本显示的最大长度,margin 修饰器允许开发者调整组件的外边距,onChange 修饰器用于监听TextInput 组件输入内容发生变化时的回调事件。用户输入的内容通过 this 函数进行字段绑定,在当前案例中将TextInput 组件输入的内容value 绑定email、password 状态变量,并通过赋值运算符=进行绑定内容的更新。

图片是应用中重要的元素,开发者使用图片传递信息和提高用户体验。将下载好的图片素材拖放media 文件夹中,路径为MyGraphics/entry/src/main/resources/base/media。如图 1-7 所示。

图 1-7 media 文件夹

添加一个 Image 组件到Column 组件中,通过$r资源接口读取本地资源并转换为Resource格式资源来加载和显示图片,如图 1-8 所示。

//第1章/Index.ets
Column(){
  Image($r('app.media.img001'))
    .width(200)
    .objectFit(ImageFit.Contain)
    .margin(48)

  ...
}

图 1-8 Image 组件显示图片

使用 Image 组件显示图片时会默认以原始图片比例显示图片大小,图片可能会因为尺寸太大而超出显示边界。objectFit 修饰器允许开发者根据屏幕设备大小对图片进行缩放,常见的缩放类型有Contain(等比例缩放,且保持图片完全在边界内)、Cover(等比例缩放,且保持图片两边大于等于边界)、Auto(自适应显示)、Fill(图片铺满边界)、ScaleDown(等比例缩放,图片缩小或者保持不变)。

图片也可以被裁减成特定的形状,clipShape 修饰器允许开发者按指定形状对组件进行裁剪,如图 1-9 所示。

//第1章/Index.ets
Image($r('app.media.img001'))
  .width(120)
  .objectFit(ImageFit.Contain)
  .margin(48)
  .clipShape(new Circle({width:120,height:120}))

图 1-9 裁剪图片

clipShape(new Circle())将 Image 组件裁剪为圆形形状,在Circle 圆形组件中设置形状的大小与图片大小一致。

1.4 按钮和导航

按钮在应用中承担着重要的交互角色,当按钮被点击时会触发相应的事件来响应用户的操作。

添加一个 Button 组件到Column 组件中,并将Button 组件的代码位置放置在显示密码输入框的 TextInput 组件之后,如图 1-10 所示。

//第1章/Index.ets
Column(){
  ...
  
  Button('登录', { type: ButtonType.Capsule, stateEffect: true })
    .backgroundColor(Color.Blue)
    .width(180)
    .height(40)
    .margin(10)
    .onClick(()=>{
      console.info('按钮被点击')
    })
}

图 1-10 Button 组件显示按钮

Button 组件允许开发者设置按钮的样式,label 参数用于设置按钮显示的文本内容,type 参数用于设置按钮的类型,常见的按钮类型有Normal(普通按钮)、Capsule(胶囊按钮)、Circle(圆形按钮)。stateEffect 参数用于设置按钮的点击效果,默认为true 开启状态。

onClick 修饰器常与Button 组件搭配使用,可以在按钮被点击时触发和执行某项交互动作,比如:使用console.info 作为按钮被点击时的响应事件。

打开DevEco-Studio 底部的“日志”按钮,在左上角设备选项中选择 Phone 选项,在预览器中点击Button 组件时,日志中将打印“按钮被点击”文字,如图 1-11 所示。

图 1-11 查看系统日志

为 Index 视图添加Navigation(路由导航)作为根视图容器,将Column 组件所包含的所有代码都剪切到Navigation 容器中,如图 1-12 所示。

//第1章/Index.ets
Navigation() {
  Column(){...}
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
}
.title('欢迎使用App')

图 1-12 Navigation+title

Navigation 组件用于 ArkUI 视图之间的导航,通过提供灵活的跳转栈操作,从而更便捷地实现对不同页面的访问和复用。添加 title 修饰器为 Index 视图设置标题,标题默认显示模式为Stack(单页面显示模式)。

创建一个名为DetailPage 的自定义组件,作为导航的目标页面,代码如下:

//第1章/Index.ets
// 首页
@Entry
@Component
struct Index {...}

// 目标页面
@Component
struct DetailPage {
  @Consume('pageStack') pageStack: NavPathStack
  @Prop param: string

  build() {
    NavDestination() {
      Stack() {
        Text(this.param)
      }
      .width('100%')
      .height('100%')
    }
    .title('详情页')
    .onReady((context: NavDestinationContext) => {
      this.pageStack = context.pathStack
    })
  }
}

@Component 装饰器用于构建自定义 ArkUI 组件,自定义 ArkUI 组件的主体代码结构为“struct 关键字+页面名称”,闭包中使用build() 函数构建 UI 结构。

DetailPage 视图通过 NavDestination 组件声明为一个导航目标页面,NavDestination 组件与Navigation 组件使用方法类似,支持使用title 修饰器设置页面标题,以及使用 onReady 修饰器设置页面生命周期的回调事件。

在视图准备就绪时,通过 NavDestinationContext 获取pathStack(导航路径栈)并将其赋值给组件的 pageStack 属性,以便后续管理页面导航。

DetailPage 页面使用 @Consume 装饰器注入了一个名为 pageStack 的导航路径栈实例,用于管理页面的跳转和返回逻辑,同时通过 @State 装饰器声明了一个状态变量 param,用于存储并动态更新页面显示的参数内容。

下一步回到 Index 视图中,Navigation 组件的路由跳转能力基于NavPathStack 提供的方法实现,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {
  ...
  @Provide('pageStack') pageStack: NavPathStack = new NavPathStack()

  @Builder pageMap(name: string,param:string) {
    if (name === 'DetailPage') {
      DetailPage({param:param})
    } else {
      Text('404')
    }
  }

  build() {
    Navigation(this.pageStack) {
      ...

      Button('登录', { type: ButtonType.Capsule, stateEffect: true })
        .backgroundColor(Color.Blue)
        .width(180)
        .height(40)
        .margin(10)
        .onClick(() => {
          this.pageStack.pushPath({ name: "DetailPage", param:'详情页参数'})
        })
    }
    .title('欢迎使用App')
    .navDestination(this.pageMap)
  }
}

Index 视图通过@Provide装饰器声明并初始化了一个名为 pageStack 的导航路径栈,该栈用于管理应用中的页面导航,实现页面的入栈和出栈操作,即实现页面的跳转和返回操作。@Provide 装饰器与@Consume 装饰器可配合使用,实现pageStack 在组件之间的传递和使用。

接下来通过@Builder装饰器声明一个自定义方法pageMap,用于根据页面名称动态渲染对应的页面内容。pageMap方法接收 2 个参数:name 表示目的页面的名称、param 表示页面传递的参数。在pageMap方法中使用 if-else 语句对name 进行判断,如果 name 为DetailPage,则渲染 DetailPage 组件并传递参数 param。否则,渲染一个 Text 组件显示 404,表示页面未找到。

在build()函数中,当 Button 组件被点击时,通过 pageStack.pushPath 方法将 DetailPage页面及其参数 “详情页参数”进行入栈操作,入栈的目的地址通过navDestination 修饰器传入给导航路径栈,从而实现页面的跳转功能。

在预览器中,开发者可以点击“登录”按钮,预览和体验页面的跳转和返回交互,如图 1-13 所示。

图 1-13 页面跳转和返回


theme: smartblue

承接上一章的内容。

1.5 使用高级组件

Select(下拉选择菜单)组件常用于在多个选项之间进行选择的场景,通常以一个下拉列表的形式展示所有选项,并允许用户从中选择一个操作或者值。

创建一个名为 MySelect 的新的 HarmonyOS 项目,并打开工程开发面板。

@kit.ArkUI 模块是一个封装了 ArkUI 核心组件和功能的工具库。它提供了额外的封装、工具函数、扩展组件等,使得开发者能够更方便地使用 ArkUI 提供的功能,同时也可能包含了一些额外的优化和便捷特性。

Select 组件在使用前需要导入@kit.ArkUI 模块中的SymbolGlyphModifier 工具接口,该接口用于实现调用ArkUI 的symbolIcon组件的能力,实现对symbolIcon 的自定义和扩展。代码如下:

import { SymbolGlyphModifier } from '@kit.ArkUI'

selectOption 是Select组件的对象,用于定义下拉选择框中的单个选项,它允许开发者定义value(选项文本)、icon(选项图片)、symbolIcon(选项图标)参数来自定义选项样式。

使用interface 关键字定义一个名为 selectOption 的接口,用于描述 Select 组件中选项的数据结构。通过@State 装饰器声明一个自定义选项selectItems,用于存储所有选项数据。同时声明选项索引参数 selectIndex 和选项文字参数 selectText,表示当前选中的选项索引和文字,最后build() 函数中使用Select 组件。代码如下:

//第1章/Index.ets
interface selectOption {
  value: string
  symbolIcon: SymbolGlyphModifier
}

@Entry
@Component
struct Index {
  @State selectItems: selectOption[] = [
    { value: 'All Items', symbolIcon: new SymbolGlyphModifier($r('sys.symbol.square_grid_2x2')) },
    { value: 'Favorites', symbolIcon: new SymbolGlyphModifier($r('sys.symbol.heart')) },
    { value: 'Edited', symbolIcon: new SymbolGlyphModifier($r('sys.symbol.slider_horizontal_2')) },
    { value: 'Photos', symbolIcon: new SymbolGlyphModifier($r('sys.symbol.shutter_photo')) },
    { value: 'Videos', symbolIcon: new SymbolGlyphModifier($r('sys.symbol.play_video')) },
    { value: 'Screenshots', symbolIcon: new SymbolGlyphModifier($r('sys.symbol.circle_viewfinder')) }
  ]
  @State selectIndex: number = 0
  @State selectText: string = this.selectItems[0].value

  build() {
    Column() {
      Select(this.selectItems)
        .selected(this.selectIndex)
        .value(this.selectText)
        .onSelect((index: number, text: string) => {
          this.selectIndex = index
          this.selectText = text
        })
    }
    .width('100%')
  }
}

selectItems 选项数组中的每个选项包含value和symbolIcon,其中symbolIcon 参数的值通过创建一个新的SymbolGlyphModifier 工具类来引用系统图标资源,引用方式为$r('sys.symbol.xxx'),其中xxx为系统资源名称。将selectItems 选项数组作为参数传递给Select 组件时,Select 组件将根据selectItems 数组渲染选项列表。

使用selected 修饰器设置当前选中的索引,初始值设置为 0,表示默认选中第一个选项。使用value 修饰器设置当前选中的文本值,初始值为第一个选项的值,标识显示第一个选项的文本。使用onSelect 修饰器触发Select 组件的回调事件,在回调中,更新 selectIndex 和 selectText,从而实现状态的同步更新。

打开预览器,开发者将可以看到Select 组件的样式,点击Select 组件体验选项的展开和选择交互,如图 1-14 所示。

图 1-14 Select 组件交互体验

SegmentButton(分段按钮)组件用于展示多个选项并允许用户选择其中单个选项。创建一个名为 MySegmentButton 的新的 HarmonyOS 项目,并打开工程开发面板。

与Select 组件使用类似,SegmentButton 组件需要导入@kit.ArkUI 模块,并引入SegmentButton、SegmentButtonOptions 接口能力,代码如下:

import { SegmentButton, SegmentButtonOptions} from '@ohos.arkui.advanced.SegmentButton'

SegmentButtonOptions 是SegmentButton 组件的对象,用于定义分段选项中的单个选项,它允许开发者自定义type(选项类型)、buttons(选项按钮信息)参数来构建分段按钮的样式。

使用@State 装饰器声明一个自定义分段按钮选项tabOptions,用于存储分段按钮的所有选项。同时声明选项索引参数selectIndex,表示当前选中的选项索引,最后build 函数中使用SegmentButton 组件,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {
  @State tabOptions: SegmentButtonOptions = SegmentButtonOptions.tab({
    buttons: [{ text: 'Daily' }, { text: 'Weekly' }, { text: 'Monthly' }]
  })
  @State selectIndex: number[] = [0]

  build() {
    Flex({
      direction: FlexDirection.Row,
      justifyContent: FlexAlign.Center
    }) {
      SegmentButton({
        options: this.tabOptions,
        selectedIndexes: $selectIndex
      })
        .width('90%')
    }
    .width('100%')
    .height('100%')
  }
}

tabOptions 状态变量定义了分段按钮的选项,其内容为一个配置对象方法SegmentButtonOptions.tab,表示SegmentButton 组件显示的样式是页签类样式。buttons 数组用于构建分段按钮的选项,每一个选项包含了text 参数,表示选项显示的文本。

使用selected 修饰器设置当前选中的索引,初始值设置为 0,表示默认选中第一个选项。

在build() 函数中使用Flex组件构建弹性布局,设置Flex 组件中的 direction 参数值为FlexDirection.Row,表示当前布局方向为水平方向。设置justifyContent 参数值为FlexAlign.Center,表示Flex 组件中的子组件按照水平居中方式对齐。

SegmentButton 组件为Flex 组件的子组件,将tabOptions绑定SegmentButton 组件的选项配置,并将selectIndex 绑定当前选中的索引selectedIndexes。值得注意的selectedIndexes 参数使用@Link 作为其类型,因此需要使用$进行参数绑定。

在设置SegmentButton 组件和Flex 组件的宽高后,打开预览器,点击SegmentButton 组件选项来体验分段选择的交互,如图 1-15 所示。

图 1-15 SegmentButton 组件交互体验

Counter(计数器)组件常用于电商应用中精确调整数量的场景,通常以“-”和“+”按钮来实现数量的快速增加或减少。

创建一个名为 MyCounter 的新的 HarmonyOS 项目,并打开工程开发面板。

Counter 组件需要导入@kit.ArkUI 模块,并引入CounterType、CounterComponent、CounterOptions接口能力,代码如下:

import {CounterType, CounterComponent, CounterOptions} from '@ohos.arkui.advanced.Counter'

CounterType 用于定义计数器的类型,允许开发者设置LIST(列表型)、COMPACT(紧凑型)、INLINE(普通数字内联调节型)、INLINE_DATE(日期型内联型)4 种类型。CounterComponent 用于定义计数器组件样式,CounterOptions 用于设置计数器的参数。

使用@State 装饰器定义计数器参数counterOptions,并在 build() 函数中使用CounterComponent 创建计数器,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {
  @State counterOptions: CounterOptions = {
    type: CounterType.LIST,
    numberOptions: { label: '数量', min: 0, value: 1, max: 99, }
  }

  build() {
    Column(){
      CounterComponent({ options: this.counterOptions})
        .margin(20)
    }
    .height('100%')
    .width('100%')
  }
}

counterOptions 状态变量定义了计数器的样式和参数,它包含 2 个参数type(计数器类型)和numberOptions(计数器参数)。设置计数器类型为CounterType.LIST,表示该计数器为列表型计数器。设置计数器显示的文本为“数量”,最小值为 0,默认值为 1,最大值为 90。

将counterOptions 状态变量传入给CounterComponent 组件后,打开预览器,点击计数器的“-”和“+”按钮,体验计数器的计数功能和交互,如图 1-16 所示。

图 1-16 CounterComponent组件交互体验

1.6 自定义样式

ArkUI 提供了许多组件的修饰器供开发者使用,例如width、backgroundColor、onClick 修饰器,除此之外,ArkUI 还允许开发者将多个修饰器设置为一个可复用的自定义样式,来提高代码的简洁性和可维护性。

创建一个名为 MyStyles 的新的 HarmonyOS 项目,并打开工程开发面板。

@Styles 装饰器用于创建自定义样式方法,使用范围目前仅限于通用组件修饰器和通用交互事件。使用@Styles 装饰器声明一个自定义方法 customButtonStyle(),在 build() 函数中将其设置在 Button 组件上,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {

  @Styles customButtonStyle() {
    .size({width:120,height:40})
    .foregroundColor('#333333')
    .padding(10)
    .backgroundColor('#F5F5F5')
    .border({ radius:16, width:1, color:'D5D5D5' })
    .onClick(() => {
      console.log('Button onClick')
    })
  }

  build() {
    Column({space:20}){
      Button('Submit')
        .customButtonStyle()
      Button('Cancel')
        .customButtonStyle()
    }
    .height('100%')
    .width('100%')
  }
}

customButtonStyle() 方法中包含size、foregroundColor、padding、backgroundColor、border、onClick 修饰器,其中size 修饰器允许开发者设置组件的尺寸,参数包含width 和height。border 修饰器用于设置组件的边框,开发者可以设置边框的圆角、边框宽度、边框颜色等等。

将customButtonStyle() 方法作用到Button 组件时,customButtonStyle() 方法中的所有修饰器都会传递给Button 组件,从而实现代码的可复用性,减少重复代码的编写。

打开预览器,查看 Button 组件在customButtonStyle() 方法的作用下的显示效果,如图 1-17 所示。

图 1-17 自定义样式效果

1.7 自定义组件

当某一个组件需要被重复使用时,ArkUI 建议开发者构建自定义组件,在提高代码可复用性的同时,让代码结构更加清晰。

创建一个名为 MyComponent 的新的 HarmonyOS 项目,并打开工程开发面板。

@Component 装饰器用于构建自定义组件,开发者可以将重复的元素或功能抽象为一个自定义组件,然后在项目中使用自定义组件来提高代码的可配置性和保持代码整洁。通过@Component 装饰器声明一个自定义组件ListItemView,并完善自定义组件的 UI,代码如下:

//第1章/Index.ets
@Component
struct ListItemView {
  @Prop index: number
  @Prop name: string
  @Prop score: number

  build() {
    Row({space:20}){
      Text(`${this.index}`)
        .font({size:14,weight:600})
        .fontColor(Color.Blue)
      Text(this.name)
        .font({size:17,weight:600})
        .fontColor(Color.Black)
      Blank()
      Text(`分数: ${this.score}`)
        .font({size:14,weight:600})
        .fontColor(Color.Gray)
    }
    .width('90%')
    .border({ color: Color.Gray, width: 1,radius:8 })
    .padding(15)
    .backgroundColor('#F5F5F5')
  }
}

ListItemView 组件的作用是渲染一个列表页的单个列表项,列表项中包含index(排名)、name(用户名)、score(分数)3 项内容。@Prop 装饰器用于定义组件内的属性,并实现从父组件传递参数值给子组件。

build() 函数中实现了一个水平布局的 UI,Text 组件用于显示文字,可使用模版字符串语法来传递非字符串类型的参数值。模板字符串使用反引号(`)”而不是单引号(')或双引号(")来包裹字符串内容,并通过(${})来嵌入变量。Blank(空白填充)组件用于在布局中添加空白区域,起到分隔的作用。

通过修饰器完善ListItemView 组件的 UI 后,开发者可以在 Index 组件中尝试使用ListItemView 组件来显示一个列表视图,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {

  build() {
    Column({space:10}){
      ListItemView({index:1,name:'Ricardo',score:100})
      ListItemView({index:2,name:'Alice',score:98})
      ListItemView({index:3,name:'Bob',score:95})
      ListItemView({index:4,name:'Charlie',score:88})
      ListItemView({index:5,name:'David',score:85})
    }
    .height('100%')
    .width('100%')
  }
}

ListItemView 组件可在 Index 组件中重复使用,通过给ListItemView 组件的参数传入不同的值,在预览器中可以查看ListItemView 组件的渲染效果,如图 1-18 所示。

图 1-18 ListItemView 组件渲染效果

1.8 HarmonyOS Symbol

HarmonyOS Symbol 库是一个官方提供的用于显示图标或符号的图标库,拥有超过 400 个免费使用的精致图标,图标数量在每年进行更新和增加。开发者可访问官方链接地址查看和使用HarmonyOS Symbol 库,链接地址: developer.huawei.com/consumer/cn…

创建一个名为 MySymbol 的新的 HarmonyOS 项目,并打开工程开发面板。

SymbolGlyph(图标符号)组件用于显示HarmonyOS Symbol 库的资源,且仅支持系统预置的symbol资源名。SymbolGlyph 组件使用$r('sys.symbol.xxx') 语法引用系统资源,其中xxx 为symbol资源名。

在 Index 组件中通过@Builder装饰器声明一个自定义函数settingItem(),设置settingItem 函数传入的参数,并在settingItem() 函数中实现 UI 样式,代码如下:

//第1章/Index.ets
@Entry
@Component
struct Index {

  @Builder settingItem(icon:string,title:string,color:string) {
    Row({space:10}){
      SymbolGlyph($r(`sys.symbol.${icon}`))
        .fontColor([color])
      Text(title)
        .fontColor(color)
      Blank()
    }.width('90%')
  }

  build() {
    Column({space:20}) {
      this.settingItem('moon_circle_fill','主题切换','#8A2BE2')
      this.settingItem('bell_fill','通知设置','#FF8C00')
      this.settingItem('checkmark_shield_fill','隐私设置','#00008B')
      this.settingItem('externaldrive_fill','数据管理','#00BFFF')
      this.settingItem('lock_fill','安全设置','#32CD32')
    }
    .height('100%')
    .width('100%')
  }
}

@Builder 装饰器是 ArkUI 提供的一种轻量的UI元素复用机制,用于构建自定义的组件或样式。settingItem() 函数通过@Builder 装饰器定义了一个可复用的组件模板,用于生成具有特定图标的设置项。

settingItem() 函数接收 3 个参数icon(图标资源)、title(文字标题)、color(十六进制颜色值)来动态渲染样式。其中SymbolGlyph 组件用于显示系统图标,通过$接口动态绑定icon 参数,Text 组件和Blank 组件用于显示文本内容及填充空白空间。

在build() 函数中,通过多次调用settingItem() 函数,并传入不同的参数,来生成多个具有不同样式和内容的设置项。打开预览器,预览自定义函数settingItem() 渲染效果,如图 1-19 所示。

图 1-19 settingItem 函数渲染效果

1.9 本章小结

ArkUI 提供了海量的基础组件和高级组件供开发者使用,覆盖多个行业使用场景。在官方提供的开发文档中,开发者可以查询和预览组件的详细属性、方法以及使用示例。这些文档不仅涵盖了组件的基本用法,还提供了丰富的代码示例和交互效果预览,帮助开发者快速理解和掌握组件的使用方式。

本章没有涵盖所有组件的使用,旨在通过组件的使用案例来帮助开发者接触 ArkUI的核心概念和开发流程。通过本章的示例代码,读者可以快速了解如何将基础组件和高级组件组合成实际可用的界面,并掌握如何通过 ArkUI 的灵活布局和样式系统实现高效的 UI 设计。

在后续的章节中我们将逐步深入探讨更多组件的用法和使用场景,展示 ArkUI 的强大功能和灵活的开发模式。请读者保持好奇心和探索精神,跟随本书的步伐,逐步解锁 ArkUI 的更多可能性。