harmonyOS基础- 快速弄懂HarmonyOS ArkTs基础组件、布局容器(前端视角篇)

大家好!我是黑臂麒麟,一位6年的前端;
if you're change the world, you're workingon important things. you're excited to get up in the norning.

一、常用基础组件

1.基础组件

简单列举常用的及含义,掌握了以下按钮可以解决日常简单场景需求。其他在使用时查询ArkTSAPI文档即可。

组件 含义
Text() 显示一段文本的组件。
Image() 图片组件,支持本地图片和网络图片的渲染展示
TextInput() 单行文本输入框组件。
Button() 按钮
Blank 空白填充组件,在容器主轴方向上,空白填充组件具有自动填充容器空余部分的能力。仅当父组件为Row/Column时生效。
LoadingProgress 显示加载进展
...

2.文本样式

ArkTS的样式以驼峰命名方式,这里以Text组件为例:

名称 参数类型 描述
fontColor ResourceColor 设置文本颜色
fontSize Length or Resource 设置文本颜色
fontStyle FontStyle 设置文本的字体样式。默认值:FontStyle.Normal。
fontWeight numbe or FontWeight or string 设置文本的字体粗细,number类型取值[100, 900],取值间隔为100,默认为400,取值越大,字体越粗。string类型仅支持number类型取值的字符串形式,例如"400",以及"bold"、"bolder"、"lighter"、"regular"、"medium",分别对应FontWeight中相应的枚举值。默认值:FontWeight.Normal。

下面代码是两个Text组件,分别是默认样式和设置了文本样式的对比。

typescript 复制代码
@Entry
@Component
struct Index {
  @State message: string = 'Hello World';
  @State myText: string = 'World';

  build() {
    Row() {
      Column(){
        Text('ArkTs')
        Text('ArkTs')
          .fontColor(Color.Blue)
          .fontSize(40)
          .fontWeight(FontWeight.Bold)
          .fontFamily('Arial')
      }
    }
    .justifyContent(FlexAlign.Center)
    .backgroundColor(0xF1F3F5)
    .width('100%')
    .height('100%')
  }
}

以上ArkTs代码的样式使用驼峰格式;其他组件的样式也是一样。使用时查阅具体用法。

3.Image

这里着重说一下Image的图片地址的引入方式,方式如下:
Image(src: string|PixelMap|Resource)

(1).使用string数据加载网络图片

typescript 复制代码
Image('https://www.example.com/xxx.png')

这里要注意Image在使用网络图片的时候,需要要在module.json5文件中声明网络访问权限

typescript 复制代码
// module.json5
{
  "module": {
   	"requestPermissions": [
  		"name": "ohos.permisssion.INTERNET"	
  	]
  }
}

(2).使用PixelMap数据加载图片

Typescript 复制代码
Image(pixelMapObject)

(3)使用Resource数据加载图片

typescript 复制代码
Image($r('app.media.logo'))

上面的Resource是一种资源引入类型。会在下面详细描述。

4.使用资源引用类型

Resource是资源引用类型,用于设置组件属性的值。ArkTs文档推荐优先使用Resource类型,将资源文件(字符串、图片、音频等)统一存放于resources目录下,便于开发者统一维护。同事系统可以根据当前配置加载合适资源,例如,开发者根据屏幕尺寸呈现不同的布局效果,或根据语言提供不同的字符串。

已上面Text组件代码为例:

typescript 复制代码
Text('ArkTs')
  .fontColor(Color.Blue)
  .fontSize(40)
  .fontWeight(FontWeight.Bold)
  .fontFamily('Arial')

(1).对元素内文本字符串的管理;

可以将这些编码写到entry/src/main/resources下的资源文件中。

在string.json中定义Button显示的文本

就个人而言,不太喜欢这种方式相对于前端喜欢而言。

float.json中定义Text的字体样式。

在color.json中定义Text的字体颜色。

