组件(Component)是界面搭建与显示的最小单位,HarmonyOS ArkUI声明式开发范式为开发者提供了丰富多样的UI组件,我们可以使用这些组件轻松的编写出更加丰富、漂亮的界面。
组件根据功能可以分为以下五大类:基础组件、容器组件、媒体组件、绘制组件、画布组件。
在ArkUI中,还支持多种布局方式,如Flex布局、Grid布局等。同时,为了提升用户体验,ArkUI还提供了丰富的动画效果和自定义动画能力。此外,ArkUI还支持多种绘制能力,以满足开发者绘制自定义形状的需求,支持图形绘制、颜色填充、文本绘制、图片绘制等。
Image(src: string|PixelMap|Resource)
1)string格式,通常用来加载网络图片。
Image('https://xxx.png')
注意:加载网络图片,需要在模块目录下的module.json5配置文件中,配置网络访问权限:ohos.permission.INTERNET,否则图片不显示。
{
"module": {
'requestPermissions': [
{
"name": "ohos.permission.INTERNET" // 网络请求权限
}
],
... // 省略其他配置
}
}
2)PixelMap格式,可以加载像素图,常用在图片编辑中
Image(pixelMapObject)
3)Resource格式,加载本地图片,推荐使用
// 读取media目录下的图片
Image($r('app.media.mate60'))
// 读取rawfile目录下的图片,需要写后缀名
Image($rawfile('mate60.png'))
Image($r('app.media.mate60'))
.width(100) // 宽度,值用数值格式时,默认单位是vp,会根据设备的像素密度进行换算
.height('100%') // 高度,值用字符串百分比格式时,会根据设备的屏幕大小进行换算
.borderRedius(10) // 边框圆角
.interpolation(ImageInterpolation.High) // 图片插值
Text(content?: string|Resource)
1)string格式,直接填写文本内容
Text('图片宽度')
2)Resource格式,读取本地资源文件
Text($r('app.sring.width_label'))
资源读取顺序:先从resources/base目录下寻找资源,app是固定前缀,string代表寻找string.json文件,width_label代表从string.json中寻找name为width_label的value值。
Text('注册账号')
.lineHeight(32) // 行高,
.fontSize(20) // 字体大小,值为数值类型时,单位是fp,是个虚拟像素单位,可以保证不同大小设备的视觉一致性
.fontColor('#ff1876f8') // 字体颜色
.fontWeight(FontWeight.Medium) // 字体粗细
属性名称 | 参数类型 | 描述 |
---|---|---|
textAlign | TextAlign | 设置对其方式,可选值:Start(默认值), Center, End |
textOverflow | TextOverflow | 设置文本超长显示,需配合maxLines使用,单独设置不生效, maxLines用于设置文本显示最大行数 |
decoration | TextDecorationType | decoration包含type和color两个参数,其中type用于设置装饰线样式,参数类型为TextDecorationTyp,color为可选参数。TextDecorationTyp 可选值:None, Overline,LineThrough,Underline |
TextInput({placeholder?: ResourceStr, text?: ResourceStr })
1)placeholder:输入框无输入时的提示文本
TextInput({placeHolder: '请输入账号或手机号'})
2)text: 输入框当前的文本内容
TextInput({text: 'itcast'})
TextInput({text: '注册账号'})
.width(32) // 宽
.height(20) // 高
.backgroundColor('#ff1876f8') // 背景色
.type(InputType.Password) // 输入框类型
.onChange(value => {
// value 是用户输入的文本内容
})
InputType 可选值: Normal | Password | Email | Number | phoneNumber,使用不同的type会对输入内容做不同的约束。
Button(label?: ResourceStr) // label是按钮文字
1)文字型按钮
Button('点我')
2)自定义按钮,在Button内嵌套其他组件
Button(){
Image($r('app.media.search')).width(20).margin(10)
}
Button('点我')
.width(100) // 宽
.height(30) // 高
.type(ButtonType.Normal) // 按钮类型
.onClick(() => {
})
ButtonType可选值: Capsule | Circle| Normal
Slider(options?: SliderOptions)
示例:
Slider({
min: 0, // 最小值
max:100, // 最大值
value: 30, // 当前值
step:10, // 滑动步长
style: SliderStyle.OutSet, //滑块位置:OutSet|Inset,默认OutSet
direction: Axis.Horizontal, // 方向:Horizontal|Vertical,默认Horizontal
reverse: false //是否反向滑动
})
Slider({
min: 0, // 最小值
max:100, // 最大值
value: 30, // 当前值
step:10, // 滑动步长
reverse: false //是否反向滑动
})
.width('90%') // 宽
.showTips(true) // 是否显示value百分比提示
.blockColor('#36d') // 按钮类型
.onChange(value => {
// value 就是当前滑块值
})
ButtonType可选值: Capsule | Circle| Normal
能够将容器内部,其他组件没占满的页面空间填充满。
能够让组件堆叠在一起。
线性布局组件
常见布局属性
纵向布局使用Column容器,横向布局采用Row容器。
容器内部元素排列方向上的这根轴线称为主轴,和主轴垂直的轴线称为交叉轴
属性方法名 | 说明 | 参数 |
---|---|---|
justifyContent | 设置子元素在主轴方向的对其格式 | FlexAlign枚举,可选值:Start,Center,Ent,SpaceBetween,SpaceEvenly |
alignItems | 设置子元素在交叉轴方向上的对其格式 | Row容器使用VerticalAlign枚举,Column容器使用HorizontalAlign枚举 |
元素和元素的间隔称为space,创建容器时可以对space进行赋值,改变元素间的间隔。
示例代码:
@Entry
@Component
struct Index {
build() {
Column({space: 20}){
Text('item1')
Text('item2')
Text('item3')
Text('item4')
}
.width('100%')
.height('100%')
.justifyContent(FlexAling.Center)
.alignItems(HorizontalAlign.Center)
}
}
ForEach 用于循环遍历数组,常用于根据数组内容渲染页面组件。
语法格式:
ForEach(
arr: Array, // 要遍历的数据数组
(item: any, index?: number) => {
// 页面组件生成函数
},
keyGenerator?: (item: any, index?: number): string => {
// 键生成函数,为数组每一项生成一个唯一标识,组件是否重新渲染的判断标准
}
)
示例代码:
// 数据数组
private items = [
{name: '华为Mate60', image: '1.jpg', price: '6999'},
{name: '小米14', image: '2.jpg', price: '4379'},
{name: '荣耀100', image: '3.jpg', price: '3799'}
]
// 遍历数据
ForEach(
this.itmes,
(item) => {
console.log(item.pirce)
...
}
)
列表(List)是一种复杂容器,具备以下特点:
语法格式:
List({space: 10}) {
ForEach([1,2,3,4], item => {
listItem(){
// 列表项内容,只能包含一个根组件
Text('ListItem')
}
})
}
.width('100%')
.listDirection(Axis.Vertical) //列表方向,默认纵向
.layoutWeight(1) // 布局权重,默认是0,可以用来设置高度
.alignListItem(ListItemAlign.Center)
}
List({space: 10}) {
ForEach([1,2,3,4], item => {
listItem(){
// 列表项内容,只能包含一个根组件
Text('ListItem')
}
.swipeAction({end: this.DeleteButton(index)}) // 滑动删除
})
}
.width('100%')
.alignListItem(ListItemAlign.Center)
// 删除按钮
@Builder DeleteButton(index: number) {
Buttion(){
Image($r('xxx'))
.fillColor(Color.White)
.width(20)
}
.width(40)
.height(40)
.type(ButtonType.Circle)
.backgroundColor(Color.Red)
.margin(5)
.onClick(() => {
// code...
})
}
将可复用的部分抽取出来,封装成自定义组件,提高代码的复用性。
自定义组件可以统一放到entry.src.main.ets.components
目录下。
定义一个struct结构体,并加上@Component注解。
对于组件内的可变的内容,定义为成员变量,在使用自定义组件处进行传参。
定义的组件要想被别的页面能够使用,要用export关键字进行导出。
标题组件:
@Component
export struct Header {
private title: ResourceStr
build() {
//标题部分
Row() {
// code ...
Image($r('app.media.ic_public_back'))
.width(30)
Text(this.title)
.fontSize(30)
.fontWeight(FontWeight.Blod)
Blank()
Image($r('app.media.ic_public_refresh'))
.width(30)
}
.width('100%')
.height(30)
}
}
使用import
关键字进行导入,引用时直接写组件名,如果有参数可以进行传参。
商品列表页面:
import {Header} from '../components/XxxComponents'
@Entry
@Component
struct ItemPage{
build() {
Column({space: 8}){
// 标题部分
Header({title: '商品列表'})
// 商品列表部分
ForEach(// ...)
}
}
}
和自定义组件功能类似,构建页面内的自定义函数,用于页面内的可复用代码的封装。
写在当前组件的外面,称为全局自定义构建函数,当前页面的所有组件都可以使用。
// 全局自定义构建函数
@Builder function ItemCard(item: Item){
Row({space: 10}){...}
.width('100%')
.backgroundColor('#FFF')
.borderRadius(20)
.height(120)
.padding(10)
}
@Entry
@Component
struct ItemPage{
// 商品数据
private items = [
{name: '华为Mate60', image: '1.jpg', price: '6999'},
{name: '小米14', image: '2.jpg', price: '4379'},
{name: '荣耀100', image: '3.jpg', price: '3799'}
]
build() {
Column({space: 8}){
// 标题部分
Header({title: '商品列表'})
.margin({bottom: 20})
// 商品列表部分
List({space: 8}){
ForEach(this.items, (item: Item) => {
ListItem(){
// 使用全局自定义构建函数
ItemCard(item)
}
})
}
}
}
}
写在当前组件的内部,称为局部自定义构建函数,只有当前组件可以使用。
@Entry
@Component
struct ItemPage{
// 商品数据
private items = [
{name: '华为Mate60', image: '1.jpg', price: '6999'},
{name: '小米14', image: '2.jpg', price: '4379'},
{name: '荣耀100', image: '3.jpg', price: '3799'}
]
build() {
Column({space: 8}){
// 标题部分
Header({title: '商品列表'})
.margin({bottom: 20})
// 商品列表部分
List({space: 8}){
ForEach(this.items, (item: Item) => {
ListItem(){
// 使用局部自定义构建函数
this.ItemCard(item)
}
})
}
}
}
// 局部自定义构建函数,不加function关键字
@Builder ItemCard(item: Item){
Row({space: 10}){...}
.width('100%')
.backgroundColor('#FFF')
.borderRadius(20)
.height(120)
.padding(10)
}
}
使用@Style装饰器定义公共样式函数,用于抽取可复用的公共样式,所抽取的样式属性必须是所有组件所共有的。
使用@Extend装饰器抽取某一组件所特有的样式属性。
写在当前组件的外部,称为全局公共样式函数,当前页面的所有组件都可以使用。
// 全局公共样式函数
@Styles function fillScreen(){
.width('100%')
.height('100%')
.backgroundColer('#EFEFEF')
.padding(20)
}
@Entry
@Component
struct ItemPage{
build() {
Column({space: 8}){
// 标题部分
Header({title: '商品列表'})
.margin({bottom: 20})
// 商品列表部分
List({space: 8}){...}
}
.fillScreen()
}
}
写在当前组件的内部,称为局部公共样式函数,只有当前组件可以使用。
@Entry
@Component
struct ItemPage{
build() {
Column({space: 8}){
// 标题部分
Header({title: '商品列表'})
.margin({bottom: 20})
// 商品列表部分
List({space: 8}){...}
}
.fillScreen()
}
// 局部公共样式函数
@Styles function fillScreen(){
.width('100%')
.height('100%')
.backgroundColer('#EFEFEF')
.padding(20)
}
}
公共样式函数所抽取的属性,必须是所有组件都共有的,当需要抽取某一组件所特有的属性时,需要用到extend语法。
Extend关键字只能写在组件外部。
// 使用@Extend 继承模式,给Text组件抽取公共样式
@Extend(Text) function priceText(){
.fontColor('#F36')
.fontSize(18)
}