一百天挑战学会HarmanyOS——HarmanyOS的基本组件与布局

561 阅读7分钟

大家好我是牛牛,一名软件开发从业者,无意中接触到了鸿蒙移动端开发,对鸿蒙操作系统产生了极大的兴趣,作者将从无到有开发出一款鸿蒙原生APP。每天写一篇关于鸿蒙开发的技术文章。欢迎大家踊跃订阅➕关注,文章中有什么 不妥之处可以在评论区中指出。

注意:最好是有开发经验的伙伴来阅读系列文章。零基础的同学可以先去了解一下TypeScript从最基本的开发语言进行学起

前言

上篇文章中《一百天挑战学会HarmanyOS——HarmanyOS 的开发模型与组件结构》 介绍了鸿蒙的开发模型与ArkUI中组件的基本结构,让大家认识了 ArkUI 初始化项目时所使用的一些组件,那么这一章节将为大家介绍 HarmanyOS 开发中布局方式。

系统组件(ArkUI)

ArkUI 将组件分为这么几类(随着 NEXT 版本的不断迭代更新,可能还会新增许多组件)

  • 基础组件
  • 容器组件
  • 媒体组件
  • 绘制组件
  • 高级组件
  • 安全组件
  • Ability Kit (在UIAbility组件可以使用ArkUI提供的组件、事件、动效、状态管理等能力。)

基本组件的使用

文章中只提供常用的部分组件的属性实现,只为展示组件的示例,更详细的配置可以查看官方的 API 文档UI 文档

Text 文本组件

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    Column(){
      // 文本组件
      Text('你好鸿蒙')
        // 文本大小
        .fontSize('50')
        // 文本颜色
        .fontColor(Color.Red)
        // 字体宽度
        .fontWeight(700)
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

编译结果:

image.png

Column 列组件,纵向排列,布局主轴是Y轴 容器中可以放任意子组件

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    // Column 列组件,纵向排列 主轴是 Y 轴
    // space 设置column容器中每个元素的间距
    Column({space:20}){
     Row()
       .width(200)
       .height(100)
       .backgroundColor(Color.Red)
      Row()
        .width(200)
        .height(100)
        .backgroundColor(Color.Blue)
      Row()
        .width(200)
        .height(100)
        .backgroundColor(Color.Pink)
    }
    // 高度
    .height('100%')
    // 宽度
    .width('100%')
    // 主轴居中对齐
    .justifyContent(FlexAlign.Center)
  }
}

编译结果: image.png

Row 行组件,横向排列,布局主轴是X 容器中可以放任意子组件

Row组件默认情况下,子组件内容会垂直方向居中- 内容超出不会换行

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    // Row  列组件,横向排列 主轴是 X 轴,超出屏幕永远不会换行
    // space 设置Row容器中每个元素的间距
    Row({space:20}){
     Row()
       .width(100)
       .height(200)
       .backgroundColor(Color.Red)
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Blue)
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Pink)
    }
    // 高度
    .height('100%')
    // 宽度
    .width('100%')
    // 主轴居中对齐
    .justifyContent(FlexAlign.Center)
  }
}

编译结果: image.png

Flex 组件以弹性方式布局子组件的容器组件。(存在二次布局,官方推荐有性能要求,使用Column和Row代替)

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    Flex({
      // 主轴横向排列
      direction: FlexDirection.Row,
      // 中间空隙平均分
      justifyContent: FlexAlign.SpaceEvenly,
      // 超出屏幕宽度换行
      wrap: FlexWrap.Wrap,
      // 内容居中显示
      alignContent: FlexAlign.Center
    }){
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Pink)
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Blue)
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Green)
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Orange)
      Row()
        .width(100)
        .height(200)
        .backgroundColor(Color.Brown)
    }
    .backgroundColor(Color.Grey)
    .height('100%')
   }

}

编译结果: image.png

Button 按钮组件

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    Row(){
      // 按钮组件
       Button('这是一个按钮')
         // 按钮类型
         .type(ButtonType.Normal)
         // 字体宽度
         .fontWeight(700)
         // 宽度
         .width(200)
         // 背景颜色
         .backgroundColor("#07c160")
         // 按钮的点击事件
         .onClick(()=>{

         })
    }
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

编译结果: image.png

TextInput 输入框组件

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    Column({space:20}){
      //  输入框组件
      TextInput({
        // 提示文字
        placeholder: '请输入文字'
      })
      TextInput({
        placeholder: '请输入密码'
        //  输入框类型
      }).type(InputType.Password)

      TextInput({
        placeholder: '请输入验证码'
        // 输入最大长度
      }).maxLength(6)
    }
    .padding(20)
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

编译结果:

image.png

Image 组件

Image组件的参数也可以使用 $r() 进行本地资源的获取也可以是网络图片。 在使用模拟器运行时,需要配置网络权限

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    Column({space:20}){
      Image("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png")
        .width(160)
        .height(80)
    }
    .padding(20)
    .height('100%')
    .width('100%')
    .justifyContent(FlexAlign.Center)
  }
}

编译结果: image.png

百度小案例