然后再Text组件通过$r('app.type.name)的形式引用应用资源。app带表应用内resources目录中定义的资源;type代表资源类型(或资源的存放位置),可以取"color","float"、"string"、"plural"、"media"; 以上几种是固定的,不支持自定义命名文件引用。name代表资源命名,由开发者定义资源时确定的。

typescript 复制代码
Text($r('app.string.Index_Text'))
  .fontColor($r('app.color.Text_color'))
  .fontSize($r('app.float.Text_fontSize'))
  .fontWeight(FontWeight.Bold)
  .fontFamily($r('app.float.Text_fontFamily'))

以上是简单的描述Resource引用方式,后面回单独出一期深入研究的Resource引入文章。

二、布局组件

前端常用布局方式header、side、main、footer等标签,还有布局样式flexgrid等,在ArkTs常用布局组件有一下几种:

组件 描述
Column 垂直方向布局的容器
Row 水平方向布局的容器
List 列表容器
Grid 网格容器
Tabs 页签容器
Swiper 滑块视图容器
Scroll 可滑动的容器

这里说一下ListGridTabsColumnRow使用方法,Swiper、Scroll布局组件相对简单详见Api文档。有点类似小程序的类似组件。

1. Column&Row

布局容器概念

线性布局容器表示垂直方向或者水平方向排列子组件的容器,ArkTs提供了ColumnRow容器来实现线性布局。

主轴和交叉轴概念

在布局容器中,默认存在两根轴,分别是主轴和交叉轴,这两个轴始终是相互垂直的。不同的容器中主轴的方向不一样的。

  • 主轴 :在Column容器中的子组件是按照从上到下的垂直方向布局,其主轴的方向是垂直方向;在Row容器中的组件时按照从左到右的水平方向布局的,其主轴的方向时水平方向。
    下图时Column&Row容器交叉轴

属性

Column&Row容器的两个属性justifyContent和alignItems,类似CSS的flex或Grid的justify-content和align-item。这样容易让我们前端快速理解。

这里注意一下它们的属性值都要首字母大写

属性名称 描述
justifyContent 设置子组件在主轴方向上的对齐格式
alignItems 设置子组件在交叉轴方向上的对齐格式

主轴方向的对其(justifyContent)

子组件在主轴方向上的使用jusifyContent属性来设置,其参数类型时FlexAlign。它有一下几种类型:

属性值 描述
Start 主轴方向首端对齐,第一个元素与行首对齐,同时后续的元素与前一个对齐
Center 主轴方向中心对齐,第一个元素与行首的距离以及最后一个元素与行尾距离相同
End 主轴方向尾部对齐,最后一个元素与行尾对齐,其他元素与后一个对齐
SpaceBetween 主轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素与行首对齐,最后一个元素与行尾对齐
SpaceAround 轴方向均匀分配弹性元素,相邻元素之间距离相同。 第一个元素到行首的距离和最后一个元素到行尾的距离是相邻元素之间距离的一半
SpaceEvenly 主轴方向等间距布局,无论是相邻元素还是边界元素到容器的间距都一样
  • Start

  • Center

  • End

  • SpaceBetween

  • SpaceAround

  • SpaceEvenly

交叉中方向对齐(alignItems)

Column容器的主轴时垂直方向,交叉轴是水平方向,其参数类型为HorizontalAlign(水平对齐),HorizontalAlign定义了一下几个类型;

属性值 描述
Start 水平方向上按照起始端对齐
Center 水平方向上居中对齐
End 水平方向上按照末端对齐
  • start

  • Centent

  • End

    Row容器的主轴是水平方向,交叉轴是垂直方向,其参数类型为VerticalAlign(垂直对其),VerticalAlign定义了一下几种类型:

    |属性值|描述|

    |--|--|

    |Top|垂直方向上居顶部对齐|

    |Center|竖直方向上居中对齐|

    |Bottom|竖直方向上居底部对齐|

  • Top

  • Center

  • Bottom

接口介绍

Column&Row都课接收一个参数space,表示子组件在主轴上的间距;

typescript 复制代码
@Entry
@Component
struct Index {
  @State TextArr: Array<string> = ["Image", "Text", "TextInput", "Button"]

  build() {
    Column({space: 30}) { // 这里设置子元素主轴上的间距
      ForEach(this.TextArr, (item: string)=> { // 利用ForEach渲染我们的字符串数组
        Row(){
          Text(item)
        }
        .width('80%')
        .height('100vp')
        .backgroundColor('#99b2df')
        .border({
          width: 5,
          color: '#8aa7da',
          style: BorderStyle.Solid
        })
        .justifyContent(FlexAlign.Center)
      })
    }
    .justifyContent(FlexAlign.Start)
    .backgroundColor('#bdd7ee')
    .width('100%')
    .height('100%')
  }
}

渲染出来的效果:

3. List使用

简介

使用频率很高的组件,需要配合ListItem子组件一起使用,列表每项对应一个ListItem组件

使用ForEach渲染

渲染多时,可以使用ForEach来循环渲染我们的列表项;

typescript 复制代码
@Entry
@Component
struct Index {
  private arr: number[] = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]

  build() {
    Column({space: 30}) {
      List({space: 10}) {
        ForEach(this.arr, (item: number)=> {
          ListItem(){
            Text(`${item}`)
              .width('100%')
              .height(100)
              .fontSize(20)
              .fontColor(Color.White)
              .textAlign(TextAlign.Center)
              .backgroundColor(0x007DFF)
          }
        }, item => item)
      }
    }
    .padding(12)
    .height('100%')
    .backgroundColor(0xF1F3F5)
  }
}

