HarmonyOS UI框架提供了用于创建用户界面的各类组件,包括一些常用的组件和常用的布局。用户可通过组件进行交互操作,并获得响应。 HarmonyOS可通过包括Java、JS和ArkTS等多种语言来实现UI的开发。本章重点介绍以ArkTS语言为核心的ArkUI框架的使用。 由于UI开发涉及的组件较多,本书将分两章来讲述,本章介绍常用的组件和基础组件,下一章继续介绍其他相关组件。
3.1 ArkUI概述
ArkUI(方舟开发框架)是一套构建HarmonyOS应用界面的UI开发框架,它提供了极简的UI语法与包括UI组件、动画机制、事件交互等在内的UI开发基础设施,以满足应用开发者的可视化界面开发需求。
3.1.1 ArkUI的基本概念
ArkUI的基本概念分为以下两部分: 1.组件:组件是界面搭建与显示的最小单位。开发者通过多种组件的组合构建出满足自身应用诉求的完整界面。 2.页面:Page页面是ArkUI最小的调度分隔单位。开发者可以将应用设计为多个功能页面,每个页面进行单独的文件管理,并通过页面路由API完成页面间的调度管理,以实现应用内功能的解耦。
我们以2.4节中的Index.ets代码为例
//导入模块
import router from '@ohos.router';
import url from '@ohos.url';@Entry
@Component
struct Index {@State message: string = 'Index页面'build() {Row() {Column() {Text(this.message).fontSize(50).fontWeight(FontWeight.Bold)//添加按钮,触发跳转Button("跳转").fontSize(40).onClick(()=>{router.pushUrl({url:'pages/Second',params:{src:"Index页面传来的数据",}})})}.width('100%')}.height('100%')}
}
代码中,Index和Second就是页面,而Row、Column、Text、Button等都是ArkUI的组件。 Index和Second这两个页面是通过页面路由API完成页面间的调度管理的,以实现应用内功能的解耦。
3.1.2 ArkUI的主要特征
UI组件:ArkUI内置了丰富的多态组件,包括Image、Text、Button等基础组件,可包含一个或多个子组件容器组件、满足开发者自定义绘图需求的绘制组件以及提供视频播放能力的媒体组件等。其中“多态”是指组件针对不同类型设备进行了设计,提供了在不同平台上的样式适配能力。同时,ArkUI也支持用户自定义组件。 布局:UI界面设计离不开布局的参与。ArkUI提供了多种布局方式,不仅保留了经典的弹性布局能力,还提供了列表、宫格、栅格布局和适应多分辨率场景开发的原子布局能力。 动画:ArkUI对于UI界面的美化,除组件内置动画效果外,还提供了属性动画、转场动画和自定义动画能力。 绘制:ArkUI提供了多种绘制能力,以满足开发者的自定义绘图需求,支持绘制形状、颜色填充、绘制文本、变形与裁剪、嵌入图片等。 交互事件:ArkUI提供了多种交互能力,以满足应用在不同平台通过不同输入设备进行UI交互响应的需求,默认适配触摸手势、遥控器按键输入、键鼠输入,同时提供了相应的事件回调以便开发者添加交互逻辑。 平台API通道:ArkUI提供了API扩展机制,可通过该机制对平台能力进行封装,提供风格统一的JS接口。 两种开发范式:ArkUI针对不同的应用场景以及不同技术背景的开发者提供了两种开发范式,分别是基于ArkTS的声明式开发范式(简称声明式开发范式)和兼容JS的类Web开发范式(简称类Web开发范式)。
3.1.3 JS、TS、ArkTS、ArkUI和ArkCompiler之间的联系
JS(JavaScript的简写),TS(TypeScript的简写)和ArkTS都是开发语言,其中,TS是JS的超集,而ArkTS在TS的基础上扩展了声明式UI,状态管理等相应的能力,让开发者能够以更简介,更自然的方式开发高性能应用。ArkTS会结合应用开发和运行的需求持续演进,包括但不限于引入分布式开发范式,并行和并发能力增强,类型系统增强等方面的语言特性。因此,三者的关系如图所示。
ArkUI是一套构建分布式应用界面的声明式UI开发框架。它使用极简的UI信息语法,丰富的UI组件以及实时界面预览工具,帮助开发者提升HarmonyOS应用界面开发效率的30%。只需使用一套ArkTS API,就能在多个HarmonyOS设备上提供生动而流畅的用户界面体验。
ArkCompiler(方舟编译器)是虎蛾为自研的统一编程平台,包含编译器,工具链,运行时等关键部件,支持高级语言在多种芯片平台的编译与运行,并支撑应用和服务运行在手机,个人计算机,平板电脑,电视,汽车和智能穿戴设备等多种设备上。ArkCompiler会把ArkTS,TS,JS编译为方舟字节码,运行时直接运行方舟字节码。同时,ArkCompiler使用多种混淆技术提供更高强度的混淆与保护,使得HarmonyOS应用包中装在的时多重混淆的字节码。ArkCompiler框架结构如图所示。
3.2 声明式开发范式
ArkUI是一套开发极简、高性能、跨设备应用的UI开发框架,支持开发者高效地构建跨设备应用UI界面。
3.2.1 声明式开发范式与类Web开发范式
声明式开发范式是采用基于TypeScript的声明式UI语法扩展而来的ArkTS语言,从组件、动画和状态管理3个维度提供了UI绘制能力。声明式开发范式更接近自然语义的编程方式,让开发者更直观地描述UI界面,不必关心框架如何实现UI绘制和渲染,实现极简高效开发。因此,声明式开发范式适合复杂度较大、团队合作度较高的程序。 类Web开发范式采用经典的HTML、CSS、JavaScript三段式开发方式,使用HTML标签文件进行布局搭建,使用CSS文件进行样式描述,使用JavaScript文件进行逻辑处理。UI组件与数据之间通过单向数据绑定的方式建立关联,当数据发生变化时,UI界面自动触发刷新。该开发方式更接近Web前端开发者的使用习惯,便于快速将已有的Web应用改造成ArkUI应用。因此,类Web开发范式适合界面较简单的中小型应用和卡片。
3.2.2 声明式开发范式的基础能力
声明式开发范式的开发框架不仅从组件,动效和状态管理3个维度来提供UI能力,还提供了系统能力接口,以实现系统能力的极简调用。
声明式开发范式具备以下基础能力:
开箱即用的组件:框架提供丰富的系统预置组件,可以通过链式调用的方式设置系统组件的渲染效果。开发者可以组合系统组件为自定义组件,通过这种方式将页面组件为一个个独立的UI单位,以实现也买你不同单元的独立创建,开发和复用,使页面具有更强的工程性。
丰富的动效接口:提供SVG标准的绘制图形能力,同时开放了丰富的动效接口,开发者可以通过封装的物理模式或者调用动画能力接口实现自定义动画轨迹。
状态数据管理:状态数据管理作为基于ArkTS的声明式开发范式的特色,通过功能不同的装饰器为开发者提供了清晰的页面更新渲染流和管道。状态管理包括UI组件状态和应用程序状态,两者协作可以使开发者完整的构建整个应用的数据更新和UI渲染。
系统能力接口:ArkUI还封装了丰富的系统能力接口,开发者可以通过简单的接口调用实现从UI设计到系统能力调用的极简开发。
3.2.3 声明式开发范式的整体架构
详细说明如下。
声明式UI前端:提供了UI开发范式的基础语言规范,并提供内置的UI组件,布局和动画,还提供了多种状态管理机制,为应用开发者提供一系列接口支持。
语言运行时:选用方舟语言运行时,提供了针对UI范式语法的解析能力,跨语言调用支持的能力和TS语言高性能运行环境。
声明式UI后端引擎:后端引擎提供了兼容不同开发范式的UI渲染管线,提供多种基础组件,布局计算,动效,交互事件,提供了状态管理和绘制能力。
渲染引擎:提供了高效的绘制能力,将渲染管线收集指令绘制到屏幕上的能力。
平台适配层:提供了对系统平台的抽象接口,具备接入不同系统的能力,如系统渲染管线,生命周期调度等。
3.2.4 声明式开发范式的基本组成
详细说明如下。
装饰器:用来装饰类,结构体,方法以及变量,赋予其特殊的含义,图中的@Entry,@Component,@State都是装饰器。具体而言,@Component表示这是一个自定义组件;@Entry表示这是一个入口组件;@State表示组件中的状态变量,此状态变化会引起UI变更。
自定义组件:可复用的UI单元,可组合其他组件,图中被@Component装饰的struct Hello。
UI描述:以声明式的方式来描述UI的结构,如上述build()方法内部的代码块。
内部组件:构架中默认内置的基础和布局组件,可直接被开发者调用,比如示例中的Column,Text,Divider,Button。
事件方法:用于添加组件对事件的响应逻辑,统一通过事件方法进行设置,如跟随在Button后面的onClick()。
属性方法:用于组件属性的配置,统一通过属性方法进行设置,如fontSize(),width(),height(),color()等,可通过链式调用的方式设置多项属性。
3.3 常用的组件
基础组件:Blank、Button、Checkbox、CheckboxGroup、DataPanel、DatePicker、Divider、Gauge、Image、ImageAnimator、LoadingProgress、Marquee、Navigation、PatternLock、Progress、QRCode、Radio、Rating、RichText、ScrollBar、Search、Select、Slider、Span、Stepper、StepperItem、Text、TextArea、TextClock、TextInput、TextPicker、TextTimer、TimePicker、Toggle、Web、XComponent。 容器组件:AlphabetIndexer、Badge、Column、ColumnSplit、Counter、Flex、GridContainer、GridCol、GridRow、Grid、GridItem、List、ListItem、Navigator、Panel、Refresh、RelativeContainer、Row、RowSplit、Scroll、SideBarContainer、Stack、Swiper、Tabs、TabContent。 媒体组件:Video。 绘制组件:Circle、Ellipse、Line、Polyline、Polygon、Path、Rect、Shape。 画布组件:Canvas。
3.4 基础组件详解
本节演示如何使用基础组件。
3.4.1 Blank
Blank是空白填充组件,在容器主轴方向上,空白填充组件具有自动填充容器空余部分的能力。 需要注意的是,Blank组件仅当其父组件为Row/Column,且父组件设置了宽度才生效。 以下示例展示Blank父组件Row未设置宽度以及设置了宽度的效果对比。
@Entry
@Component
struct Index {@State message: string = 'Hello World'build() {Row() {Text('左边').fontSize(50).fontWeight(FontWeight.Bold)//内容之外的空白由此控件填充Blank()Text('右边').fontSize(50).fontWeight(FontWeight.Bold)}.width('100%')}
}
第一行Row由于未设置宽度,导致Blank未生效。
Blank组件也是支持颜色的,可以给空白组件设置颜色,其代码方式如下:
Blank().color(Color.Red)
3.4.2 Button
Button是按钮组件,可快速创建不同样式的按钮。
@Entry
@Component
struct Two {@State message: string = 'Hello World'build() {Column() {Row() {//一个基本的按钮,设置要显示的文字Button('01').width(60)//设置变量的半径,背景色和宽度的按钮Button('02').borderRadius(8).backgroundColor(Color.Red).width(90)}.width('100%')}.width('100%')}
}
Button组件支持通过type属性来设置按钮显示样式。示例如下:
@Entry
@Component
struct Two {@State message: string = 'Hello World'build() {Column() {//第一行Row() {//一个基本的按钮,设置要显示的文字Button('01').width(60)//设置变量的半径,背景色和宽度的按钮Button('02').borderRadius(8).backgroundColor(Color.Red).width(90)}.width('100%')//第二行Row(){//胶囊型按钮(圆角默认为高度的一半)Button('03',{type:ButtonType.Capsule}).width(90)//圆形按钮Button('04',{type:ButtonType.Circle}).width(90)//普通按钮(默认不带圆角)Button('05',{type:ButtonType.Normal}).width(90)}.width('100%')}.width('100%').height('100%')}
}
Button组件支持包含子组件,示例如下:
//第三行Row(){//带子组件的按钮Button({type:ButtonType.Normal}){//圆形加载进度条LoadingProgress().width(40).height(40).color(0xFFFFFF)}.width(90)}.width("100%")
这里需要注意,如果在按钮中嵌套其他的组件,那么该按钮就不能在用以前的方式添加文字。
在这里添加文本的组件时Text,后面会详细讲解,在这里需要在按钮上既显示圆形加载进度条又要显示文字,也就意味着按钮内需要加入两个组件,这里是不允许的,按钮内部只能加入一个组件,我们可以将LoadingProgress组件和Text组件套在一个容器组件中,这样按钮内部就只有一个容器组件,容器组件中有多少组件和按钮无关。
//第三行Row(){//带子组件的按钮Button({type:ButtonType.Normal}){//圆形加载进度条LoadingProgress().width(40).height(40).color(0xFFFFFF)}.width(90)//带多个子组件需要套在一个容器中,这里使用横向线性容器Button({type:ButtonType.Capsule}){Row(){LoadingProgress().width(40).height(40).color(0xFF0000)Text('06').fontSize(40).fontColor(Color.Yellow)}.width(100)}}.width("100%")
3.4.3 Checkbox
Checkbox是多选框组件,通常用于某选项的打开或关闭,示例如下:
//第四行Row(){//设置多选框名称、多选框的群组名称Checkbox({ name: 'checkbox1', group: 'checkboxGroup' }).select(true) //设置默认选中.selectedColor(0xed6f21) //设置选中颜色.onChange((value: boolean) => { //设置选中事件console.info('Checkbox1 change is ' + value)})Checkbox({ name: 'checkbox2', group: 'checkboxGroup' }).select(false).selectedColor(0x39a2db).onChange((value: boolean) => {console.info('Checkbox2 change is ' + value)})}.width('100%')
3.4.4 CheckboxGroup
CheckboxGroup是多选框群组,用于控制多选框全选或者不全选状态,示例如下:
//第五行Row(){Column(){Row() {CheckboxGroup({ group: 'checkboxGroup1' })Text('全要').fontSize(20)}Row() {Checkbox({ name: 'checkbox1', group: 'checkboxGroup1' })Text('可乐').fontSize(20)}Row() {Checkbox({ name: 'checkbox2', group: 'checkboxGroup1' })Text('鸡翅').fontSize(20)}}.width('100%')}.width('100%')
3.4.5 DataPanel
DataPanel是数据面板组件,用于将多个数据占比情况使用占比图进行展示。DataPanel主要支持两类数据面板: Line:线形数据面板。 Circle:环形数据面板。
DataPanel示例如下:
@Entry
@Component
struct Three {private dataPanelValues: number[] = [11, 3, 10, 2, 36, 4, 7, 22, 5]build() {Column() {//环形数据面板DataPanel({ values: this.dataPanelValues,max: 100, type: DataPanelType.Circle}).width(350).height(350)//线形数据面板DataPanel({ values: this.dataPanelValues, max: 100, type: DataPanelType.Line}).width(350).height(50)}.height('100%')}
}
上述示例中,DataPanel主要有3个参数,其中values是数据值列表,最大支持9个数据,max表示数据的最大值;type就是类型。
3.4.6 DatePicker
DatePicker是选择日期的滑动选择器组件。以下是一个DatePicker的基本示例:
@Entry
@Component
struct Four {build() {Row() {Column() {DatePicker({start: new Date('1970-1-1'), //指定选择器的起始日期。 默认值为Date('1970-1-1')end: new Date('2100-1-1'), //指定选择器的结束日期。 默认值为Date('2100-12-31')selected: new Date(), //设置指定的日期。默认值为当前系统日期})}.width('100%')}.height('100%')}
}
上述示例中,DatePicker主要有3个参数,其中start用于指定选择器的起始日期,end用于指定选择器的结束日期,selected用于设置选中项的日期。如果3个参数都不设置,就使用默认值。
DatePicker支持农历。可以通过设置lunar属性来设置日期是否显示农历。其中: true:展示农历。 false:不展示农历。默认值为false。 DatePicker在选择日期时会触发onChange事件,以下是示例:
@Entry
@Component
struct Four {build() {Row() {Column() {DatePicker({start: new Date('1970-1-1'), //指定选择器的起始日期。 默认值为Date('1970-1-1')end: new Date('2100-1-1'), //指定选择器的结束日期。 默认值为Date('2100-12-31')selected: new Date(), //设置指定的日期。默认值为当前系统日期}).lunar(true).onChange((value: DatePickerResult) => { //选择日期时触发该事件console.info('select current date is: ' + JSON.stringify(value))})}.width('100%')}.height('100%')}
}
上述示例中,DatePicker设置了农历,同时监听onChange事件。
3.4.7 Divider
Divider是分隔器组件,用于分隔不同内容块/内容元素。以下是示例:
@Entry
@Component
struct Five {build() {Row() {Column() {Text('我是白云').fontSize(29)Divider().color(Color.Red)//分割线设置颜色.strokeWidth(10)//设置分割线粗细Text('我是大地').fontSize(29)Divider().color(Color.Blue)//分割线设置颜色.strokeWidth(5)//设置分割线粗细Text('我是黑土').fontSize(29)}.width('100%')}.height('100%')}
}
上述代码中,Divider在两个Text组件之间形成了一条水平分割线,并设置其颜色和粗细,默认颜色为黑色,粗细为1个像素。还可以设置分割线为垂直摆放,默认情况下,Divider是水平的,但也可以通过vertical属性来设置为垂直。以下是示例:
Text('我是大地').fontSize(29)Divider().color(Color.Blue)//分割线设置颜色.strokeWidth(5)//设置分割线粗细.vertical(true)//设置分割线垂直摆放.height(100)//设置分割线高度Text('我是黑土').fontSize(29)
Divider还可以通过以下属性来设置样式。 color:分隔线颜色。 strokeWidth:分隔线宽度。默认值为1。 lineCap:分隔线的端点样式。默认值为LineCapStyle.Butt。 以下是设置了样式的Divider示例:
@Entry
@Component
struct Five {build() {Row() {Column() {Text('我是白云').fontSize(29)Divider().color(Color.Red)//分割线设置颜色.strokeWidth(10)//设置分割线粗细.width("90%").lineCap(LineCapStyle.Round)//设置线条端点样式Text('我是大地').fontSize(29)Divider().color(Color.Blue)//分割线设置颜色.strokeWidth(5)//设置分割线粗细.vertical(true)//设置分割线垂直摆放.height(100)//设置分割线高度Text('我是黑土').fontSize(29)}.width('100%')}.height('100%')}
}
3.4.8 Gauge
Gauge是一种数据量规图表组件,用于将数据展示为环形图表。以下是Gauge示例:
@Entry
@Component
struct Six {@State message: string = 'Hello World'build() {Row() {Column() {//value值的设置,使用默认的min和max为0和100,角度范围默认为0~360//参数中设置当前值为75Gauge({ value: 75 }).width(200).height(200)//设置量规图的颜色,支持分段颜色设置.colors([[0x317AF7, 1], [0x5BA854, 1], [0xE08C3A, 1], [0x9C554B, 1]])}.width('100%')}.height('100%')}
}
上述示例中,colors是一个颜色数组,表示该量规图由4段颜色组成,参数value是量规图的当前数据值,既图中指针指向的位置如上图所示。
上述value值也可以在属性中进行设置。如果属性和参数都设置,以参数为准。
//参数设置当前值为75,属性设置值为25,属性设置优先级高Gauge({ value: 75 }).value(25) //属性和参数都设置时以属性为准.width(200).height(200).colors([[0x317AF7, 1], [0x5BA854, 1], [0xE08C3A, 1], [0x9C554B, 1]])
上述示例中,参数设置当前值为75,属性设置值为25,属性设置优先级高。
Gauge组件还有其他的一些属性设置,分别说明如下。 startAngle:设置起始角度位置,时钟0点为0度,顺时针方向为正角度。默认值为0。 endAngle:设置终止角度位置,时钟0点为0度,顺时针方向为正角度。默认值为360。 strokeWidth:设置环形量规图的环形厚度。 以下是一个设置了210~150度、厚度为20的Gauge示例:
//210~150度环形图表Gauge({ value: 70}).startAngle(210) //起始角度.endAngle(150) //终止角度.colors([[0x317AF7, 0.1], [0x5BA854, 0.2], [0xE08C3A, 0.3], [0x9C554B, 0.4]]).strokeWidth(20) //环形厚度.width(200).height(200)
3.4.9 Image
Image是图片组件,支持本地图片和网络图片的渲染展示。以下是Image组件使用本地图片的示例:
//使用本地图片的示例//图片资源在base/media目录下Image($r('app.media.cookie2')).width('100%').height('50%')
以下展示Image采用网络图片的过程。
首先,在module.json5文件中声明使用网络的权限ohos.permission.INTERNET,示例如下:
{"module": {...//允许该应该访问网络资源"requestPermissions": [{"name": "ohos.permission.INTERNET"}]
}
其次,编写请求网络图片,方法如下:
//先创建一个PixelMap状态变量用于接收网络图片@State imagePixelMap: PixelMap = undefined//网络图片请求方法private httpRequest() {let httpRequest = http.createHttp();httpRequest.request("https://ww2.sinaimg.cn/mw690/9b4973cbgy1hrin2to044j20u00zwn62.jpg", //网络图片地址(error, data) => {if(error) {console.log("error code: " + error.code + ", msg: " + error.message)} else {let code = data.responseCodeif(http.ResponseCode.OK == code) {//@ts-ignorelet imageSource = imageModule.createImageSource(data.result)let options = {alphaType: 0, //透明度editable: false, //是否可编辑pixelFormat: 3, //像素格式scaleMode: 1, //缩略值size: {height: 281, width: 207}} //创建图片大小imageSource.createPixelMap(options).then((pixelMap) => {this.imagePixelMap = pixelMap})} else {console.log("response code: " + code);}}})}
最后,将imagePixelMap复制到Image组件中即可,代码如下:
build() {Row() {Column() {//使用网络图片的示例Button("获取网络图片").onClick(() => {//请求网络资源this.httpRequest();})Image(this.imagePixelMap).width('90%').height('80%')}.width('100%')}.height('100%')}
接着将EntryAbility的启动项由Index改为当前page的名称,然后启动模拟器,点击按钮,则可以看到效果。
3.4.10 ImageAnimator
ImageAnimator提供帧动画组件来实现逐帧播放图片的能力,可以配置需要播放的图片列表,每幅图片可以配置时长。示例代码:
@Entry
@Component
struct Seven {@State animationStatus:number=NaNbuild() {Row() {Column() {//按钮控制动画的播放和暂停Button('播放').width(100).padding(5).onClick(() => {this.animationStatus = AnimationStatus.Running}).margin(5)Button('暂停').width(100).padding(5).onClick(() => {this.animationStatus = AnimationStatus.Paused}).margin(5)//images设置图片帧信息集合//每一帧的帧信息(ImageFrameInfo)包含图片路径、图片大小、图片位置和图片播放时长信息ImageAnimator().images([{src: $r('app.media.cookie1'), //图片路径duration: 500, //播放时长width: 240, //图片大小height: 350,top: 0, //图片位置left: 0},{src: $r('app.media.cookie2'),duration: 500,width: 240,height: 350,top: 0,left: 170},{src: $r('app.media.cookie3'),duration: 500,width: 240,height: 350,top: 120,left: 170},{src: $r('app.media.cookie4'),duration: 500,width: 240,height: 350,top: 120,left: 0}]).state(this.animationStatus).reverse(false) //是否逆序播放.fixedSize(false) //是否固定大小.preDecode(2) //是否启用预解码.iterations(-1) //循环播放次数.width(240).height(350).margin({ top: 100 })}.width('100%')}.height('100%')}
}
3.4.11 LoadingProgress
LoadingProgress是用于显示加载动效的组件。示例代码如下:
//显示加载动效LoadingProgress().color(Color.Red) //设置为红色
3.4.12 Marquee
Marquee是跑马灯组件,用于滚动展示一段单行文本,仅当文本内容宽度超过跑马灯组件宽度时滚动。示例代码如下:
//文本内容宽度未超过跑马灯组件宽度,不滚动Marquee({start: true, //控制跑马灯是否进入播放状态step: 12, //滚动动画文本的滚动步长。默认值为6,单位为vploop: -1, //循环次数,-1为无限循环fromStart: true, //设置文本从头开始滚动或反向滚动src: "HarmonyOS也称为鸿蒙系统"}).fontSize(20)//文本内容宽度超过了跑马灯组件宽度,滚动Marquee({start: true, //控制跑马灯是否进入播放状态step: 12, //滚动动画文本的滚动步长。默认值为6,单位为vploop: -1, //循环次数,-1为无限循环fromStart: true, //设置文本从头开始滚动或反向滚动src: "在传统的单设备系统能力基础上,HarmonyOS提出了基于同一套系统能力、适配多种终端形态的分布式理念。"}).fontSize(20)
3.4.13 Navigation
Navigation组件一般作为Page页面的根容器,通过属性设置来展示页面的标题、工具栏、菜单。 示例代码:
@Entry
@Component
struct Nine {//自定义一个Toolbar组件@Builder NavigationToolbar() {Row() {Text("首页").fontSize(25).margin({ left: 70 })Text("+").fontSize(25).margin({ left: 70 })Text("我").fontSize(25).margin({ left: 70 })}}build() {Row() {Column() {//Navigation使用自定义的NavigationToolbar组件Navigation() {Flex() {}}.toolBar(this.NavigationToolbar) //自定义一个Toolbar组件}.width('100%')}.height('100%')}
}
3.4.14 PatternLock
PatternLock是图案密码锁组件,以九宫格图案的方式输入密码,用于密码验证场景。手指在PatternLock组件区域按下时开始进入输入状态,手指离开屏幕时结束输入状态完成密码输入。
@Entry
@Component
struct Ten {build() {Row() {Column() {PatternLock().sideLength(300) //设置组件的宽度和高度(宽高相同).circleRadius(9) //设置宫格中圆点的半径.pathStrokeWidth(18) //设置连线的宽度。设置为0或负数等非法值时连线不显示.activeColor('#B0C4DE') //设置宫格圆点在“激活”状态的填充颜色.selectedColor('#228B22') //设置宫格圆点在“选中”状态的填充颜色.pathColor('#90EE90') //设置连线的颜色.backgroundColor('#F5F5F5') //背景颜色.autoReset(true) //设置在完成密码输入后,再次在组件区域按下时是否重置组件状态}.width('100%')}.height('100%')}
}
3.4.15 Progress
Progress进度条组件用于显示内容加载或操作处理等进度。 Progress主要有以下参数。 value:指定当前进度值。 total:指定进度总长。 type:指定进度条类型ProgressType。 其中,ProgressType主要有以下5种。 Linear:线性样式。 Ring:环形无刻度样式,环形圆环逐渐显示至完全填充效果。 Eclipse:圆形样式,显示类似于月圆月缺的进度展示效果,从月牙逐渐变化至满月。 ScaleRing:环形有刻度样式,显示类似时钟刻度形式的进度展示效果。 Capsule:胶囊样式,头尾两端圆弧处的进度展示效果与Eclipse相同,中段处的进度展示效果与Linear相同。
以下是5种ProgressType的具体示例:
@Entry
@Component
struct A1 {@State message: string = 'Hello World'build() {Row() {Column() {Progress({ value: 20, total: 100, type: ProgressType.Linear }).width(150).margin({ top: 10 })Progress({ value: 20, total: 100, type: ProgressType.Ring }).width(150).margin({ top: 10 })Progress({ value: 20, total: 100, type: ProgressType.Eclipse }).width(150).margin({ top: 10})Progress({ value: 20, total: 100, type: ProgressType.ScaleRing }).width(150).margin({ top: 10})Progress({ value: 20, total: 100, type: ProgressType.Capsule }).width(40).margin({ top: 10 })}.width('100%')}.height('100%')}
}
3.4.16 QRCode
QRCode是用于显示单个二维码的组件。以下是赋了黄码的具体示例:
@Entry
@Component
struct A2 {build() {Row() {Column() {//华为鸿蒙开发者API文档网址QRCode("https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/start-overview-0000001478061421-V2").width(300).height(300) //大小.backgroundColor(Color.Orange) //颜色}.width('100%')}.height('100%')}
}
3.4.17 Radio
Radio是单选框,提供相应的用户交互选择项。当前单选框所属的群组名称,相同group的Radio只能有一个 被选中。以下是一组Radio的具体示例:
@Entry
@Component
struct A3 {build() {Row() {Column() {Radio({ value: 'Radio1', group: 'radioGroup' }).checked(false) //默认不选中.height(50).width(50)Radio({ value: 'Radio2', group: 'radioGroup' }).checked(true) //默认选中.height(50).width(50)Radio({ value: 'Radio2', group: 'radioGroup' }).checked(false) //默认不选中.height(50).width(50)}.width('100%')}.height('100%')}
}
3.4.18 Rating
Rating是提供在给定范围内选择评分的组件。以下是一组Rating的具体示例:
@Entry
@Component
struct A3 {build() {Row() {Column() {//设置初始星数为1,可以操作Rating({ rating: 1, indicator: false }).stars(5) //设置评星总数。默认值为5.stepSize(0.5) //操作评级的步长。默认值为0.5.onChange((value: number) => {console.log('aaa',value)})}.width('100%')}.height('100%')}
}
3.4.19 RichText
RichText是富文本组件,可以解析并显示HTML格式文本。示例如下:
@Entry
@Component
struct A3 {build() {Row() {Column() {RichText('<h1 style="text-align: center;">h1标题</h1>' +'<h1 style="text-align: center;"><i>h1斜体</i></h1>' +'<h1 style="text-align: center;"><u>h1下画线</u></h1>' +'<h2 style="text-align: center;">h2标题</h2>' +'<h3 style="text-align: center;">h3标题</h3>' +'<p style="text-align: center;">p常规</p><hr/>' +'<div style="width: 500px;height: 500px;border: 1px solid;margin: 0auto;">' +'<p style="font-size: 35px;text-align: center;font-weight: bold; color: rgb(24,78,228)">字体大小35px,行高45px</p>' +'<p style="background-color: #e5e5e5;line-height: 45px;font-size: 35px;text-indent: 2em;">' +'<p>这是一段文字这是一段文字这是一段文字这是一段文字这是一段文字这是一段文字这是一段文字这是一段文字这是一段文字</p>')}.width('100%')}.height('100%')}
}
这个要通过模拟器运行才能看到效果,预览不能显示。
3.4.20 ScrollBar
滚动条组件ScrollBar用于配合可滚动组件使用,如List、Grid、Scroll等。 ScrollBar实例化构造函数为 ScrollBar(value: { scroller: Scroller, direction?: ScrollBarDirection, state?: BarState }),这些参数说明: Scroller:可滚动组件的控制器,用于与可滚动组件进行绑定。 ScrollBarDirection:滚动条的方向,控制可滚动组件对应方向的滚动。默认值是ScrollBarDirection.Vertical。 BarState:滚动条状态。默认值是BarState.Auto。
ScrollBar示例如下:
@Entry
@Component
struct A3 {//可滚动组件的控制器private scroller: Scroller = new Scroller()private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]build() {Row() {Column() {//定义了可滚动组件ScrollScroll(this.scroller) {Flex({ direction: FlexDirection.Column }) {ForEach(this.arr, (item) => {Row() {Text(item.toString()).width('90%').height(100).backgroundColor('#3366CC').borderRadius(15).fontSize(16).textAlign(TextAlign.Center).margin({ top: 5 })}}, item => item)}.margin({ left: 52 })}.scrollBar(BarState.Auto).scrollable(ScrollDirection.Vertical)//定义了滚动条组件ScrollBarScrollBar({ scroller: this.scroller, direction: ScrollBarDirection.Vertical, state: BarState.Auto }) {//定义Text作为滚动条的样式Text().width(30).height(100).borderRadius(10).backgroundColor('#C0C0C0')}.width(30).backgroundColor('#ededed')}.width('100%')}.height('100%')}
}
上述代码中,定义了可滚动组件Scroll及滚动条组件ScrollBar。在ScrollBar子组件中定义Text作为滚动条的样式。可滚动组件Scroll及滚动条组件ScrollBar通过Scroller进行绑定,且当只有当两者方向相同时,才能联动,ScrollBar与可滚动组件Scroll仅支持一对一绑定。
3.4.21 Search
Search是搜索框组件,适用于浏览器的搜索内容输入框等应用场景。Search示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {Search({ placeholder: '输入内容...'}).searchButton('搜索') //搜索按钮的文字.width(300).height(80).placeholderColor(Color.Grey) //提示文本样式.placeholderFont({ size: 24, weight: 400 }) //提示文本字体大小.textFont({ size: 24, weight: 400 }) //搜索框文字字体大小}.width('100%')}.height('100%')}
}
Search组件还支持以下事件。 onSubmit(callback: (value: string) => void):单击搜索图标、搜索按钮或者按下软键盘搜索按钮时触发该回调。 onChange(callback: (value: string) => void):输入内容发生变化时,触发该回调。
上述事件中,value是指当前搜索框中输入的文本内容。
3.4.22 Select
Select提供下拉选择菜单,可以让用户在多个选项之间选择。Select示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {//设置下拉列表值和图标Select([{ value: '生日蛋糕', icon: $r('app.media.cookie1') },{ value: '节日蛋糕', icon: $r('app.media.cookie2') },{ value: '儿童蛋糕', icon: $r('app.media.cookie3') },{ value: '公主蛋糕', icon: $r('app.media.cookie4') }]).selected(2) //选中的下拉列表索引.value('蛋糕私人房') //下拉按钮本身的文本内容.font({ size: 16, weight: 500 }) //下拉按钮本身的文本样式.fontColor('#182431') //下拉按钮本身的文本颜色.selectedOptionFont({ size: 16, weight: 400 }) //下拉菜单选中项的文本样式.optionFont({ size: 16, weight: 400 }) //下拉菜单项的文本样式}.width('100%')}.height('100%')}
}
Select组件还可以设置默认选中的下拉列表索引,下拉按钮本身的文本内容,下拉按钮本身的文本样式,下拉按钮本身的文本颜色,下拉菜单选中项的文本样式,下拉菜单项的文本样式等。
3.4.23 Slider
Slider是滑动条组件,通常用于快速调节设置值,如音量调节、亮度调节等应用场景。Slider示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {//设置垂直的SliderSlider({value: 40,step: 10,style: SliderStyle.InSet, //滑块在滑轨上direction: Axis.Vertical //方向}).showSteps(true) //设置显示步长刻度值.height('50%')//设置水平的SliderSlider({value: 40,min: 0,max: 100,style: SliderStyle.OutSet //滑块在滑轨内}).blockColor('#191970') //设置滑块的颜色.trackColor('#ADD8E6') //设置滑轨的背景颜色.selectedColor('#4169E1') //设置滑轨的已滑动部分颜色.showTips(true) //设置气泡提示.width('50%')}.width('100%')}.height('100%')}
}
上述代码中定义了两个Slider组件,一个是垂直的,另一个是水平的,是由direction参数决定的。参数style用来设置滑块是否在滑轨内。
Slider组件还包括以下属性: blockColor:设置滑块的颜色。 trackColor:设置滑轨的背景颜色。 selectedColor:设置滑轨的已滑动部分的颜色。 showSteps:设置当前是否显示步长刻度值。 showTips:设置滑动时是否显示百分比气泡提示。 trackThickness:设置滑轨的粗细。
3.4.24 Span
Span作为Text组件的子组件,用于显示行内文本。 Span组件主要包括以下属性。 decoration:设置文本装饰线样式及其颜色。 letterSpacing:设置文本字符间距。取值小于0,字符聚集重叠,取值大于0且随着数值变大,字符间距越来越大,分布越稀疏。 textCase:设置文本大小写。
Span示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {//文本添加横线Text() {Span('文本添加横线').decoration({type: TextDecorationType.Underline,color: Color.Red}).fontSize(24)}//文本添加划掉线Text() {Span('文本添加划掉线').decoration({type: TextDecorationType.LineThrough,color: Color.Red }).fontSize(24)}//文本添加上画线Text() {Span('文本添加上画线').decoration({type: TextDecorationType.Overline,color: Color.Red}).fontSize(24)}//文本字符间距Text() {Span('文本字符间距').letterSpacing(10).fontSize(24)}//文本转化为小写LowerCaseText() {Span('文本转化为小写LowerCase').fontSize(24).textCase(TextCase.LowerCase).decoration({ type: TextDecorationType.None })}//文本转化为大写UpperCaseText() {Span('文本转化为小写UpperCase').fontSize(24).textCase(TextCase.UpperCase).decoration({ type: TextDecorationType.None })}}.width('100%')}.height('100%')}
}
3.4.25 Stepper与StepperItem
Stepper是步骤导航器组件,适用于引导用户按照步骤完成任务的导航场景。而StepperItem是Stepper组件的页面子组件。Stepper与StepperItem示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {Stepper({//设置Stepper当前显示StepperItem的索引值index: 0}) {//第1页StepperItem() {Text('第1页').fontSize(34)}.nextLabel('下一页')//第2页StepperItem() {Text('第2页').fontSize(34)}.nextLabel('下一页').prevLabel('上一页')//第3页StepperItem() {Text('第3页').fontSize(34)}.prevLabel('上一页')}.width('100%')}.height('100%')}}
}
上述示例设置Stepper当前显示StepperItem的索引值为0,即显示第1页的内容。后续定义了3个StepperItem页面。
3.4.26 Text
Text是显示一段文本的组件,可以包含Span子组件。 Text组件包含以下属性。 textAlign:设置文本在水平方向的对齐方式。 textOverflow:设置文本超长时的显示方式。默认值是TextOverflow.Clip。 maxLines:设置文本的最大行数。默认值是Infinity。 lineHeight:设置文本的行高,设置值不大于0时,不限制文本行高,自适应字体大小,Length为number类型时单位为fp。 decoration:设置文本装饰线样式及其颜色。 baselineOffset:设置文本基线的偏移量,默认值为0。 letterSpacing:设置文本字符间距。 minFontSize:设置文本最小显示字号。需要配合maxFontSize、maxline或布局大小限制使用,单独设置不生效。 maxFontSize:设置文本最大显示字号。需要配合minFontSize、maxline或布局大小限制使用,单独设置不生效。 textCase:设置文本大小写。默认值是TextCase.Normal。 copyOption:组件支持设置文本是否可复制和粘贴。默认值是CopyOptions.None。
@Entry
@Component
struct A4 {build() {Row() {Column() {//单行文本//红色单行文本居中Text('红色单行文本居中').fontSize(24).fontColor(Color.Red) //红色.textAlign(TextAlign.Center) //居中.width('100%')//单行文本对齐左侧Text('单行文本对齐左侧').fontSize(24).textAlign(TextAlign.Start) //对齐左侧.width('100%')//单行文本带边框对齐右侧Text('单行文本带边框对齐右侧').fontSize(24).textAlign(TextAlign.End) //对齐右侧.border({ width: 1 }) //边宽.padding(10).width('100%')//多行文本//超出maxLines截断内容展示Text('寒雨连江夜入吴,平明送客楚山孤。洛阳亲友如相问,一片冰心在玉壶。').textOverflow({ overflow: TextOverflow.None }) //超出截断内容.maxLines(2) //最多显示2行.fontSize(24).border({ width: 1 }).padding(10)//超出maxLines展示省略号Text('寒雨连江夜入吴,平明送客楚山孤。洛阳亲友如相问,一片冰心在玉壶。').textOverflow({ overflow: TextOverflow.Ellipsis }) //超出展示省略号.maxLines(2).fontSize(24).border({ width: 1 }).padding(10)Text('寒雨连江夜入吴,平明送客楚山孤。洛阳亲友如相问,一片冰心在玉壶。').textOverflow({ overflow: TextOverflow.Ellipsis }) //超出展示省略号.maxLines(2).fontSize(24).border({ width: 1 }).padding(10).lineHeight(50) //设置文本的行高}.width('100%')}.height('100%')}
}
3.4.27 TextArea
TextArea是多行文本输入框组件,当输入的文本内容超过组件宽度时会自动换行显示。 TextArea组件支持以下属性: placeholderColor:设置placeholder文本颜色。 placeholderFont:设置placeholder文本样式。 textAlign:设置文本在输入框中的水平对齐式。 caretColor:设置输入框光标颜色。 inputFilter:通过正则表达式设置输入过滤器。匹配表达式的输入允许显示,不匹配的输入将被过滤。仅支持单个字符匹配,不支持字符串匹配。 copyOption:设置输入的文本是否可复制。
@Entry
@Component
struct A4 {build() {Row() {Column() {TextArea({//设置无输入时的提示文本placeholder: '寒雨连江夜入吴,平明送客楚山孤。洛阳亲友如相问,一片冰心在玉壶。'}).placeholderFont({ size: 24, weight: 400 }) //设置placeholder文本样式.width(336).height(100).margin(20).fontSize(16).fontColor('#182431').backgroundColor('#FFFFFF')}.width('100%')}.height('100%')}
}
3.4.28 TextClock
TextClock组件通过文本将当前系统时间显示在设备上,支持不同时区的时间显示,最高精确到秒级。 TextClock示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {//普通的TextClock示例TextClock().margin(20).fontSize(30)//带日期格式化的TextClock示例TextClock().margin(20).fontSize(30).format('yyyyMMdd hh:mm:ss') //日期格式化}.width('100%')}.height('100%')}
}
3.4.29 TextInput
TextInput是单行文本输入框组件。TextInput示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {//文本输入框TextInput({ placeholder: '请输入...'}) //设置无输入时的提示文本.placeholderColor(Color.Grey) //设置placeholder文本颜色.placeholderFont({ size: 14, weight: 400 }) //设置placeholder文本样式.caretColor(Color.Blue) //设置输入框光标颜色.width(300).height(40).margin(20).fontSize(24).fontColor(Color.Black)//密码输入框TextInput({ placeholder: '请输入密码...' }).width(300).height(40).margin(20).fontSize(24).type(InputType.Password) //密码类型.maxLength(9) //设置文本的最大输入字符数.showPasswordIcon(true) //输入框末尾的图标显示}.width('100%')}.height('100%')}
}
3.4.30 TextPicker
TextPicker是滑动选择文本内容的组件。TextPicker示例如下:
@Entry
@Component
struct A4 {build() {Row() {Column() {//文本输入框TextPicker({//选择器的数据选择列表range: ['Java核心编程', '轻量级Java EE企业应用开发实战', '鸿蒙HarmonyOS手机应用开发实战','Node.js+Express+MongoDB+Vue.js全栈开发实战'],//设置默认选中项在数组中的索引值。默认值是0selected: 1}).defaultPickerItemHeight(30)//设置Picker各选择项的高度.width("80%").height(300)}.width('100%')}.height('100%')}
}
3.4.31 TextTimer
TextTimer是通过文本显示计时信息并控制其计时器状态的组件。TextTimer组件支持绑定一个控制器。TextTimerController用来控制文本计时器。TextTimer示例如下:
@Entry
@Component
struct A4 {//TextTimer组件的控制器private textTimerController: TextTimerController = new TextTimerController()build() {Row() {Column() {//定义TextTimer组件TextTimer({ controller: this.textTimerController,isCountDown: true, //是否倒计时。默认值为falsecount: 30000 }) //倒计时时间,单位为毫秒.format('mm:ss.SS') //格式化.fontColor(Color.Black) //字体颜色.fontSize(50) //字体大小//控制按钮Row() {Button("开始").onClick(() => {this.textTimerController.start()})Button("暂停").onClick(() => {this.textTimerController.pause()})Button("重置").onClick(() => {this.textTimerController.reset()})}}.width('100%')}.height('100%')}
}
3.4.32 TimePicker
TimePicker是滑动选择时间的组件。TimePicker示例如下:
@Entry
@Component
struct A4 {//TextTimer组件的控制器private textTimerController: TextTimerController = new TextTimerController()build() {Row() {Column() {TimePicker().useMilitaryTime(true) //设置为24小时制}.width('100%')}.height('100%')}
}
3.4.33 Toggle
Toggle组件提供复选框样式、状态按钮样式及开关样式。仅当ToggleType为Button时可包含子组件。 Toggle组件的构造函数参数主要有两个。 typ:开关类型,可以是Checkbox、Button、Switch。 isOn:开关是否打开。默认值是false。 Toggle组件还可以设置以下属性。 selectedColor:设置组件打开状态的背景颜色。 switchPointColor:设置Switch类型的圆形滑块颜色。
Toggle示例如下:
@Entry
@Component
struct A4 {//TextTimer组件的控制器private textTimerController: TextTimerController = new TextTimerController()build() {Row() {Column() {//关闭的Switch类型Toggle({ type: ToggleType.Switch, isOn: false }).size({ width: 40, height: 40 }) //设置大小.selectedColor('#007DFF') //设置组件打开状态的背景颜色.switchPointColor('#FFFFFF') //设置Switch类型的圆形滑块颜色//打开的Switch类型Toggle({ type: ToggleType.Switch, isOn: true }).size({ width: 40, height: 40 }) //设置大小.selectedColor('#007DFF') //设置组件打开状态的背景颜色.switchPointColor('#FFFFFF') //设置Switch类型的圆形滑块颜色//关闭的Checkbox类型Toggle({ type: ToggleType.Checkbox, isOn: false }).size({ width: 40, height: 40 }) //设置大小.selectedColor('#007DFF') //设置组件打开状态的背景颜色//打开的Checkbox类型Toggle({ type: ToggleType.Checkbox, isOn: true }).size({ width: 40, height: 40 }) //设置大小.selectedColor('#007DFF') //设置组件打开状态的背景颜色//关闭的Button类型Toggle({ type: ToggleType.Button, isOn: false }).size({ width: 40, height: 40 }) //设置大小.selectedColor('#007DFF') //设置组件打开状态的背景颜色//打开的Button类型Toggle({ type: ToggleType.Button, isOn: true }).size({ width: 40, height: 40 }) //设置大小.selectedColor('#007DFF') //设置组件打开状态的背景颜色}.width('100%')}.height('100%')}
}
3.4.34 Web
Web组件是提供具有网页显示能力的组件。需要注意的是,在访问在线网页时需添加网络权限ohos.permission.INTERNET。Web组件示例如下:
//Web组件控制器需要导入的包
import web_webview from '@ohos.web.webview'@Entry
@Component
struct A5 {private webviewController: web_webview.WebviewController = new web_webview.WebviewController()build() {Row() {Column() {Web({src: 'https://developer.huawei.com/consumer/cn/doc/harmonyos-guides-V2/start-overview-0000001478061421-V2',controller: this.webviewController})}.width('100%')}.height('100%')}
}
3.5 小结
本章介绍了UI开发的基本概念,以及常用组件和基础组件,希望读者能够掌握UI开发的基本知识,并了解这些常用组件和基础组件的功能,学习如何使用这些基础组件。下一章将继续讲解UI的相关知识。
3.6 习题
1.判断题
(1)TabContent的tabBar属性仅支持string类型。( )
(2)当Tabs组件的参数barPosition为BarPosition.End时,页签位于页面底部。( )
2.单选题
(1)关于Button组件,下面哪个样式是胶囊型按钮?( )
A. ButtonType.Capsule B. ButtonType.Normal C. ButtonType.Circle D. 以上都不是
(2)关于Web组件,下面描述错误的是?( )
A. WebController控制器可以控制Web组件的各种行为,比如forward、backward、 runJavaScript等
B. Web组件支持fileAccess、javaScriptAccess等多种属性的设置,例如 .javaScriptAccess(true)表示允许执行JavaScript脚本
C. Web组件支持onConfirm、onConsole等多种事件,例如网页调用confirm()告警 时触发 onConfirm回调
D. 使用Web组件访问在线和离线网页都需要添加ohos.permission.INTERNET权限
3.多选题
(1)关于Tabs组件页签的位置设置、下面描述正确的是?( )
A. 当barPosition为Start(默认值)、vertical属性为false时(默认值),页签位于 容器顶部
B. 当barPosition为Start(默认值)、vertical属性为true时,页签位于容器左侧
C. 当barPosition为End、vertical属性为false(默认值)时,页签位于容器底部
D. 当barPosition为End、vertical属性为true时,页签位于容器右侧
(2)针对包含文本元素的组件,如Text、Button、TextInput等,可以使用下列哪些属性?( ) A. fontColor B. fontSize C. fontStyle D. fontWeight E. fontFamily