使用以上的组件可以实现一个百度搜索的小案例。大家也可以动手实操起来。

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    Column({ space: 20 }) {
      // 百度图片
      Image("https://www.baidu.com/img/PCtm_d9c8750bed0b3c7d089fa7d55720d6cf.png")
        .width(160)
        .height(80)
      // 行布局
      Row() {
        // 输入框
        TextInput()
          // 圆角属性
          .borderRadius({
            topLeft: 6,
            bottomLeft: 6
          })
          .height(40)
          .layoutWeight(1)
          // 背景颜色
          .backgroundColor(Color.White)
          // 边框颜色
          .border({
            color: "#c4c7ce",
            width: 2
          })
        // 按钮
        Button("百度一下")
          .type(ButtonType.Normal)
          .backgroundColor("#516aee")
          .padding({
            left: 10,
            right: 10,
            top: 6,
            bottom: 6
          })
          // 位移
          .translate({
            x: -2
          })
          // 按钮圆角
          .borderRadius({
            topRight: 6,
            bottomRight: 6
          })
      }
      .padding({
        left: 10,
        right: 10
      })
      .width('100%')
    }
    .justifyContent(FlexAlign.Center)
    .width('100%')
    .height('100%')
  }
}

编译结果:

image.png

Tips:

Row和Column的布局方式成为线性布局-不是横向排列就是纵向排列

  • 线性布局中永远不会产生换行
  • Flex布局-使用Flex组件-容器- 支持横向和纵向-弹性布局-支持换行
  • 均不支持出现滚动条

Grid(网格容器,由“行”和“列”分割的单元格所组成,通过指定“项目”所在的单元格做出各种各样的布局。仅支持GridItem组件)

Grid布局

  • 想要控制屏幕的分栏分几列,怎么分特别像前端的栅格布局
  • Row组件默认情况下,里面的元素的纵向是居中的
  • Column组件默认横向是居中的
  • Grid组件下只能放置GridItem组件

Grid可以设置columnsTemplaterowsTemplate ,columnsTemplate是设置横向的分配,如果设置 1fr 1fr 表示,等分为两份, 如果设置1fr 2fr表示左边一份,右边两份, 在设置columnsTemplate不设置rowsTemplate的情况下,如果内容超出容器区域,会自动出现滚动条 columnsGap设置列和列之间的间距,rowsGap设置行和行之间的间距

示例代码:

@Entry
@Component
struct FlexCase {
  build() {
    // 网格布局
    Grid() {
      // 自定义组件
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
      GridItemCase()
    }
    .width("100%")
    .height("100%")
    // 等分两份
    .columnsTemplate("1fr 1fr")
    // 列分栏间距
    .columnsGap(10)
    // 行分栏间距
    .rowsGap(10)
    .padding(10)
  }
}
/**
 * 定义内容组件
 */
@Component
struct GridItemCase {
  build() {
    // 必须放置GridItem组件,不然不会显示宫格
    GridItem() {
      Row() {
        Column() {
          Text("内容")
        }
        .width('100%')
      }
      .height(200)
      .borderRadius(4)
      .backgroundColor(Color.Pink)
    }
  }

}

编译结果: image.png

Scroll 组件

在基本的布局组件 Column/Row/Flex/Stack中不论内容超出与否,皆不会出现滚动条

出现滚动条的组件

  • List(列表)
  • Grid
  • Scroll(滚动条)
  • Swiper(轮播)
  • WaterFlow(瀑布流)

出现滚动条的前提条件是: 上述组件中的子组件的内容超出了父容器组件的宽度或者高度

使用最基本的Scroll组件出现一个滚动条

image.png

先实现基本的布局

示例代码:

@Entry
@Component
struct FlexCase {
  // 中间区域高度
  @State middleHeight: number = 0
  build() {
    // 竖向容器
    Column() {
      // 顶部
      Row() {
        Text('顶部').width('100%').textAlign(TextAlign.Center)
      }
      .width('100%')
      .height(50)
      .backgroundColor(Color.Pink)
      // 中间区域
      Column() {
        Text('要滚动的区域').width('100%').textAlign(TextAlign.Center).fontColor(Color.White)
      }
      .width('100%')
      // 高度为动态计算出 根据视口大小动态计算
      .height(this.middleHeight)
      .backgroundColor(Color.Gray)
      //底部
      Row() {
        Text('底部').width('100%').textAlign(TextAlign.Center).fontColor(Color.White)
      }
      .width('100%')
      .height(50)
      .backgroundColor(Color.Red)
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .height('100%')
    // 监听页面变化(页面初始化也会被调用)
    .onAreaChange((old: Area, newArea: Area) => {
      // 全局状态设置 高度
      this.middleHeight = (newArea.height as number) - 100
    })
  }
}

编译运行: image.png

实现区域滚动

示例代码:

@Entry
@Component
struct FlexCase {

  @State message: string = 'Hello World';
  @State middleHeight: number = 0
  build() {
    Column() {
      Row()
        .width('100%')
        .height(50)
        .backgroundColor(Color.Red)
        
      // Scroll List Grid Swiper WaterFlow
      Scroll() {
        // 有且只能有一个组件
        Column() {
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
          ScrollItem()
        }
      }
      .width('100%')
      .height(this.middleHeight)
      .backgroundColor(Color.Orange)

      Row()
        .width('100%')
        .height(50)
        .backgroundColor(Color.Blue)
    }
    .justifyContent(FlexAlign.SpaceBetween)
    .width('100%')
    .height('100%')
    .onAreaChange((old: Area, newArea: Area) => {
      this.middleHeight = (newArea.height as number) - 100
    })
  }
}

@Component
struct ScrollItem {
  build() {
    Row() {
      Text("滚动区域内容")
    }
    .width('100%')
    .height(80)
    .backgroundColor(Color.Pink)
    .borderRadius(8)
    .margin({
      top: 20,
      bottom: 10
    })
    .justifyContent(FlexAlign.Center)
  }

}

编译运行: 2024-07-01-215505.gif

这一期就到这里啦!常用的组件还有很多,这里就不一一列举,大家有兴趣的可以去查看官方文档,去查看更多的组件的使用方式。这一期代码内容比较多,建议大家动起手实操起来。 下一期继续为大家更新组件相关的知识点。