设置分割线

这里如有需求可以给list组件可以使用divider属性给ListItem设置分割线。有四个参数:

  • strokeWidth: 分割线宽度
  • color: 分割线颜色
  • startMargin: 分割线距离列表起始端的距离
  • endMargin: 分割线距离列表结束端的距离
typescript 复制代码
List({space: 50}) {
  ForEach(this.arr, (item: number)=> {
    ListItem(){
      Text(`${item}`)
    }
  }, item => item)
}
.divider({
  strokeWidth: 5,
  color: '#d8d8d8',
  startMargin: 20,
  endMargin: 20,
 })

列表滚动事件监听

List滚动监听事件和前端监听Scroll监听时间方法很像:

  • onScroll: 滑动触发,返回scrollOffset为滑动偏移量,scrollState为当前滑动状态。
  • onScrollIndex: 滑动时触发,分别返回滑动起始索引值与滑动结束索引值。
  • onReachStart: 列表到达起始位置时触发。
  • onReachEnd: 列表到底末尾位置触发。
  • onScrollStrop: 列表滑动结束时触发。

    利用这些时间监听,并可以在log面板中打印出我们想要的滑动数据;

设置List排列方向

List组件排列可以垂直方向和水平方向排列,默认是垂直方向排列。如果想设置List为水平方向,可以使用listDiretion属性为Axis.Horizontal即可。

4. Grid

简介

如果前端学过css的grid布局模式,那大家一定不会对Grid组件布局陌生,接下来学习如何使用Grid网格布局组件。

使用

Grid组件是由"行"和"列"分割的单元格组成。Grid一般和GridItem一起使用。

typescript 复制代码
@Entry
@Component
struct GridPage {
  private arr: string[] = new Array(9).fill('').map((_, index) => `item ${index + 1}`)

  build() {
    Column() {
      Grid() {
        ForEach(this.arr, (item: string) => {
          GridItem(){
            Text(item)
              .fontSize(16)
              .fontColor(Color.White)
              .backgroundColor(0x007DFF)
              .width('100%')
              .height('100%')
              .textAlign(TextAlign.Center)
          }
        }, (item: string) => item)
      }
      .columnsTemplate('1fr 1fr 1fr')
      .rowsTemplate('1fr 1fr 1fr')
      .columnsGap(10)
      .rowsGap(10)
      .height(300)
    }
    .width('100%')
    .padding(12)
    .backgroundColor(0xF1F3F5)
  }
}

这里我们同样跟List一样使用ForEach遍历出的数组,可以看到我们设置columnsTemplate属性垂直方向配置3等分个1fr,同样纵向rowsTemplate也是3等分的1fr1fr代表所占Grid等分个数。columnGaprowGap分别设置垂直和纵向元素之间的间距。这里分别设置了 10vp

5. Tabs

概述

Tabs是我们常用的做视图切换的常用布局组件。如"底部页签","顶部标签",平板的"侧边页签"等。

使用

Tabs组件仅含子组件TabContent,每一个页签对应内容视图即TabContent组件。

结合之前我们写的ListGrid的组件,我们编写一个简单的Tabs布局

typescript 复制代码
import Home from '../view/Home';
import GridPage from '../view/GridPage'
@Entry
@Component
struct Index {
  private controller: TabsController = new TabsController();

  build() {
    Column() {
      Tabs() {
        TabContent() {
          Home()
        }
        .tabBar('List')

        TabContent() {
          GridPage()
        }
        .tabBar('Grid')
      }
      .barWidth('100%') // 设置TabBar宽度
      .barHeight('60') // 设置TabBar高度
      .width('100%') 
      .height('100%')
      .backgroundColor(0xF5F5F5)
    }
    .width('100%')
    .height('100%')
  }
}

展示后的效果

上面代码,通过属性widthheight设置了Tabs组件的宽高,使用TabWidthBarHeight设置了TabBar的宽度和高度。

设置TabBar布局属性

Tabs布局模式默认Fixed的,不支持滑动。如果页签过多会可能导致显示不全,讲布局模式设置为Scrollable的话,可以实现页签的滚动。

布局属性 描述 属性值
barMode Tabs的布局模式 BarMode.Fixed (默认):所有TabBar平均分配barWidth宽度。 BarMode.Scrollable: 每个TabBar使用实际宽度,超过总长度后可滑动。
barPosition 设置TabBar位置和排列方向 BarPosition.Start,vertical属性为false(默认值)时,页签在顶部.vertical属性为true时,位于容器左侧。 BarPosition.End, vertical属性为false时,位于容器底部。vertical属性为true时,位于容器右侧。

自定义TabBar样式

如果需要自定义TabBar, 需要通过@Builder装饰器的函数。构造一个生成自定义TabBar样式的函数,我们来实现上面底部页签效果:

typescript 复制代码
import Home from '../view/Home';
import GridPage from '../view/GridPage'
@Entry
@Component
struct Index {
  private tabsController: TabsController = new TabsController();
  @State currentIndex: number = 0;


  @Builder TabBuilder(title: string, targetIndex: number, selectedImg: Resource, normalImg: Resource) {
    Column() {
      Image(this.currentIndex === targetIndex ? selectedImg : normalImg)
        .size({width: 25, height: 25})
      Text(title)
        .fontColor(this.currentIndex === targetIndex ? '#1698CE' : '#6B6B6B')
    }
    .width('100%')
    .height(50)
    .justifyContent(FlexAlign.Center)
    .onClick(() => {
      this.currentIndex = targetIndex;
      this.tabsController.changeIndex(this.currentIndex);
    })
  }
  build() {
    Column() {
      Tabs({barPosition: BarPosition.End, controller: this.tabsController}) {
        TabContent() {
          Home()
        }
        .tabBar(this.TabBuilder('List', 0, $r('app.media.home_selected'), $r('app.media.home_normal')))

        TabContent() {
          GridPage()
        }
        .tabBar(this.TabBuilder('List', 1, $r('app.media.mine_selected'), $r('app.media.mine_normal')))
      }
      .vertical(false)
      .barWidth("100%") // 设置TabBar宽度
      .barHeight(60) // 设置TabBar高度
      .width('100%')
      .height('100%')
      .backgroundColor(0xF5F5F5)
      .onChange((index: number) => {
        this.currentIndex = index;
      })
    }
    .width('100%')
    .height('100%')
  }
}

渲染后效果:

barPosition的值设置为BarPosition.End,使页签显示在底部。使用@Builder自定义TabBuilder函数,生成由Image和Text组成的页签。同时也给Tabs组件设置了TabsController控制器,当点击某个页签时,调用changeIndex方法进行页签内容切换。

最后在Tabs添加onChange事件。切换时,把当前最近Index赋给currentIndex保存起来。

参考

华为开发者联盟官网开发者基础课程

相关推荐
zhanshuo11 小时前
在鸿蒙里优雅地处理网络错误:从 Demo 到实战案例
harmonyos
zhanshuo11 小时前
在鸿蒙中实现深色/浅色模式切换:从原理到可运行 Demo
harmonyos
whysqwhw16 小时前
鸿蒙分布式投屏
harmonyos
whysqwhw17 小时前
鸿蒙AVSession Kit
harmonyos
whysqwhw19 小时前
鸿蒙各种生命周期
harmonyos
whysqwhw20 小时前
鸿蒙音频编码
harmonyos
whysqwhw20 小时前
鸿蒙音频解码
harmonyos
whysqwhw20 小时前
鸿蒙视频解码
harmonyos
whysqwhw20 小时前
鸿蒙视频编码
harmonyos
ajassi200020 小时前
开源 Arkts 鸿蒙应用 开发(十八)通讯--Ble低功耗蓝牙服务器
华为·开源·harmonyos